blob: d26e91408666ebd92ded1afbd9541cb301181728 [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
Romain Guy6b7bd242010-10-06 19:49:23 -070019import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070020import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070021import android.app.ActivityManagerNative;
22import android.content.ClipDescription;
23import android.content.ComponentCallbacks;
24import android.content.Context;
25import android.content.pm.PackageManager;
26import android.content.res.CompatibilityInfo;
27import android.content.res.Configuration;
28import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.Canvas;
Alan Viverettefed3f722013-11-14 14:48:20 -080030import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070032import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070033import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070034import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.graphics.Rect;
36import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070037import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070038import android.hardware.display.DisplayManager;
39import android.hardware.display.DisplayManager.DisplayListener;
Romain Guy6b7bd242010-10-06 19:49:23 -070040import android.media.AudioManager;
41import android.os.Binder;
Michael Wright5bd69e62015-05-14 14:48:08 +010042import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070043import android.os.Bundle;
44import android.os.Debug;
45import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070046import android.os.Looper;
47import android.os.Message;
48import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070050import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070051import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070052import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080053import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070055import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070056import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070057import android.util.Slog;
John Reckba6adf62015-02-19 14:36:50 -080058import android.util.TimeUtils;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080059import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080060import android.view.Surface.OutOfResourcesException;
Jeff Browna175a5b2012-02-15 19:18:31 -080061import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070063import android.view.accessibility.AccessibilityEvent;
64import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070065import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070066import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070067import android.view.accessibility.AccessibilityNodeInfo;
Alan Viverette25acc7e2015-05-19 11:32:08 -070068import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav Ganov02107852011-10-03 17:06:56 -070069import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070070import android.view.accessibility.IAccessibilityInteractionConnection;
71import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080072import android.view.animation.AccelerateDecelerateInterpolator;
73import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.view.inputmethod.InputConnection;
75import android.view.inputmethod.InputMethodManager;
76import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070077
Svetoslav Ganov42138042012-03-20 11:51:39 -070078import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070079import com.android.internal.os.SomeArgs;
Adam Powell6711f3b2015-05-06 15:57:09 -070080import com.android.internal.policy.PhoneFallbackEventHandler;
Romain Guy6b7bd242010-10-06 19:49:23 -070081import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070082import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
Jeff Brown5182c782013-10-15 20:31:52 -070084import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import java.io.IOException;
86import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070087import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070088import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070090import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092/**
93 * The top of a view hierarchy, implementing the needed protocol between View
94 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070095 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 *
97 * {@hide}
98 */
Romain Guy812ccbe2010-06-01 14:07:24 -070099@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -0800100public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -0800101 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700102 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700104 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 /** @noinspection PointlessBooleanExpression*/
106 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
107 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800108 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
110 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
111 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
112 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700113 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700114 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700115 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
Romain Guy59a12ca2011-06-09 17:48:21 -0700117 /**
118 * Set this system property to true to force the view hierarchy to render
119 * at 60 Hz. This can be used to measure the potential framerate.
120 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700121 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700122
Griff Hazena0938022015-03-13 10:01:41 -0700123 // properties used by emulator to determine display shape
Griff Hazena0938022015-03-13 10:01:41 -0700124 public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
125 "ro.emu.win_outset_bottom_px";
Michael Kolb437d3132014-06-20 13:28:44 -0700126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 /**
128 * Maximum time we allow the user to roll the trackball enough to generate
129 * a key event, before resetting the counters.
130 */
131 static final int MAX_TRACKBALL_DELAY = 250;
132
Alan Viverettebea0c7da2015-09-01 16:00:20 -0400133 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800135 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
136 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700137
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800138 static final ArrayList<ComponentCallbacks> sConfigCallbacks
139 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700140
Jeff Brownf9e989d2013-04-04 23:04:03 -0700141 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700142 final IWindowSession mWindowSession;
143 final Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700144 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800145 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700148
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800149 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 final Thread mThread;
152
153 final WindowLeaked mLocation;
154
155 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
156
157 final W mWindow;
158
Dianne Hackborn180c4842011-09-13 12:39:25 -0700159 final int mTargetSdkVersion;
160
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700161 int mSeq;
162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700164
165 View mAccessibilityFocusedHost;
166 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 int mViewVisibility;
169 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700170 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Dianne Hackbornce418e62011-03-01 14:31:38 -0800172 // Set to true if the owner of this window is in the stopped state,
173 // so the window should no longer be active.
174 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700175
George Mount41725de2015-04-09 08:23:05 -0700176 // Set to true to stop input during an Activity Transition.
177 boolean mPausedForTransition = false;
178
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700179 boolean mLastInCompatMode = false;
180
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700181 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700182 BaseSurfaceHolder mSurfaceHolder;
183 boolean mIsCreating;
184 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 final Region mTransparentRegion;
187 final Region mPreviousTransparentRegion;
188
189 int mWidth;
190 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800191 Rect mDirty;
Romain Guybb93d552009-03-24 21:04:15 -0700192 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700193
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700194 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
196 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700197 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700198 InputQueue.Callback mInputQueueCallback;
199 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700200 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800201 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 final Rect mTempRect; // used in the transaction to not thrash the heap.
204 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205
206 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800207 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700209 /** Set to true while in performTraversals for detecting when die(true) is called from internal
210 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
211 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700212 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 boolean mLayoutRequested;
214 boolean mFirst;
215 boolean mReportNextDraw;
216 boolean mFullRedrawNeeded;
217 boolean mNewSurfaceNeeded;
218 boolean mHasHadWindowFocus;
219 boolean mLastWasImTarget;
Dianne Hackborn12d3a942012-04-27 14:16:30 -0700220 boolean mWindowsAnimating;
Michael Jurkaf42d90102013-05-08 18:00:04 +0200221 boolean mDrawDuringWindowsAnimating;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -0700222
223 /** How many frames the app is still allowed to draw when a window animation is happening. */
224 private int mRemainingFrameCount;
Romain Guy1f59e5c2012-05-06 14:11:16 -0700225 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700226 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700227 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800228 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800229
230 // Pool of queued input events.
231 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
232 private QueuedInputEvent mQueuedInputEventPool;
233 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800234
Michael Wrightc8a7e542013-03-20 17:58:33 -0700235 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700236 * Pending input events are input events waiting to be delivered to the input stages
237 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700238 */
239 QueuedInputEvent mPendingInputEventHead;
240 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700241 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800242 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800243 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700244 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700245
246 InputStage mFirstInputStage;
247 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700248 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
250 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700251 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
253 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700254 // Surface can never be reassigned or cleared (use Surface.clear()).
John Reckb13de072014-11-19 16:33:47 -0800255 final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 boolean mAdded;
258 boolean mAddedTouchMode;
259
Craig Mautner48d0d182013-06-11 07:53:06 -0700260 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 // These are accessed by multiple threads.
263 final Rect mWinFrame; // frame given by window manager.
264
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800265 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700267 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 final Rect mPendingContentInsets = new Rect();
Filip Gruszczynski2217f612015-05-26 11:32:08 -0700269 final Rect mPendingOutsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
271 = new ViewTreeObserver.InternalInsetsInfo();
272
Adrian Roosfa104232014-06-20 16:10:14 -0700273 final Rect mDispatchContentInsets = new Rect();
274 final Rect mDispatchStableInsets = new Rect();
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700275
Filip Gruszczynski954289d2015-02-26 15:46:47 -0800276 private WindowInsets mLastWindowInsets;
277
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700278 final Configuration mLastConfiguration = new Configuration();
279 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 boolean mScrollMayChange;
282 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800283 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 int mScrollY;
285 int mCurScrollY;
286 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800287 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700288 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700289
Romain Guy8506ab42009-06-11 17:35:47 -0700290 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291
Christopher Tatea53146c2010-09-07 11:57:52 -0700292 /* Drag/drop */
293 ClipDescription mDragDescription;
294 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800295 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700296 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700297 final PointF mLastTouchPoint = new PointF();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700298
299 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800300 private Choreographer.FrameCallback mRenderProfiler;
301 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700302
Chet Haase2f2022a2011-10-11 06:41:59 -0700303 // Variables to track frames per second, enabled via DEBUG_FPS flag
304 private long mFpsStartTime = -1;
305 private long mFpsPrevTime = -1;
306 private int mFpsNumFrames;
307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 /**
309 * see {@link #playSoundEffect(int)}
310 */
311 AudioManager mAudioManager;
312
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700313 final AccessibilityManager mAccessibilityManager;
314
Gilles Debunne5ac84422011-10-19 09:35:58 -0700315 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700316
317 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
Chris Craikcce47eb2014-07-16 15:12:15 -0700318 HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700319
Svetoslav Ganova0156172011-06-26 17:55:44 -0700320 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700321
Svetoslav Ganov42138042012-03-20 11:51:39 -0700322 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800323
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700324 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700325 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700326
Chet Haase97140572012-09-13 14:56:47 -0700327 private boolean mInLayout = false;
328 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
329 boolean mHandlingLayoutInLayoutRequest = false;
330
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700331 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700332
Craig Mautner8f303ad2013-06-14 11:32:22 -0700333 /** Set to true once doDie() has been called. */
334 private boolean mRemoved;
335
Jeff Brown21bc5c92011-02-28 18:27:14 -0800336 /**
337 * Consistency verifier for debugging purposes.
338 */
339 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
340 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
341 new InputEventConsistencyVerifier(this, 0) : null;
342
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700343 static final class SystemUiVisibilityInfo {
344 int seq;
345 int globalVisibility;
346 int localValue;
347 int localChanges;
348 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700349
Jeff Brown98365d72012-08-19 20:30:52 -0700350 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700351 mContext = context;
352 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700353 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800354 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700355
Craig Mautner48d0d182013-06-11 07:53:06 -0700356 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 mThread = Thread.currentThread();
359 mLocation = new WindowLeaked(null);
360 mLocation.fillInStackTrace();
361 mWidth = -1;
362 mHeight = -1;
363 mDirty = new Rect();
364 mTempRect = new Rect();
365 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700367 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700368 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 mViewVisibility = View.GONE;
370 mTransparentRegion = new Region();
371 mPreviousTransparentRegion = new Region();
372 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 mAdded = false;
Chris Craikcce47eb2014-07-16 15:12:15 -0700374 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700375 mAccessibilityManager = AccessibilityManager.getInstance(context);
376 mAccessibilityInteractionConnectionManager =
377 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800378 mAccessibilityManager.addAccessibilityStateChangeListener(
379 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -0700380 mHighContrastTextManager = new HighContrastTextManager();
381 mAccessibilityManager.addHighTextContrastStateChangeListener(
382 mHighContrastTextManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700384 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700385 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100386 mFallbackEventHandler = new PhoneFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800387 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700388 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Dianne Hackborna53de062012-05-08 18:53:51 -0700389 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
391
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800392 public static void addFirstDrawHandler(Runnable callback) {
393 synchronized (sFirstDrawHandlers) {
394 if (!sFirstDrawComplete) {
395 sFirstDrawHandlers.add(callback);
396 }
397 }
398 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700399
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800400 public static void addConfigCallback(ComponentCallbacks callback) {
401 synchronized (sConfigCallbacks) {
402 sConfigCallbacks.add(callback);
403 }
404 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 // FIXME for perf testing only
407 private boolean mProfile = false;
408
409 /**
410 * Call this to profile the next traversal call.
411 * FIXME for perf testing only. Remove eventually
412 */
413 public void profile() {
414 mProfile = true;
415 }
416
417 /**
418 * Indicates whether we are in touch mode. Calling this method triggers an IPC
419 * call and should be avoided whenever possible.
420 *
421 * @return True, if the device is in touch mode, false otherwise.
422 *
423 * @hide
424 */
425 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700426 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
427 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700429 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 } catch (RemoteException e) {
431 }
432 }
433 return false;
434 }
435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 /**
437 * We have one child
438 */
Romain Guye4d01122010-06-16 18:44:05 -0700439 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 synchronized (this) {
441 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700442 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700443
444 mAttachInfo.mDisplayState = mDisplay.getState();
445 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
446
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700447 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700448 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700449 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800450 if (mWindowAttributes.packageName == null) {
451 mWindowAttributes.packageName = mBasePackageName;
452 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700453 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700454 // Keep track of the actual window flags supplied by the client.
455 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700456
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700457 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700458
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700459 if (view instanceof RootViewSurfaceTaker) {
460 mSurfaceHolderCallback =
461 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
462 if (mSurfaceHolderCallback != null) {
463 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700464 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700465 }
466 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800467
Alan Viverette49a22e82014-07-12 20:01:27 -0700468 // Compute surface insets required to draw at specified Z value.
469 // TODO: Use real shadow insets for a constant max Z.
Alan Viverette5435a302015-01-29 10:25:34 -0800470 if (!attrs.hasManualSurfaceInsets) {
471 final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
472 attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
473 }
Alan Viverette49a22e82014-07-12 20:01:27 -0700474
Craig Mautner48d0d182013-06-11 07:53:06 -0700475 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700476 mTranslator = compatibilityInfo.getTranslator();
477
Romain Guy1aec9a22011-01-05 09:37:12 -0800478 // If the application owns the surface, don't enable hardware acceleration
479 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700480 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800481 }
482
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700483 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700484 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700485 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700486 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700487 attrs.backup();
488 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700489 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700490 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
491
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700492 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700493 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700494 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700495 }
496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 mSoftInputMode = attrs.softInputMode;
498 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700499 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700501 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700502 mAttachInfo.mApplicationScale =
503 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 if (panelParentView != null) {
505 mAttachInfo.mPanelParentWindowToken
506 = panelParentView.getApplicationWindowToken();
507 }
508 mAdded = true;
509 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 // Schedule the first layout -before- adding to the window
512 // manager, to make sure we do the relayout before receiving
513 // any other events from the system.
514 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700515 if ((mWindowAttributes.inputFeatures
516 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
517 mInputChannel = new InputChannel();
518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700520 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700521 mAttachInfo.mRecomputeGlobalAttributes = true;
522 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700523 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
524 getHostVisibility(), mDisplay.getDisplayId(),
Filip Gruszczynski0ec13282015-06-25 11:26:01 -0700525 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
526 mAttachInfo.mOutsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 } catch (RemoteException e) {
528 mAdded = false;
529 mView = null;
530 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700531 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700532 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700534 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700536 } finally {
537 if (restore) {
538 attrs.restore();
539 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700541
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700542 if (mTranslator != null) {
543 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700544 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800545 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700547 mPendingStableInsets.set(mAttachInfo.mStableInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800549 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700550 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 mAttachInfo.mRootView = null;
552 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700553 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700555 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700557 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
558 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
559 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800560 "Unable to add window -- token " + attrs.token
561 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700562 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
563 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800564 "Unable to add window -- token " + attrs.token
565 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700566 case WindowManagerGlobal.ADD_APP_EXITING:
567 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800568 "Unable to add window -- app for token " + attrs.token
569 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700570 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
571 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800572 "Unable to add window -- window " + mWindow
573 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700574 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 // Silently ignore -- we would have just removed it
576 // right away, anyway.
577 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700578 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
579 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800580 "Unable to add window " + mWindow +
581 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700582 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
583 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800584 "Unable to add window " + mWindow +
585 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700586 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
587 throw new WindowManager.InvalidDisplayException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800588 "Unable to add window " + mWindow +
589 " -- the specified display can not be found");
590 case WindowManagerGlobal.ADD_INVALID_TYPE:
591 throw new WindowManager.InvalidDisplayException(
592 "Unable to add window " + mWindow
593 + " -- the specified window type is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
595 throw new RuntimeException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800596 "Unable to add window -- unknown error code " + res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700598
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700599 if (view instanceof RootViewSurfaceTaker) {
600 mInputQueueCallback =
601 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
602 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700603 if (mInputChannel != null) {
604 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700605 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700606 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700607 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700608 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
609 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700610 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700613 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
614 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700615
616 if (mAccessibilityManager.isEnabled()) {
617 mAccessibilityInteractionConnectionManager.ensureConnection();
618 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700619
620 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
621 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
622 }
Michael Wright95ae9422013-03-14 10:58:50 -0700623
Jeff Brownf9e989d2013-04-04 23:04:03 -0700624 // Set up the input pipeline.
625 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700626 mSyntheticInputStage = new SyntheticInputStage();
627 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700628 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
629 "aq:native-post-ime:" + counterSuffix);
630 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
631 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
632 "aq:ime:" + counterSuffix);
633 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
634 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
635 "aq:native-pre-ime:" + counterSuffix);
636
637 mFirstInputStage = nativePreImeStage;
638 mFirstPostImeInputStage = earlyPostImeStage;
639 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 }
641 }
642 }
643
keunyoung30f420f2013-08-02 14:23:10 -0700644 /** Whether the window is in local focus mode or not */
645 private boolean isInLocalFocusMode() {
646 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
647 }
648
Dianne Hackborn49b043f2015-05-07 14:21:38 -0700649 public int getWindowFlags() {
650 return mWindowAttributes.flags;
651 }
652
Dianne Hackbornece0f4f2015-06-11 13:29:01 -0700653 public int getDisplayId() {
654 return mDisplay.getDisplayId();
655 }
656
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800657 public CharSequence getTitle() {
658 return mWindowAttributes.getTitle();
659 }
660
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800661 void destroyHardwareResources() {
Romain Guy31f2c2e2011-11-21 10:55:41 -0800662 if (mAttachInfo.mHardwareRenderer != null) {
663 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
John Reckf47a5942014-06-30 16:20:04 -0700664 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800665 }
666 }
667
Bo Liu845535a2014-03-21 12:06:23 -0700668 public void detachFunctor(long functor) {
John Reck44ac42a2014-05-16 14:46:07 -0700669 if (mAttachInfo.mHardwareRenderer != null) {
670 // Fence so that any pending invokeFunctor() messages will be processed
671 // before we return from detachFunctor.
John Reckf47a5942014-06-30 16:20:04 -0700672 mAttachInfo.mHardwareRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700673 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700674 }
675
John Reck3b202512014-06-23 13:13:08 -0700676 /**
677 * Schedules the functor for execution in either kModeProcess or
678 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
679 *
680 * @param functor The native functor to invoke
681 * @param waitForCompletion If true, this will not return until the functor
682 * has invoked. If false, the functor may be invoked
683 * asynchronously.
684 */
Hui Shu9970aee2014-06-23 17:10:30 -0700685 public void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700686 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700687 }
688
John Reck119907c2014-08-14 09:02:01 -0700689 public void registerAnimatingRenderNode(RenderNode animator) {
690 if (mAttachInfo.mHardwareRenderer != null) {
691 mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
692 } else {
693 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
694 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
695 }
696 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
697 }
698 }
699
Romain Guy3b748a42013-04-17 18:54:38 -0700700 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800701 mAttachInfo.mHardwareAccelerated = false;
702 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800703
Romain Guy856d4e12011-10-14 15:47:55 -0700704 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +0000705 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -0700706
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800707 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700708 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800709 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
710
John Reckdd58e792014-04-02 16:54:28 +0000711 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700712 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700713 return;
714 }
715
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700716 // Persistent processes (including the system) should not do
717 // accelerated rendering on low-end devices. In that case,
718 // sRendererDisabled will be set. In addition, the system process
719 // itself should never do accelerated rendering. In that case, both
720 // sRendererDisabled and sSystemRendererDisabled are set. When
721 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
722 // can be used by code on the system process to escape that and enable
723 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800724
John Reck61375a82014-09-18 19:27:48 +0000725 final boolean fakeHwAccelerated = (attrs.privateFlags &
726 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700727 final boolean forceHwAccelerated = (attrs.privateFlags &
728 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800729
John Reck61375a82014-09-18 19:27:48 +0000730 if (fakeHwAccelerated) {
731 // This is exclusively for the preview windows the window manager
732 // shows for launching applications, so they will look more like
733 // the app being launched.
734 mAttachInfo.mHardwareAccelerationRequested = true;
735 } else if (!HardwareRenderer.sRendererDisabled
John Reck1dd0e0f2014-08-12 09:27:33 -0700736 || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Romain Guyb051e892010-09-28 19:09:36 -0700737 if (mAttachInfo.mHardwareRenderer != null) {
John Reckf47a5942014-06-30 16:20:04 -0700738 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -0800739 }
740
Alan Viverette2b12b582014-10-29 11:11:40 -0700741 final Rect insets = attrs.surfaceInsets;
Alan Viverette2cd23e62014-11-04 17:04:02 -0800742 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
743 || insets.top != 0 || insets.bottom != 0;
Alan Viverette2b12b582014-10-29 11:11:40 -0700744 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
John Reckb8802b12014-06-16 15:28:50 -0700745 mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700746 if (mAttachInfo.mHardwareRenderer != null) {
747 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
748 mAttachInfo.mHardwareAccelerated =
749 mAttachInfo.mHardwareAccelerationRequested = true;
750 }
Romain Guye4d01122010-06-16 18:44:05 -0700751 }
752 }
753 }
754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 public View getView() {
756 return mView;
757 }
758
759 final WindowLeaked getLocation() {
760 return mLocation;
761 }
762
763 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
764 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -0700765 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
766 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
767 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
768 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
769 final int oldSoftInputMode = mWindowAttributes.softInputMode;
Alan Viverette5435a302015-01-29 10:25:34 -0800770 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
Alan Viverettedbed8932014-08-06 17:54:52 -0700771
Dianne Hackborn9d090892012-06-11 18:35:41 -0700772 // Keep track of the actual window flags supplied by the client.
773 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -0700774
775 // Preserve compatible window flag if exists.
776 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -0700777 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -0700778
779 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -0700780 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
781 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -0700782
Romain Guyf21c9b02011-09-06 16:56:54 -0700783 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400784 if ((mWindowAttributesChangesFlag
785 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
786 // Recompute system ui visibility.
787 mAttachInfo.mRecomputeGlobalAttributes = true;
788 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800789 if (mWindowAttributes.packageName == null) {
790 mWindowAttributes.packageName = mBasePackageName;
791 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700792 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700793
Alan Viverettedbed8932014-08-06 17:54:52 -0700794 // Restore old surface insets.
795 mWindowAttributes.surfaceInsets.set(
796 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
Alan Viverette5435a302015-01-29 10:25:34 -0800797 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
Alan Viverettedbed8932014-08-06 17:54:52 -0700798
Dianne Hackborn9d090892012-06-11 18:35:41 -0700799 applyKeepScreenOnFlag(mWindowAttributes);
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 if (newView) {
802 mSoftInputMode = attrs.softInputMode;
803 requestLayout();
804 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700805
The Android Open Source Project10592532009-03-18 17:39:46 -0700806 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -0700807 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -0700808 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
809 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
810 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -0700811 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -0700812 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 mWindowAttributesChanged = true;
815 scheduleTraversals();
816 }
817 }
818
819 void handleAppVisibility(boolean visible) {
820 if (mAppVisible != visible) {
821 mAppVisible = visible;
822 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -0700823 if (!mAppVisible) {
824 WindowManagerGlobal.trimForeground();
825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 }
827 }
828
829 void handleGetNewSurface() {
830 mNewSurfaceNeeded = true;
831 mFullRedrawNeeded = true;
832 scheduleTraversals();
833 }
834
Jeff Brownd912e1f2014-04-11 18:46:22 -0700835 private final DisplayListener mDisplayListener = new DisplayListener() {
836 @Override
837 public void onDisplayChanged(int displayId) {
838 if (mView != null && mDisplay.getDisplayId() == displayId) {
839 final int oldDisplayState = mAttachInfo.mDisplayState;
840 final int newDisplayState = mDisplay.getState();
841 if (oldDisplayState != newDisplayState) {
842 mAttachInfo.mDisplayState = newDisplayState;
Jeff Brownc2932a12014-11-20 18:04:05 -0800843 pokeDrawLockIfNeeded();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700844 if (oldDisplayState != Display.STATE_UNKNOWN) {
845 final int oldScreenState = toViewScreenState(oldDisplayState);
846 final int newScreenState = toViewScreenState(newDisplayState);
847 if (oldScreenState != newScreenState) {
848 mView.dispatchScreenStateChanged(newScreenState);
849 }
850 if (oldDisplayState == Display.STATE_OFF) {
851 // Draw was suppressed so we need to for it to happen here.
852 mFullRedrawNeeded = true;
853 scheduleTraversals();
854 }
855 }
856 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800857 }
858 }
Jeff Brownd912e1f2014-04-11 18:46:22 -0700859
860 @Override
861 public void onDisplayRemoved(int displayId) {
862 }
863
864 @Override
865 public void onDisplayAdded(int displayId) {
866 }
867
868 private int toViewScreenState(int displayState) {
869 return displayState == Display.STATE_OFF ?
870 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
871 }
872 };
Romain Guy7e4e5612012-03-05 14:37:29 -0800873
Jeff Brownc2932a12014-11-20 18:04:05 -0800874 void pokeDrawLockIfNeeded() {
875 final int displayState = mAttachInfo.mDisplayState;
876 if (mView != null && mAdded && mTraversalScheduled
877 && (displayState == Display.STATE_DOZE
878 || displayState == Display.STATE_DOZE_SUSPEND)) {
879 try {
880 mWindowSession.pokeDrawLock(mWindow);
881 } catch (RemoteException ex) {
882 // System server died, oh well.
883 }
884 }
885 }
886
Craig Mautner6018aee2012-10-23 14:27:49 -0700887 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700888 public void requestFitSystemWindows() {
889 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -0700890 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700891 scheduleTraversals();
892 }
893
Craig Mautner6018aee2012-10-23 14:27:49 -0700894 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800896 if (!mHandlingLayoutInLayoutRequest) {
897 checkThread();
898 mLayoutRequested = true;
899 scheduleTraversals();
900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 }
902
Craig Mautner6018aee2012-10-23 14:27:49 -0700903 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 public boolean isLayoutRequested() {
905 return mLayoutRequested;
906 }
907
Romain Guycfef1232012-02-23 13:50:37 -0800908 void invalidate() {
909 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -0700910 if (!mWillDrawSoon) {
911 scheduleTraversals();
912 }
Romain Guycfef1232012-02-23 13:50:37 -0800913 }
914
Dianne Hackborna53de062012-05-08 18:53:51 -0700915 void invalidateWorld(View view) {
916 view.invalidate();
917 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700918 ViewGroup parent = (ViewGroup) view;
919 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700920 invalidateWorld(parent.getChildAt(i));
921 }
922 }
923 }
924
Craig Mautner6018aee2012-10-23 14:27:49 -0700925 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800927 invalidateChildInParent(null, dirty);
928 }
929
Craig Mautner8f303ad2013-06-14 11:32:22 -0700930 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800931 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700933 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800934
Chet Haase70d4ba12010-10-06 09:46:45 -0700935 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700936 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800937 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700938 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700939 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700940 }
Romain Guycfef1232012-02-23 13:50:37 -0800941
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700942 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700944 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700945 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800946 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700947 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700948 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700949 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700950 }
Romain Guy1e095972009-07-07 11:22:45 -0700951 if (mAttachInfo.mScalingRequired) {
952 dirty.inset(-1, -1);
953 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
Romain Guycfef1232012-02-23 13:50:37 -0800955
Alan Viverettea7ea65e2015-05-15 11:30:21 -0700956 invalidateRectOnScreen(dirty);
957
958 return null;
959 }
960
961 private void invalidateRectOnScreen(Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800962 final Rect localDirty = mDirty;
963 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700964 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800965 mAttachInfo.mIgnoreDirtyState = true;
966 }
Romain Guycfef1232012-02-23 13:50:37 -0800967
968 // Add the new dirty rect to the current one
969 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
970 // Intersect with the bounds of the window to skip
971 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700972 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700973 final boolean intersected = localDirty.intersect(0, 0,
974 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
975 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700976 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 }
Chet Haase3561d062012-10-23 12:54:51 -0700978 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
979 scheduleTraversals();
980 }
Romain Guy0d9275e2010-10-26 14:22:30 -0700981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982
George Mount41725de2015-04-09 08:23:05 -0700983 void setWindowStopped(boolean stopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -0800984 if (mStopped != stopped) {
985 mStopped = stopped;
George Mount41725de2015-04-09 08:23:05 -0700986 if (!mStopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -0800987 scheduleTraversals();
988 }
989 }
990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991
George Mount41725de2015-04-09 08:23:05 -0700992 /**
993 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
994 * through to allow quick reversal of the Activity Transition.
995 *
996 * @param paused true to pause, false to resume.
997 */
998 public void setPausedForTransition(boolean paused) {
999 mPausedForTransition = paused;
1000 }
1001
Craig Mautner8f303ad2013-06-14 11:32:22 -07001002 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001003 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 return null;
1005 }
1006
Craig Mautner8f303ad2013-06-14 11:32:22 -07001007 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001008 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 if (child != mView) {
1010 throw new RuntimeException("child is not mine, honest!");
1011 }
1012 // Note: don't apply scroll offset, because we want to know its
1013 // visibility in the virtual canvas being given to the view hierarchy.
1014 return r.intersect(0, 0, mWidth, mHeight);
1015 }
1016
Igor Murashkina86ab6402013-08-30 12:58:36 -07001017 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 public void bringChildToFront(View child) {
1019 }
1020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 int getHostVisibility() {
1022 return mAppVisible ? mView.getVisibility() : View.GONE;
1023 }
Romain Guy8506ab42009-06-11 17:35:47 -07001024
Chet Haasecca2c982011-05-20 14:34:18 -07001025 /**
1026 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1027 * This list will be cleared after the transitions on the list are start()'ed. These
1028 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1029 * happens during the layout phase of traversal, which we want to complete before any of the
1030 * animations are started (because those animations may side-effect properties that layout
1031 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1032 * to the list and it is started just prior to starting the drawing phase of traversal.
1033 *
1034 * @param transition The LayoutTransition to be started on the next traversal.
1035 *
1036 * @hide
1037 */
1038 public void requestTransitionStart(LayoutTransition transition) {
1039 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1040 if (mPendingTransitions == null) {
1041 mPendingTransitions = new ArrayList<LayoutTransition>();
1042 }
1043 mPendingTransitions.add(transition);
1044 }
1045 }
1046
John Recka5dda642014-05-22 15:43:54 -07001047 /**
1048 * Notifies the HardwareRenderer that a new frame will be coming soon.
1049 * Currently only {@link ThreadedRenderer} cares about this, and uses
1050 * this knowledge to adjust the scheduling of off-thread animations
1051 */
1052 void notifyRendererOfFramePending() {
1053 if (mAttachInfo.mHardwareRenderer != null) {
1054 mAttachInfo.mHardwareRenderer.notifyFramePending();
1055 }
1056 }
1057
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001058 void scheduleTraversals() {
1059 if (!mTraversalScheduled) {
1060 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001061 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001062 mChoreographer.postCallback(
1063 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001064 if (!mUnbufferedInputDispatch) {
1065 scheduleConsumeBatchedInput();
1066 }
John Recka5dda642014-05-22 15:43:54 -07001067 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001068 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001069 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001070 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001071
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001072 void unscheduleTraversals() {
1073 if (mTraversalScheduled) {
1074 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001075 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001076 mChoreographer.removeCallbacks(
1077 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1078 }
1079 }
1080
1081 void doTraversal() {
1082 if (mTraversalScheduled) {
1083 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001084 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001085
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001086 if (mProfile) {
1087 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001088 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001089
Chris Craike22c59b2015-05-21 18:33:37 -07001090 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001091
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001092 if (mProfile) {
1093 Debug.stopMethodTracing();
1094 mProfile = false;
1095 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001096 }
1097 }
1098
Dianne Hackborn9d090892012-06-11 18:35:41 -07001099 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1100 // Update window's global keep screen on flag: if a view has requested
1101 // that the screen be kept on, then it is always set; otherwise, it is
1102 // set to whatever the client last requested for the global state.
1103 if (mAttachInfo.mKeepScreenOn) {
1104 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1105 } else {
1106 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1107 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1108 }
1109 }
1110
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001111 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001112 if (mAttachInfo.mRecomputeGlobalAttributes) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001113 //Log.i(TAG, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001114 mAttachInfo.mRecomputeGlobalAttributes = false;
1115 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1116 mAttachInfo.mKeepScreenOn = false;
1117 mAttachInfo.mSystemUiVisibility = 0;
1118 mAttachInfo.mHasSystemUiListeners = false;
1119 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1120 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001121 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001122 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1123 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1124 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1125 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001126 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001127 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1128 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1129 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001130 return true;
1131 }
1132 }
1133 return false;
1134 }
1135
John Spurlockbd957402013-10-03 11:38:39 -04001136 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1137 int vis = 0;
1138 // Translucent decor window flags imply stable system ui visibility.
1139 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1140 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1141 }
1142 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1143 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1144 }
1145 return vis;
1146 }
1147
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001148 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1149 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1150 int childWidthMeasureSpec;
1151 int childHeightMeasureSpec;
1152 boolean windowSizeMayChange = false;
1153
1154 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1155 "Measuring " + host + " in display " + desiredWindowWidth
1156 + "x" + desiredWindowHeight + "...");
1157
1158 boolean goodMeasure = false;
1159 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1160 // On large screens, we don't want to allow dialogs to just
1161 // stretch to fill the entire width of the screen to display
1162 // one line of text. First try doing the layout at a smaller
1163 // size to see if it will fit.
1164 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1165 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1166 int baseSize = 0;
1167 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1168 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1169 }
1170 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1171 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1172 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1173 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001174 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001175 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1176 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1177 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1178 goodMeasure = true;
1179 } else {
1180 // Didn't fit in that size... try expanding a bit.
1181 baseSize = (baseSize+desiredWindowWidth)/2;
1182 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1183 + baseSize);
1184 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001185 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001186 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1187 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1188 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1189 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1190 goodMeasure = true;
1191 }
1192 }
1193 }
1194 }
1195
1196 if (!goodMeasure) {
1197 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1198 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001199 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001200 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1201 windowSizeMayChange = true;
1202 }
1203 }
1204
1205 if (DBG) {
1206 System.out.println("======================================");
1207 System.out.println("performTraversals -- after measure");
1208 host.debug();
1209 }
1210
1211 return windowSizeMayChange;
1212 }
1213
Alan Viverettefed3f722013-11-14 14:48:20 -08001214 /**
1215 * Modifies the input matrix such that it maps view-local coordinates to
1216 * on-screen coordinates.
1217 *
1218 * @param m input matrix to modify
1219 */
1220 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001221 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001222 }
1223
1224 /**
1225 * Modifies the input matrix such that it maps on-screen coordinates to
1226 * view-local coordinates.
1227 *
1228 * @param m input matrix to modify
1229 */
1230 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001231 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001232 }
1233
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001234 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1235 if (mLastWindowInsets == null || forceConstruct) {
1236 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1237 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
1238 Rect contentInsets = mDispatchContentInsets;
1239 Rect stableInsets = mDispatchStableInsets;
1240 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1241 // immediately use pending insets.
1242 if (!forceConstruct
1243 && (!mPendingContentInsets.equals(contentInsets) ||
1244 !mPendingStableInsets.equals(stableInsets))) {
1245 contentInsets = mPendingContentInsets;
1246 stableInsets = mPendingStableInsets;
1247 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001248 Rect outsets = mAttachInfo.mOutsets;
1249 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1250 contentInsets = new Rect(contentInsets.left + outsets.left,
1251 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1252 contentInsets.bottom + outsets.bottom);
1253 }
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001254 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001255 null /* windowDecorInsets */, stableInsets,
1256 mContext.getResources().getConfiguration().isScreenRound());
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001257 }
1258 return mLastWindowInsets;
1259 }
1260
Adam Powell2accbf92014-04-16 23:14:57 +00001261 void dispatchApplyInsets(View host) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001262 host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
Adam Powell2accbf92014-04-16 23:14:57 +00001263 }
1264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 private void performTraversals() {
1266 // cache mView since it is used so much below...
1267 final View host = mView;
1268
1269 if (DBG) {
1270 System.out.println("======================================");
1271 System.out.println("performTraversals");
1272 host.debug();
1273 }
1274
1275 if (host == null || !mAdded)
1276 return;
1277
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001278 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001280 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001282 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 WindowManager.LayoutParams lp = mWindowAttributes;
1284
1285 int desiredWindowWidth;
1286 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 final int viewVisibility = getHostVisibility();
1289 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1290 || mNewSurfaceNeeded;
1291
1292 WindowManager.LayoutParams params = null;
1293 if (mWindowAttributesChanged) {
1294 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001295 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 params = lp;
1297 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001298 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001299 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1300 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001301 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001302 mLayoutRequested = true;
1303 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001304 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001305 mLastInCompatMode = false;
1306 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001307 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001308 mLastInCompatMode = true;
1309 }
1310 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001311
Romain Guyf21c9b02011-09-06 16:56:54 -07001312 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001313
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001314 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001316 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 mLayoutRequested = true;
1318
John Spurlockf8508272013-10-14 21:06:52 -04001319 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1320 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001321 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001322 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001323 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001324 desiredWindowWidth = size.x;
1325 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001326 } else {
1327 DisplayMetrics packageMetrics =
1328 mView.getContext().getResources().getDisplayMetrics();
1329 desiredWindowWidth = packageMetrics.widthPixels;
1330 desiredWindowHeight = packageMetrics.heightPixels;
1331 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332
Romain Guyc5d55862011-01-21 19:01:46 -08001333 // We used to use the following condition to choose 32 bits drawing caches:
1334 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1335 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001336 mAttachInfo.mUse32BitDrawingCache = true;
1337 mAttachInfo.mHasWindowFocus = false;
1338 mAttachInfo.mWindowVisibility = viewVisibility;
1339 mAttachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001341 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001342 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001343 // Set the layout direction if it has not been set before (inherit is the default)
1344 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1345 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1346 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001347 host.dispatchAttachedToWindow(mAttachInfo, 0);
1348 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001349 dispatchApplyInsets(host);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001353 desiredWindowWidth = frame.width();
1354 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001356 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001357 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001358 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001360 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 }
1362 }
1363
1364 if (viewVisibilityChanged) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001365 mAttachInfo.mWindowVisibility = viewVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 host.dispatchWindowVisibilityChanged(viewVisibility);
1367 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001368 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 }
1370 if (viewVisibility == View.GONE) {
1371 // After making a window gone, we will count it as being
1372 // shown for the first time the next time it gets focus.
1373 mHasHadWindowFocus = false;
1374 }
1375 }
1376
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001377 // Non-visible windows can't hold accessibility focus.
1378 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1379 host.clearAccessibilityFocus();
1380 }
1381
Chet Haaseb78c2842012-04-19 13:39:50 -07001382 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001383 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001386
Craig Mautner72d6f212015-02-19 16:33:09 -08001387 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001388 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001389
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001390 final Resources res = mView.getContext().getResources();
1391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 // make sure touch mode code executes by setting cached value
1394 // to opposite of the added touch mode.
1395 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001396 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001398 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1399 insetsChanged = true;
1400 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001401 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 }
Adrian Roosfa104232014-06-20 16:10:14 -07001404 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1405 insetsChanged = true;
1406 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001407 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1409 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1410 + mAttachInfo.mVisibleInsets);
1411 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001412 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1413 insetsChanged = true;
1414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1416 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001417 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418
John Spurlockf8508272013-10-14 21:06:52 -04001419 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1420 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001421 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001422 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001423 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001424 desiredWindowWidth = size.x;
1425 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001426 } else {
1427 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1428 desiredWindowWidth = packageMetrics.widthPixels;
1429 desiredWindowHeight = packageMetrics.heightPixels;
1430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 }
1432 }
1433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001435 windowSizeMayChange |= measureHierarchy(host, lp, res,
1436 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
1438
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001439 if (collectViewAttributes()) {
1440 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001442 if (mAttachInfo.mForceReportNewAttributes) {
1443 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001444 params = lp;
1445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446
Chris Craikd36a81f2014-07-17 10:16:51 -07001447 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1448 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 int resizeMode = mSoftInputMode &
1450 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1451 // If we are in auto resize mode, then we need to determine
1452 // what mode to use now.
1453 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001454 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001456 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1458 }
1459 }
1460 if (resizeMode == 0) {
1461 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1462 }
1463 if ((lp.softInputMode &
1464 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1465 lp.softInputMode = (lp.softInputMode &
1466 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1467 resizeMode;
1468 params = lp;
1469 }
1470 }
1471 }
Romain Guy8506ab42009-06-11 17:35:47 -07001472
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001473 if (params != null) {
1474 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1475 if (!PixelFormat.formatHasAlpha(params.format)) {
1476 params.format = PixelFormat.TRANSLUCENT;
1477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001479 mAttachInfo.mOverscanRequested = (params.flags
1480 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 }
1482
Adrian Roosfa104232014-06-20 16:10:14 -07001483 if (mApplyInsetsRequested) {
1484 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001485 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001486 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001487 if (mLayoutRequested) {
1488 // Short-circuit catching a new layout request here, so
1489 // we don't need to go through two layout passes when things
1490 // change due to fitting system windows, which can happen a lot.
1491 windowSizeMayChange |= measureHierarchy(host, lp,
1492 mView.getContext().getResources(),
1493 desiredWindowWidth, desiredWindowHeight);
1494 }
1495 }
1496
1497 if (layoutRequested) {
1498 // Clear this now, so that if anything requests a layout in the
1499 // rest of this function we will catch it and re-run a full
1500 // layout pass.
1501 mLayoutRequested = false;
1502 }
1503
1504 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001505 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001506 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1507 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1508 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1509 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510
Jeff Brown2e05ec32013-09-30 15:57:43 -07001511 // Determine whether to compute insets.
1512 // If there are no inset listeners remaining then we may still need to compute
1513 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001515 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1516 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 boolean insetsPending = false;
1519 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001520
1521 if (mFirst || windowShouldResize || insetsChanged ||
1522 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523
1524 if (viewVisibility == View.VISIBLE) {
1525 // If this window is giving internal insets to the window
1526 // manager, and it is being added or changing its visibility,
1527 // then we want to first give the window manager "fake"
1528 // insets to cause it to effectively ignore the content of
1529 // the window during layout. This avoids it briefly causing
1530 // other windows to resize/move based on the raw frame of the
1531 // window, waiting until we can finish laying out this window
1532 // and get back to the window manager with the ultimately
1533 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001534 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
1536
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001537 if (mSurfaceHolder != null) {
1538 mSurfaceHolder.mSurfaceLock.lock();
1539 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001540 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001541
Romain Guyc361da82010-10-25 15:29:10 -07001542 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001544 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001547 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001548 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1549 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001550 }
Romain Guy2a83f002011-01-18 18:28:21 -08001551
John Reckf7d9c1d2014-04-09 10:01:03 -07001552 if (mAttachInfo.mHardwareRenderer != null) {
1553 // relayoutWindow may decide to destroy mSurface. As that decision
1554 // happens in WindowManager service, we need to be defensive here
1555 // and stop using the surface in case it gets destroyed.
John Reck01a5ea32014-12-03 13:01:07 -08001556 if (mAttachInfo.mHardwareRenderer.pauseSurface(mSurface)) {
1557 // Animations were running so we need to push a frame
1558 // to resume them
1559 mDirty.set(0, 0, mWidth, mHeight);
1560 }
John Reckba6adf62015-02-19 14:36:50 -08001561 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07001562 }
Romain Guy2a83f002011-01-18 18:28:21 -08001563 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001564 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001567 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 + " content=" + mPendingContentInsets.toShortString()
1569 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roosfa104232014-06-20 16:10:14 -07001570 + " visible=" + mPendingStableInsets.toShortString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07001571 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001573
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001574 if (mPendingConfiguration.seq != 0) {
1575 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1576 + mPendingConfiguration);
1577 updateConfiguration(mPendingConfiguration, !mFirst);
1578 mPendingConfiguration.seq = 0;
1579 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001580
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001581 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1582 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 contentInsetsChanged = !mPendingContentInsets.equals(
1584 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001585 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001587 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
1588 mAttachInfo.mStableInsets);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001589 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 if (contentInsetsChanged) {
1591 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1593 + mAttachInfo.mContentInsets);
1594 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001595 if (overscanInsetsChanged) {
1596 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1597 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1598 + mAttachInfo.mOverscanInsets);
1599 // Need to relayout with content insets.
1600 contentInsetsChanged = true;
1601 }
Adrian Roosfa104232014-06-20 16:10:14 -07001602 if (stableInsetsChanged) {
1603 mAttachInfo.mStableInsets.set(mPendingStableInsets);
1604 if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: "
1605 + mAttachInfo.mStableInsets);
1606 // Need to relayout with content insets.
1607 contentInsetsChanged = true;
1608 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001609 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07001610 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001611 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
1612 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001613 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001614 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001615 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001616 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00001617 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001618 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 if (visibleInsetsChanged) {
1620 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1621 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1622 + mAttachInfo.mVisibleInsets);
1623 }
1624
1625 if (!hadSurface) {
1626 if (mSurface.isValid()) {
1627 // If we are creating a new surface, then we need to
1628 // completely redraw it. Also, when we get to the
1629 // point of drawing it we will hold off and schedule
1630 // a new traversal instead. This is so we can tell the
1631 // window manager about all of the windows being displayed
1632 // before actually drawing them, so it can display then
1633 // all at once.
1634 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001635 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001636 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001637
John Reck63005e62015-05-19 15:00:13 -07001638 // Only initialize up-front if transparent regions are not
1639 // requested, otherwise defer to see if the entire window
1640 // will be transparent
Romain Guyb051e892010-09-28 19:09:36 -07001641 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001642 try {
Romain Guy786fc932012-07-24 16:24:56 -07001643 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08001644 mSurface);
John Reck63005e62015-05-19 15:00:13 -07001645 if (hwInitialized && (host.mPrivateFlags
1646 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
1647 // Don't pre-allocate if transparent regions
1648 // are requested as they may not be needed
1649 mSurface.allocateBuffers();
1650 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001651 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001652 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001653 return;
1654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
1656 }
1657 } else if (!mSurface.isValid()) {
1658 // If the surface has been removed, then reset the scroll
1659 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001660 if (mLastScrolledFocus != null) {
1661 mLastScrolledFocus.clear();
1662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02001664 if (mView instanceof RootViewSurfaceTaker) {
1665 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
1666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 if (mScroller != null) {
1668 mScroller.abortAnimation();
1669 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001670 // Our surface is gone
1671 if (mAttachInfo.mHardwareRenderer != null &&
1672 mAttachInfo.mHardwareRenderer.isEnabled()) {
John Reckf47a5942014-06-30 16:20:04 -07001673 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07001674 }
Romain Guy2a83f002011-01-18 18:28:21 -08001675 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1676 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001677 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001678 try {
John Reck79d81e62013-11-05 13:26:57 -08001679 mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001680 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001681 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001682 return;
1683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 }
1685 } catch (RemoteException e) {
1686 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001689 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690
Chris Craikd36a81f2014-07-17 10:16:51 -07001691 mAttachInfo.mWindowLeft = frame.left;
1692 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693
1694 // !!FIXME!! This next section handles the case where we did not get the
1695 // window size we asked for. We should avoid this by getting a maximum size from
1696 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001697 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001698 mWidth = frame.width();
1699 mHeight = frame.height();
1700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001702 if (mSurfaceHolder != null) {
1703 // The app owns the surface; tell it about what is going on.
1704 if (mSurface.isValid()) {
1705 // XXX .copyFrom() doesn't work!
1706 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1707 mSurfaceHolder.mSurface = mSurface;
1708 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001709 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001710 mSurfaceHolder.mSurfaceLock.unlock();
1711 if (mSurface.isValid()) {
1712 if (!hadSurface) {
1713 mSurfaceHolder.ungetCallbacks();
1714
1715 mIsCreating = true;
1716 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1717 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1718 if (callbacks != null) {
1719 for (SurfaceHolder.Callback c : callbacks) {
1720 c.surfaceCreated(mSurfaceHolder);
1721 }
1722 }
1723 surfaceChanged = true;
1724 }
1725 if (surfaceChanged) {
1726 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1727 lp.format, mWidth, mHeight);
1728 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1729 if (callbacks != null) {
1730 for (SurfaceHolder.Callback c : callbacks) {
1731 c.surfaceChanged(mSurfaceHolder, lp.format,
1732 mWidth, mHeight);
1733 }
1734 }
1735 }
1736 mIsCreating = false;
1737 } else if (hadSurface) {
1738 mSurfaceHolder.ungetCallbacks();
1739 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1740 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1741 if (callbacks != null) {
1742 for (SurfaceHolder.Callback c : callbacks) {
1743 c.surfaceDestroyed(mSurfaceHolder);
1744 }
1745 }
1746 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001747 try {
1748 mSurfaceHolder.mSurface = new Surface();
1749 } finally {
1750 mSurfaceHolder.mSurfaceLock.unlock();
1751 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001752 }
1753 }
Romain Guy53389bd2010-09-07 17:16:32 -07001754
Alan Viverette50210d92015-05-14 18:05:36 -07001755 final HardwareRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
1756 if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {
1757 if (hwInitialized
1758 || mWidth != hardwareRenderer.getWidth()
1759 || mHeight != hardwareRenderer.getHeight()) {
1760 hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
1761 mWindowAttributes.surfaceInsets);
Chet Haase40e03832011-10-06 08:34:13 -07001762 if (!hwInitialized) {
Alan Viverette50210d92015-05-14 18:05:36 -07001763 hardwareRenderer.invalidate(mSurface);
Chet Haase391fef02012-09-27 15:26:36 -07001764 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001765 }
Romain Guy03985752011-07-11 15:33:51 -07001766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 }
1768
Craig Mautner72d6f212015-02-19 16:33:09 -08001769 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001770 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001771 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001772 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1773 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001774 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1775 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001776
Dianne Hackbornce418e62011-03-01 14:31:38 -08001777 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1778 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1779 + " mHeight=" + mHeight
1780 + " measuredHeight=" + host.getMeasuredHeight()
1781 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001782
Dianne Hackbornce418e62011-03-01 14:31:38 -08001783 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001784 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001785
Dianne Hackbornce418e62011-03-01 14:31:38 -08001786 // Implementation of weights from WindowManager.LayoutParams
1787 // We just grow the dimensions as needed and re-measure if
1788 // needs be
1789 int width = host.getMeasuredWidth();
1790 int height = host.getMeasuredHeight();
1791 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001792
Dianne Hackbornce418e62011-03-01 14:31:38 -08001793 if (lp.horizontalWeight > 0.0f) {
1794 width += (int) ((mWidth - width) * lp.horizontalWeight);
1795 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1796 MeasureSpec.EXACTLY);
1797 measureAgain = true;
1798 }
1799 if (lp.verticalWeight > 0.0f) {
1800 height += (int) ((mHeight - height) * lp.verticalWeight);
1801 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1802 MeasureSpec.EXACTLY);
1803 measureAgain = true;
1804 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001805
Dianne Hackbornce418e62011-03-01 14:31:38 -08001806 if (measureAgain) {
1807 if (DEBUG_LAYOUT) Log.v(TAG,
1808 "And hey let's measure once more: width=" + width
1809 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001810 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001811 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001812
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001813 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001816 } else {
1817 // Not the first pass and no window/insets/visibility change but the window
1818 // may have moved and we need check that and if so to update the left and right
1819 // in the attach info. We translate only the window frame since on window move
1820 // the window manager tells us only for the new frame but the insets are the
1821 // same and we do not want to translate them more than once.
1822
1823 // TODO: Well, we are checking whether the frame has changed similarly
1824 // to how this is done for the insets. This is however incorrect since
1825 // the insets and the frame are translated. For example, the old frame
1826 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1827 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1828 // true since we are comparing a not translated value to a translated one.
1829 // This scenario is rare but we may want to fix that.
1830
Chris Craikd36a81f2014-07-17 10:16:51 -07001831 final boolean windowMoved = (mAttachInfo.mWindowLeft != frame.left
1832 || mAttachInfo.mWindowTop != frame.top);
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001833 if (windowMoved) {
1834 if (mTranslator != null) {
1835 mTranslator.translateRectInScreenToAppWinFrame(frame);
1836 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001837 mAttachInfo.mWindowLeft = frame.left;
1838 mAttachInfo.mWindowTop = frame.top;
Alan Viverette50210d92015-05-14 18:05:36 -07001839
1840 // Update the light position for the new window offsets.
1841 if (mAttachInfo.mHardwareRenderer != null) {
1842 mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
1843 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 }
1846
Craig Mautner72d6f212015-02-19 16:33:09 -08001847 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07001849 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001851 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001853 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 // We can compute the transparent area
1855
Dianne Hackborn4702a852012-08-17 15:18:29 -07001856 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 // start out transparent
1858 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1859 host.getLocationInWindow(mTmpLocation);
1860 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1861 mTmpLocation[0] + host.mRight - host.mLeft,
1862 mTmpLocation[1] + host.mBottom - host.mTop);
1863
1864 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001865 if (mTranslator != null) {
1866 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1867 }
1868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1870 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001871 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 // reconfigure window manager
1873 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001874 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 } catch (RemoteException e) {
1876 }
1877 }
1878 }
1879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 if (DBG) {
1881 System.out.println("======================================");
1882 System.out.println("performTraversals -- after setFrame");
1883 host.debug();
1884 }
1885 }
1886
1887 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001888 mAttachInfo.mRecomputeGlobalAttributes = false;
1889 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 }
1891
1892 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001893 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07001894 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08001895 insets.reset();
1896
1897 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07001898 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
1899 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08001900
1901 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1903 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001904
1905 // Translate insets to screen coordinates if needed.
1906 final Rect contentInsets;
1907 final Rect visibleInsets;
1908 final Region touchableRegion;
1909 if (mTranslator != null) {
1910 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1911 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1912 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1913 } else {
1914 contentInsets = insets.contentInsets;
1915 visibleInsets = insets.visibleInsets;
1916 touchableRegion = insets.touchableRegion;
1917 }
1918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001920 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001921 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 } catch (RemoteException e) {
1923 }
1924 }
1925 }
Romain Guy8506ab42009-06-11 17:35:47 -07001926
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001927 boolean skipDraw = false;
1928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 if (mFirst) {
1930 // handle first focus request
1931 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1932 + mView.hasFocus());
1933 if (mView != null) {
1934 if (!mView.hasFocus()) {
1935 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001937 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001940 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
1942 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001943 } else if (mWindowsAnimating) {
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07001944 if (mRemainingFrameCount <= 0) {
1945 skipDraw = true;
1946 }
1947 mRemainingFrameCount--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 }
1949
1950 mFirst = false;
1951 mWillDrawSoon = false;
1952 mNewSurfaceNeeded = false;
1953 mViewVisibility = viewVisibility;
1954
keunyoung30f420f2013-08-02 14:23:10 -07001955 if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 final boolean imTarget = WindowManager.LayoutParams
1957 .mayUseInputMethod(mWindowAttributes.flags);
1958 if (imTarget != mLastWasImTarget) {
1959 mLastWasImTarget = imTarget;
1960 InputMethodManager imm = InputMethodManager.peekInstance();
1961 if (imm != null && imTarget) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07001962 imm.onPreWindowFocus(mView, true /* hasWindowFocus */);
1963 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 mWindowAttributes.softInputMode,
1965 !mHasHadWindowFocus, mWindowAttributes.flags);
1966 }
1967 }
1968 }
Romain Guy8506ab42009-06-11 17:35:47 -07001969
Jeff Brown96e942d2011-11-30 19:55:01 -08001970 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001971 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001972 mReportNextDraw = true;
1973 }
1974
Chris Craikd36a81f2014-07-17 10:16:51 -07001975 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() ||
Romain Guyea835032011-07-28 19:24:37 -07001976 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977
Chet Haase61158c62011-09-06 22:19:45 -07001978 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001979 if (!skipDraw || mReportNextDraw) {
1980 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1981 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1982 mPendingTransitions.get(i).startChangingAnimations();
1983 }
1984 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001985 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001986
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001987 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001990 if (viewVisibility == View.VISIBLE) {
1991 // Try again
1992 scheduleTraversals();
1993 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001994 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1995 mPendingTransitions.get(i).endChangingAnimations();
1996 }
1997 mPendingTransitions.clear();
1998 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002000
2001 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 }
2003
Romain Guy3696779b2013-01-28 14:04:07 -08002004 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
2005 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
2006 try {
2007 if (!mWindowSession.outOfMemory(mWindow) &&
2008 Process.myUid() != Process.SYSTEM_UID) {
2009 Slog.w(TAG, "No processes killed for memory; killing self");
2010 Process.killProcess(Process.myPid());
2011 }
2012 } catch (RemoteException ex) {
2013 }
2014 mLayoutRequested = true; // ask wm for a new surface next time.
2015 }
2016
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002017 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
2018 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2019 try {
2020 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2021 } finally {
2022 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2023 }
2024 }
2025
Chet Haase97140572012-09-13 14:56:47 -07002026 /**
2027 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2028 * is currently undergoing a layout pass.
2029 *
2030 * @return whether the view hierarchy is currently undergoing a layout pass
2031 */
2032 boolean isInLayout() {
2033 return mInLayout;
2034 }
2035
2036 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002037 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2038 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2039 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2040 * all children in that container hierarchy are measured and laid out at the end of the layout
2041 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2042 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2043 * we check all of those views to see if any still have pending layout requests, which
2044 * indicates that they were not correctly handled by their container hierarchy. If that is
2045 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2046 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002047 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002048 * requests to the next frame to avoid possible infinite loops.
2049 *
2050 * <p>The return value from this method indicates whether the request should proceed
2051 * (if it is a request during the first layout pass) or should be skipped and posted to the
2052 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002053 *
2054 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002055 *
2056 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002057 */
Chet Haasecc699b42012-12-13 09:06:55 -08002058 boolean requestLayoutDuringLayout(final View view) {
2059 if (view.mParent == null || view.mAttachInfo == null) {
2060 // Would not normally trigger another layout, so just let it pass through as usual
2061 return true;
2062 }
Chet Haase107a4822013-03-13 06:46:50 -07002063 if (!mLayoutRequesters.contains(view)) {
2064 mLayoutRequesters.add(view);
2065 }
Chet Haase97140572012-09-13 14:56:47 -07002066 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002067 // Let the request proceed normally; it will be processed in a second layout pass
2068 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002069 return true;
Chet Haase97140572012-09-13 14:56:47 -07002070 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002071 // Don't let the request proceed during the second layout pass.
2072 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002073 return false;
Chet Haase97140572012-09-13 14:56:47 -07002074 }
2075 }
2076
Chet Haase3efa7b52012-12-03 08:33:17 -08002077 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2078 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002079 mLayoutRequested = false;
2080 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002081 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002082
2083 final View host = mView;
2084 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
2085 Log.v(TAG, "Laying out " + host + " to (" +
2086 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2087 }
2088
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002089 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2090 try {
2091 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002092
Chet Haased5a83522012-11-21 16:24:44 -08002093 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002094 int numViewsRequestingLayout = mLayoutRequesters.size();
2095 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002096 // requestLayout() was called during layout.
2097 // If no layout-request flags are set on the requesting views, there is no problem.
2098 // If some requests are still pending, then we need to clear those flags and do
2099 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002100 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2101 false);
2102 if (validLayoutRequesters != null) {
2103 // Set this flag to indicate that any further requests are happening during
2104 // the second pass, which may result in posting those requests to the next
2105 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002106 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002107
2108 // Process fresh layout requests, then measure and layout
2109 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002110 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002111 final View view = validLayoutRequesters.get(i);
2112 Log.w("View", "requestLayout() improperly called by " + view +
2113 " during layout: running second layout pass");
2114 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002115 }
2116 measureHierarchy(host, lp, mView.getContext().getResources(),
2117 desiredWindowWidth, desiredWindowHeight);
2118 mInLayout = true;
2119 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002120
Chet Haasecc699b42012-12-13 09:06:55 -08002121 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002122
2123 // Check the valid requests again, this time without checking/clearing the
2124 // layout flags, since requests happening during the second pass get noop'd
2125 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2126 if (validLayoutRequesters != null) {
2127 final ArrayList<View> finalRequesters = validLayoutRequesters;
2128 // Post second-pass requests to the next frame
2129 getRunQueue().post(new Runnable() {
2130 @Override
2131 public void run() {
2132 int numValidRequests = finalRequesters.size();
2133 for (int i = 0; i < numValidRequests; ++i) {
2134 final View view = finalRequesters.get(i);
2135 Log.w("View", "requestLayout() improperly called by " + view +
2136 " during second layout pass: posting in next frame");
2137 view.requestLayout();
2138 }
2139 }
2140 });
2141 }
Chet Haasecc699b42012-12-13 09:06:55 -08002142 }
Chet Haase107a4822013-03-13 06:46:50 -07002143
Chet Haase97140572012-09-13 14:56:47 -07002144 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002145 } finally {
2146 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2147 }
Chet Haase97140572012-09-13 14:56:47 -07002148 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002149 }
2150
Chet Haase107a4822013-03-13 06:46:50 -07002151 /**
2152 * This method is called during layout when there have been calls to requestLayout() during
2153 * layout. It walks through the list of views that requested layout to determine which ones
2154 * still need it, based on visibility in the hierarchy and whether they have already been
2155 * handled (as is usually the case with ListView children).
2156 *
2157 * @param layoutRequesters The list of views that requested layout during layout
2158 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2159 * If so, the FORCE_LAYOUT flag was not set on requesters.
2160 * @return A list of the actual views that still need to be laid out.
2161 */
2162 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2163 boolean secondLayoutRequests) {
2164
2165 int numViewsRequestingLayout = layoutRequesters.size();
2166 ArrayList<View> validLayoutRequesters = null;
2167 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2168 View view = layoutRequesters.get(i);
2169 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2170 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2171 View.PFLAG_FORCE_LAYOUT)) {
2172 boolean gone = false;
2173 View parent = view;
2174 // Only trigger new requests for views in a non-GONE hierarchy
2175 while (parent != null) {
2176 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2177 gone = true;
2178 break;
2179 }
2180 if (parent.mParent instanceof View) {
2181 parent = (View) parent.mParent;
2182 } else {
2183 parent = null;
2184 }
2185 }
2186 if (!gone) {
2187 if (validLayoutRequesters == null) {
2188 validLayoutRequesters = new ArrayList<View>();
2189 }
2190 validLayoutRequesters.add(view);
2191 }
2192 }
2193 }
2194 if (!secondLayoutRequests) {
2195 // If we're checking the layout flags, then we need to clean them up also
2196 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2197 View view = layoutRequesters.get(i);
2198 while (view != null &&
2199 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2200 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2201 if (view.mParent instanceof View) {
2202 view = (View) view.mParent;
2203 } else {
2204 view = null;
2205 }
2206 }
2207 }
2208 }
2209 layoutRequesters.clear();
2210 return validLayoutRequesters;
2211 }
2212
Igor Murashkina86ab6402013-08-30 12:58:36 -07002213 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 public void requestTransparentRegion(View child) {
2215 // the test below should not fail unless someone is messing with us
2216 checkThread();
2217 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002218 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 // Need to make sure we re-evaluate the window attributes next
2220 // time around, to ensure the window has the correct format.
2221 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002222 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002223 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 }
2225 }
2226
2227 /**
2228 * Figures out the measure spec for the root view in a window based on it's
2229 * layout params.
2230 *
2231 * @param windowSize
2232 * The available width or height of the window
2233 *
2234 * @param rootDimension
2235 * The layout params for one dimension (width or height) of the
2236 * window.
2237 *
2238 * @return The measure spec to use to measure the root view.
2239 */
Romain Guya998dff2012-03-23 18:58:36 -07002240 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 int measureSpec;
2242 switch (rootDimension) {
2243
Romain Guy980a9382010-01-08 15:06:28 -08002244 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002245 // Window can't resize. Force root view to be windowSize.
2246 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2247 break;
2248 case ViewGroup.LayoutParams.WRAP_CONTENT:
2249 // Window can resize. Set max size for root view.
2250 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2251 break;
2252 default:
2253 // Window wants to be an exact size. Force root view to be that size.
2254 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2255 break;
2256 }
2257 return measureSpec;
2258 }
2259
Alan Viveretteccb11e12014-07-08 16:04:02 -07002260 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002261 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002262
Igor Murashkina86ab6402013-08-30 12:58:36 -07002263 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002264 public void onHardwarePreDraw(DisplayListCanvas canvas) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002265 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002266 }
2267
Igor Murashkina86ab6402013-08-30 12:58:36 -07002268 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002269 public void onHardwarePostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07002270 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002271 }
2272
Chet Haaseed30fd82011-04-22 16:18:45 -07002273 /**
2274 * @hide
2275 */
2276 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07002277 view.mRenderNode.output();
John Recke248bd12015-08-05 13:53:53 -07002278 if (mAttachInfo.mHardwareRenderer != null) {
2279 ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
2280 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002281 }
2282
2283 /**
2284 * @see #PROPERTY_PROFILE_RENDERING
2285 */
2286 private void profileRendering(boolean enabled) {
2287 if (mProfileRendering) {
2288 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002289
2290 if (mRenderProfiler != null) {
2291 mChoreographer.removeFrameCallback(mRenderProfiler);
2292 }
2293 if (mRenderProfilingEnabled) {
2294 if (mRenderProfiler == null) {
2295 mRenderProfiler = new Choreographer.FrameCallback() {
2296 @Override
2297 public void doFrame(long frameTimeNanos) {
2298 mDirty.set(0, 0, mWidth, mHeight);
2299 scheduleTraversals();
2300 if (mRenderProfilingEnabled) {
2301 mChoreographer.postFrameCallback(mRenderProfiler);
2302 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002303 }
Chris Craikae4f32042013-02-07 12:57:10 -08002304 };
2305 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002306 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002307 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002308 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002309 }
2310 }
2311 }
2312
Chet Haase2f2022a2011-10-11 06:41:59 -07002313 /**
2314 * Called from draw() when DEBUG_FPS is enabled
2315 */
2316 private void trackFPS() {
2317 // Tracks frames per second drawn. First value in a series of draws may be bogus
2318 // because it down not account for the intervening idle time
2319 long nowTime = System.currentTimeMillis();
2320 if (mFpsStartTime < 0) {
2321 mFpsStartTime = mFpsPrevTime = nowTime;
2322 mFpsNumFrames = 0;
2323 } else {
2324 ++mFpsNumFrames;
2325 String thisHash = Integer.toHexString(System.identityHashCode(this));
2326 long frameTime = nowTime - mFpsPrevTime;
2327 long totalTime = nowTime - mFpsStartTime;
2328 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2329 mFpsPrevTime = nowTime;
2330 if (totalTime > 1000) {
2331 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2332 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2333 mFpsStartTime = nowTime;
2334 mFpsNumFrames = 0;
2335 }
2336 }
2337 }
2338
Jeff Brown96e942d2011-11-30 19:55:01 -08002339 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07002340 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07002341 return;
2342 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002343
Jeff Brown96e942d2011-11-30 19:55:01 -08002344 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2345 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002346
Romain Guy1f59e5c2012-05-06 14:11:16 -07002347 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002348 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2349 try {
2350 draw(fullRedrawNeeded);
2351 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002352 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002353 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2354 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002355
John Reck119907c2014-08-14 09:02:01 -07002356 // For whatever reason we didn't create a HardwareRenderer, end any
2357 // hardware animations that are now dangling
2358 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
2359 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
2360 for (int i = 0; i < count; i++) {
2361 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
2362 }
2363 mAttachInfo.mPendingAnimatingRenderNodes.clear();
2364 }
2365
Jeff Brown96e942d2011-11-30 19:55:01 -08002366 if (mReportNextDraw) {
2367 mReportNextDraw = false;
John Reck28ad7b52014-04-07 16:59:25 -07002368 if (mAttachInfo.mHardwareRenderer != null) {
2369 mAttachInfo.mHardwareRenderer.fence();
2370 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002371
2372 if (LOCAL_LOGV) {
2373 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2374 }
2375 if (mSurfaceHolder != null && mSurface.isValid()) {
2376 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2377 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2378 if (callbacks != null) {
2379 for (SurfaceHolder.Callback c : callbacks) {
2380 if (c instanceof SurfaceHolder.Callback2) {
2381 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2382 mSurfaceHolder);
2383 }
2384 }
2385 }
2386 }
2387 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002388 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002389 } catch (RemoteException e) {
2390 }
2391 }
2392 }
2393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 private void draw(boolean fullRedrawNeeded) {
2395 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002396 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 return;
2398 }
2399
Chet Haase2f2022a2011-10-11 06:41:59 -07002400 if (DEBUG_FPS) {
2401 trackFPS();
2402 }
2403
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002404 if (!sFirstDrawComplete) {
2405 synchronized (sFirstDrawHandlers) {
2406 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002407 final int count = sFirstDrawHandlers.size();
2408 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002409 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002410 }
2411 }
2412 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 scrollToRectOrFocus(null, false);
2415
Chris Craikd36a81f2014-07-17 10:16:51 -07002416 if (mAttachInfo.mViewScrollChanged) {
2417 mAttachInfo.mViewScrollChanged = false;
2418 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002419 }
Romain Guy8506ab42009-06-11 17:35:47 -07002420
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002421 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07002422 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002423 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002424 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002425 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002426 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002428 if (mCurScrollY != curScrollY) {
2429 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002431 if (mView instanceof RootViewSurfaceTaker) {
2432 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002435
Chris Craikd36a81f2014-07-17 10:16:51 -07002436 final float appScale = mAttachInfo.mApplicationScale;
2437 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002438
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002439 int resizeAlpha = 0;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002440
Jeff Brown96e942d2011-11-30 19:55:01 -08002441 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002442 if (mSurfaceHolder != null) {
2443 // The app owns the surface, we won't draw.
2444 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04002445 if (animating && mScroller != null) {
2446 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002447 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002448 return;
2449 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002450
2451 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002452 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002453 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002454 }
Chet Haasead4f7032011-06-22 09:18:31 -07002455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002456 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002457 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458 + mWindowAttributes.getTitle()
2459 + ": dirty={" + dirty.left + "," + dirty.top
2460 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002461 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2462 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 }
2464
Chris Craikd36a81f2014-07-17 10:16:51 -07002465 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07002466
Alan Viverettea51cab92014-07-16 15:15:49 -07002467 int xOffset = 0;
2468 int yOffset = curScrollY;
2469 final WindowManager.LayoutParams params = mWindowAttributes;
2470 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
2471 if (surfaceInsets != null) {
2472 xOffset -= surfaceInsets.left;
2473 yOffset -= surfaceInsets.top;
2474
2475 // Offset dirty rect for surface insets.
2476 dirty.offset(surfaceInsets.left, surfaceInsets.right);
2477 }
2478
Alan Viverette632af842014-10-28 13:45:11 -07002479 boolean accessibilityFocusDirty = false;
2480 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
2481 if (drawable != null) {
2482 final Rect bounds = mAttachInfo.mTmpInvalRect;
2483 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
2484 if (!hasFocus) {
2485 bounds.setEmpty();
2486 }
2487 if (!bounds.equals(drawable.getBounds())) {
2488 accessibilityFocusDirty = true;
2489 }
2490 }
2491
John Reckba6adf62015-02-19 14:36:50 -08002492 mAttachInfo.mDrawingTime =
2493 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
2494
Alan Viverette632af842014-10-28 13:45:11 -07002495 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002496 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07002497 // If accessibility focus moved, always invalidate the root.
2498 boolean invalidateRoot = accessibilityFocusDirty;
2499
Jeff Brown96e942d2011-11-30 19:55:01 -08002500 // Draw with hardware renderer.
2501 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07002502
John Reck0a973302014-07-16 13:29:45 -07002503 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
2504 mHardwareYOffset = yOffset;
2505 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07002506 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002507 }
2508
Alan Viverette632af842014-10-28 13:45:11 -07002509 if (invalidateRoot) {
2510 mAttachInfo.mHardwareRenderer.invalidateRoot();
2511 }
2512
Jeff Brown96e942d2011-11-30 19:55:01 -08002513 dirty.setEmpty();
2514
John Reck61375a82014-09-18 19:27:48 +00002515 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
Romain Guy3696779b2013-01-28 14:04:07 -08002516 } else {
2517 // If we get here with a disabled & requested hardware renderer, something went
2518 // wrong (an invalidate posted right before we destroyed the hardware surface
2519 // for instance) so we should just bail out. Locking the surface with software
2520 // rendering at this point would lock it forever and prevent hardware renderer
2521 // from doing its job when it comes back.
2522 // Before we request a new frame we must however attempt to reinitiliaze the
2523 // hardware renderer if it's in requested state. This would happen after an
2524 // eglTerminate() for instance.
Chris Craikd36a81f2014-07-17 10:16:51 -07002525 if (mAttachInfo.mHardwareRenderer != null &&
2526 !mAttachInfo.mHardwareRenderer.isEnabled() &&
2527 mAttachInfo.mHardwareRenderer.isRequested()) {
Romain Guy3696779b2013-01-28 14:04:07 -08002528
2529 try {
Chris Craikd36a81f2014-07-17 10:16:51 -07002530 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07002531 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002532 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002533 handleOutOfResourcesException(e);
2534 return;
2535 }
2536
2537 mFullRedrawNeeded = true;
2538 scheduleTraversals();
2539 return;
2540 }
2541
Chris Craikd36a81f2014-07-17 10:16:51 -07002542 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
Romain Guy3696779b2013-01-28 14:04:07 -08002543 return;
2544 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 }
Romain Guy8506ab42009-06-11 17:35:47 -07002547
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002548 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 mFullRedrawNeeded = true;
2550 scheduleTraversals();
2551 }
2552 }
2553
Romain Guy25eba5c2012-04-04 17:29:03 -07002554 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07002555 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002556 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07002557 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Romain Guy25eba5c2012-04-04 17:29:03 -07002558 boolean scalingRequired, Rect dirty) {
2559
2560 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07002561 final Canvas canvas;
Romain Guy25eba5c2012-04-04 17:29:03 -07002562 try {
Alan Viverettea51cab92014-07-16 15:15:49 -07002563 final int left = dirty.left;
2564 final int top = dirty.top;
2565 final int right = dirty.right;
2566 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07002567
Romain Guy25eba5c2012-04-04 17:29:03 -07002568 canvas = mSurface.lockCanvas(dirty);
2569
Romain Guye55945e2013-04-04 15:26:04 -07002570 // The dirty rectangle can be modified by Surface.lockCanvas()
2571 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07002572 if (left != dirty.left || top != dirty.top || right != dirty.right
2573 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002574 attachInfo.mIgnoreDirtyState = true;
2575 }
2576
2577 // TODO: Do this in native
2578 canvas.setDensity(mDensity);
2579 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002580 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002581 return false;
2582 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002583 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002584 // Don't assume this is due to out of memory, it could be
2585 // something else, and if it is something else then we could
2586 // kill stuff (or ourself) for no reason.
2587 mLayoutRequested = true; // ask wm for a new surface next time.
2588 return false;
2589 }
2590
2591 try {
2592 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2593 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2594 + canvas.getWidth() + ", h=" + canvas.getHeight());
2595 //canvas.drawARGB(255, 255, 0, 0);
2596 }
2597
Romain Guy25eba5c2012-04-04 17:29:03 -07002598 // If this bitmap's format includes an alpha channel, we
2599 // need to clear it before drawing so that the child will
2600 // properly re-composite its drawing on a transparent
2601 // background. This automatically respects the clip/dirty region
2602 // or
2603 // If we are applying an offset, we need to clear the area
2604 // where the offset doesn't appear to avoid having garbage
2605 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07002606 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002607 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2608 }
2609
2610 dirty.setEmpty();
2611 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07002612 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002613
2614 if (DEBUG_DRAW) {
2615 Context cxt = mView.getContext();
2616 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2617 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2618 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2619 }
2620 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002621 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07002622 if (mTranslator != null) {
2623 mTranslator.translateCanvas(canvas);
2624 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002625 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002626 attachInfo.mSetIgnoreDirtyState = false;
2627
Romain Guy25eba5c2012-04-04 17:29:03 -07002628 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07002629
2630 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002631 } finally {
2632 if (!attachInfo.mSetIgnoreDirtyState) {
2633 // Only clear the flag if it was not set during the mView.draw() call
2634 attachInfo.mIgnoreDirtyState = false;
2635 }
2636 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002637 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002638 try {
2639 surface.unlockCanvasAndPost(canvas);
2640 } catch (IllegalArgumentException e) {
2641 Log.e(TAG, "Could not unlock surface", e);
2642 mLayoutRequested = true; // ask wm for a new surface next time.
2643 //noinspection ReturnInsideFinallyBlock
2644 return false;
2645 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002646
Romain Guy25eba5c2012-04-04 17:29:03 -07002647 if (LOCAL_LOGV) {
2648 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2649 }
2650 }
2651 return true;
2652 }
2653
Alan Viverette632af842014-10-28 13:45:11 -07002654 /**
2655 * We want to draw a highlight around the current accessibility focused.
2656 * Since adding a style for all possible view is not a viable option we
2657 * have this specialized drawing method.
2658 *
2659 * Note: We are doing this here to be able to draw the highlight for
2660 * virtual views in addition to real ones.
2661 *
2662 * @param canvas The canvas on which to draw.
2663 */
2664 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
2665 final Rect bounds = mAttachInfo.mTmpInvalRect;
2666 if (getAccessibilityFocusedRect(bounds)) {
2667 final Drawable drawable = getAccessibilityFocusedDrawable();
2668 if (drawable != null) {
2669 drawable.setBounds(bounds);
2670 drawable.draw(canvas);
2671 }
2672 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
2673 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
2674 }
2675 }
2676
2677 private boolean getAccessibilityFocusedRect(Rect bounds) {
2678 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2679 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
2680 return false;
2681 }
2682
2683 final View host = mAccessibilityFocusedHost;
2684 if (host == null || host.mAttachInfo == null) {
2685 return false;
2686 }
2687
2688 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
2689 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08002690 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07002691 } else if (mAccessibilityFocusedVirtualView != null) {
2692 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
2693 } else {
2694 return false;
2695 }
2696
Alan Viverette2232add2015-05-26 15:24:18 -07002697 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07002698 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07002699 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07002700 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07002701 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
2702 attachInfo.mViewRootImpl.mHeight)) {
2703 // If no intersection, set bounds to empty.
2704 bounds.setEmpty();
2705 }
Alan Viverette632af842014-10-28 13:45:11 -07002706 return !bounds.isEmpty();
2707 }
2708
2709 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07002710 // Lazily load the accessibility focus drawable.
2711 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002712 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07002713 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2714 R.attr.accessibilityFocusedDrawable, value, true);
2715 if (resolved) {
2716 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002717 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002718 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002719 }
Chris Craikd36a81f2014-07-17 10:16:51 -07002720 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002721 }
2722
Michael Jurkaf42d90102013-05-08 18:00:04 +02002723 /**
2724 * @hide
2725 */
2726 public void setDrawDuringWindowsAnimating(boolean value) {
2727 mDrawDuringWindowsAnimating = value;
2728 if (value) {
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07002729 handleDispatchWindowAnimationStopped();
Michael Jurkaf42d90102013-05-08 18:00:04 +02002730 }
2731 }
2732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002733 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002734 final Rect ci = mAttachInfo.mContentInsets;
2735 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002736 int scrollY = 0;
2737 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 if (vi.left > ci.left || vi.top > ci.top
2740 || vi.right > ci.right || vi.bottom > ci.bottom) {
2741 // We'll assume that we aren't going to change the scroll
2742 // offset, since we want to avoid that unless it is actually
2743 // going to make the focus visible... otherwise we scroll
2744 // all over the place.
2745 scrollY = mScrollY;
2746 // We can be called for two different situations: during a draw,
2747 // to update the scroll position if the focus has changed (in which
2748 // case 'rectangle' is null), or in response to a
2749 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2750 // is non-null and we just want to scroll to whatever that
2751 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002752 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002753 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002754 return false;
2755 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002756 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002757 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002758 // If the focus has changed, then ignore any requests to scroll
2759 // to a rectangle; first we want to make sure the entire focus
2760 // view is visible.
2761 rectangle = null;
2762 }
2763 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2764 + " rectangle=" + rectangle + " ci=" + ci
2765 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002766 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 // Optimization: if the focus hasn't changed since last
2768 // time, and no layout has happened, then just leave things
2769 // as they are.
2770 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2771 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002772 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 // We need to determine if the currently focused view is
2774 // within the visible part of the window and, if not, apply
2775 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002776 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002777 mScrollMayChange = false;
2778 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2779 // Try to find the rectangle from the focus view.
2780 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2781 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2782 + mView.getWidth() + " h=" + mView.getHeight()
2783 + " ci=" + ci.toShortString()
2784 + " vi=" + vi.toShortString());
2785 if (rectangle == null) {
2786 focus.getFocusedRect(mTempRect);
2787 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2788 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002789 if (mView instanceof ViewGroup) {
2790 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2791 focus, mTempRect);
2792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002793 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2794 "Focus in window: focusRect="
2795 + mTempRect.toShortString()
2796 + " visRect=" + mVisRect.toShortString());
2797 } else {
2798 mTempRect.set(rectangle);
2799 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2800 "Request scroll to rect: "
2801 + mTempRect.toShortString()
2802 + " visRect=" + mVisRect.toShortString());
2803 }
2804 if (mTempRect.intersect(mVisRect)) {
2805 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2806 "Focus window visible rect: "
2807 + mTempRect.toShortString());
2808 if (mTempRect.height() >
2809 (mView.getHeight()-vi.top-vi.bottom)) {
2810 // If the focus simply is not going to fit, then
2811 // best is probably just to leave things as-is.
2812 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2813 "Too tall; leaving scrollY=" + scrollY);
2814 } else if ((mTempRect.top-scrollY) < vi.top) {
2815 scrollY -= vi.top - (mTempRect.top-scrollY);
2816 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2817 "Top covered; scrollY=" + scrollY);
2818 } else if ((mTempRect.bottom-scrollY)
2819 > (mView.getHeight()-vi.bottom)) {
2820 scrollY += (mTempRect.bottom-scrollY)
2821 - (mView.getHeight()-vi.bottom);
2822 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2823 "Bottom covered; scrollY=" + scrollY);
2824 }
2825 handled = true;
2826 }
2827 }
2828 }
2829 }
Romain Guy8506ab42009-06-11 17:35:47 -07002830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 if (scrollY != mScrollY) {
2832 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2833 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04002834 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835 if (mScroller == null) {
2836 mScroller = new Scroller(mView.getContext());
2837 }
2838 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2839 } else if (mScroller != null) {
2840 mScroller.abortAnimation();
2841 }
2842 mScrollY = scrollY;
2843 }
Romain Guy8506ab42009-06-11 17:35:47 -07002844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 return handled;
2846 }
Romain Guy8506ab42009-06-11 17:35:47 -07002847
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002848 /**
2849 * @hide
2850 */
2851 public View getAccessibilityFocusedHost() {
2852 return mAccessibilityFocusedHost;
2853 }
2854
2855 /**
2856 * @hide
2857 */
2858 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2859 return mAccessibilityFocusedVirtualView;
2860 }
2861
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002862 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002863 // If we have a virtual view with accessibility focus we need
2864 // to clear the focus and invalidate the virtual view bounds.
2865 if (mAccessibilityFocusedVirtualView != null) {
2866
2867 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2868 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002869
2870 // Wipe the state of the current accessibility focus since
2871 // the call into the provider to clear accessibility focus
2872 // will fire an accessibility event which will end up calling
2873 // this method and we want to have clean state when this
2874 // invocation happens.
2875 mAccessibilityFocusedHost = null;
2876 mAccessibilityFocusedVirtualView = null;
2877
Alan Viverette239a0c02013-05-07 17:17:35 -07002878 // Clear accessibility focus on the host after clearing state since
2879 // this method may be reentrant.
2880 focusHost.clearAccessibilityFocusNoCallbacks();
2881
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002882 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2883 if (provider != null) {
2884 // Invalidate the area of the cleared accessibility focus.
2885 focusNode.getBoundsInParent(mTempRect);
2886 focusHost.invalidate(mTempRect);
2887 // Clear accessibility focus in the virtual node.
2888 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2889 focusNode.getSourceNodeId());
2890 provider.performAction(virtualNodeId,
2891 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2892 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002893 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002894 }
2895 if (mAccessibilityFocusedHost != null) {
2896 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002897 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2898 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002899
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002900 // Set the new focus host and node.
2901 mAccessibilityFocusedHost = view;
2902 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07002903
2904 if (mAttachInfo.mHardwareRenderer != null) {
2905 mAttachInfo.mHardwareRenderer.invalidateRoot();
2906 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002907 }
2908
Igor Murashkina86ab6402013-08-30 12:58:36 -07002909 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002911 if (DEBUG_INPUT_RESIZE) {
2912 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002914 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002915 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916 }
2917
Igor Murashkina86ab6402013-08-30 12:58:36 -07002918 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002920 if (DEBUG_INPUT_RESIZE) {
2921 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002922 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002923 checkThread();
2924 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002925 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002926
Svetoslav Ganov42138042012-03-20 11:51:39 -07002927 @Override
2928 public ViewParent getParentForAccessibility() {
2929 return null;
2930 }
2931
Igor Murashkina86ab6402013-08-30 12:58:36 -07002932 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933 public void focusableViewAvailable(View v) {
2934 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002935 if (mView != null) {
2936 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002937 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002938 } else {
2939 // the one case where will transfer focus away from the current one
2940 // is if the current view is a view group that prefers to give focus
2941 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002942 View focused = mView.findFocus();
2943 if (focused instanceof ViewGroup) {
2944 ViewGroup group = (ViewGroup) focused;
2945 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2946 && isViewDescendantOf(v, focused)) {
2947 v.requestFocus();
2948 }
Romain Guy1c90f032011-05-24 14:59:50 -07002949 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002950 }
2951 }
2952 }
2953
Igor Murashkina86ab6402013-08-30 12:58:36 -07002954 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 public void recomputeViewAttributes(View child) {
2956 checkThread();
2957 if (mView == child) {
2958 mAttachInfo.mRecomputeGlobalAttributes = true;
2959 if (!mWillDrawSoon) {
2960 scheduleTraversals();
2961 }
2962 }
2963 }
2964
2965 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002966 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07002967 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 mView.dispatchDetachedFromWindow();
2969 }
2970
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002971 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2972 mAccessibilityManager.removeAccessibilityStateChangeListener(
2973 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07002974 mAccessibilityManager.removeHighTextContrastStateChangeListener(
2975 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002976 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002977
Romain Guya998dff2012-03-23 18:58:36 -07002978 destroyHardwareRenderer();
2979
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002980 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002981
Craig Mautner8f303ad2013-06-14 11:32:22 -07002982 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 mView = null;
2984 mAttachInfo.mRootView = null;
2985
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002986 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987
Jeff Browncc4f7db2011-08-30 20:34:48 -07002988 if (mInputQueueCallback != null && mInputQueue != null) {
2989 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002990 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002991 mInputQueueCallback = null;
2992 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002993 }
2994 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002995 mInputEventReceiver.dispose();
2996 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002997 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002999 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003000 } catch (RemoteException e) {
3001 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003002
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003003 // Dispose the input channel after removing the window so the Window Manager
3004 // doesn't interpret the input channel being closed as an abnormal termination.
3005 if (mInputChannel != null) {
3006 mInputChannel.dispose();
3007 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003008 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003009
Jeff Brownd912e1f2014-04-11 18:46:22 -07003010 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3011
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003012 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013 }
Romain Guy8506ab42009-06-11 17:35:47 -07003014
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003015 void updateConfiguration(Configuration config, boolean force) {
3016 if (DEBUG_CONFIGURATION) Log.v(TAG,
3017 "Applying new config to window "
3018 + mWindowAttributes.getTitle()
3019 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003020
Craig Mautner48d0d182013-06-11 07:53:06 -07003021 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
3022 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003023 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003024 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003025 }
3026
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003027 synchronized (sConfigCallbacks) {
3028 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
3029 sConfigCallbacks.get(i).onConfigurationChanged(config);
3030 }
3031 }
3032 if (mView != null) {
3033 // At this point the resources have been updated to
3034 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003035 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07003036 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003037 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003038 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
3039 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003040 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07003041 if (lastLayoutDirection != currentLayoutDirection &&
3042 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003043 mView.setLayoutDirection(currentLayoutDirection);
3044 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003045 mView.dispatchConfigurationChanged(config);
3046 }
3047 }
3048 }
John Reck05e85842014-04-23 14:48:28 -07003049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003050 /**
3051 * Return true if child is an ancestor of parent, (or equal to the parent).
3052 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003053 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 if (child == parent) {
3055 return true;
3056 }
3057
3058 final ViewParent theParent = child.getParent();
3059 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3060 }
3061
Yohei Yukawad2e56472015-07-28 17:00:33 -07003062 private static void forceLayout(View view) {
3063 view.forceLayout();
3064 if (view instanceof ViewGroup) {
3065 ViewGroup group = (ViewGroup) view;
3066 final int count = group.getChildCount();
3067 for (int i = 0; i < count; i++) {
3068 forceLayout(group.getChildAt(i));
3069 }
3070 }
3071 }
3072
Jeff Browna175a5b2012-02-15 19:18:31 -08003073 private final static int MSG_INVALIDATE = 1;
3074 private final static int MSG_INVALIDATE_RECT = 2;
3075 private final static int MSG_DIE = 3;
3076 private final static int MSG_RESIZED = 4;
3077 private final static int MSG_RESIZED_REPORT = 5;
3078 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07003079 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08003080 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3081 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08003082 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
3083 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
3084 private final static int MSG_CHECK_FOCUS = 13;
3085 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3086 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3087 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3088 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3089 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003090 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003091 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003092 private final static int MSG_INVALIDATE_WORLD = 22;
3093 private final static int MSG_WINDOW_MOVED = 23;
3094 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
3095 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
3096 private final static int MSG_DISPATCH_WINDOW_ANIMATION_STOPPED = 26;
3097 private final static int MSG_DISPATCH_WINDOW_ANIMATION_STARTED = 27;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098
Jeff Browna175a5b2012-02-15 19:18:31 -08003099 final class ViewRootHandler extends Handler {
3100 @Override
3101 public String getMessageName(Message message) {
3102 switch (message.what) {
3103 case MSG_INVALIDATE:
3104 return "MSG_INVALIDATE";
3105 case MSG_INVALIDATE_RECT:
3106 return "MSG_INVALIDATE_RECT";
3107 case MSG_DIE:
3108 return "MSG_DIE";
3109 case MSG_RESIZED:
3110 return "MSG_RESIZED";
3111 case MSG_RESIZED_REPORT:
3112 return "MSG_RESIZED_REPORT";
3113 case MSG_WINDOW_FOCUS_CHANGED:
3114 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003115 case MSG_DISPATCH_INPUT_EVENT:
3116 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003117 case MSG_DISPATCH_APP_VISIBILITY:
3118 return "MSG_DISPATCH_APP_VISIBILITY";
3119 case MSG_DISPATCH_GET_NEW_SURFACE:
3120 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003121 case MSG_DISPATCH_KEY_FROM_IME:
3122 return "MSG_DISPATCH_KEY_FROM_IME";
3123 case MSG_FINISH_INPUT_CONNECTION:
3124 return "MSG_FINISH_INPUT_CONNECTION";
3125 case MSG_CHECK_FOCUS:
3126 return "MSG_CHECK_FOCUS";
3127 case MSG_CLOSE_SYSTEM_DIALOGS:
3128 return "MSG_CLOSE_SYSTEM_DIALOGS";
3129 case MSG_DISPATCH_DRAG_EVENT:
3130 return "MSG_DISPATCH_DRAG_EVENT";
3131 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3132 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3133 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3134 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3135 case MSG_UPDATE_CONFIGURATION:
3136 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003137 case MSG_PROCESS_INPUT_EVENTS:
3138 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003139 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3140 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003141 case MSG_DISPATCH_WINDOW_ANIMATION_STARTED:
3142 return "MSG_DISPATCH_WINDOW_ANIMATION_STARTED";
3143 case MSG_DISPATCH_WINDOW_ANIMATION_STOPPED:
3144 return "MSG_DISPATCH_WINDOW_ANIMATION_STOPPED";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003145 case MSG_WINDOW_MOVED:
3146 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07003147 case MSG_SYNTHESIZE_INPUT_EVENT:
3148 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07003149 case MSG_DISPATCH_WINDOW_SHOWN:
3150 return "MSG_DISPATCH_WINDOW_SHOWN";
Jeff Browna175a5b2012-02-15 19:18:31 -08003151 }
3152 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003153 }
Romain Guyf9284692011-07-13 18:46:21 -07003154
Jeff Browna175a5b2012-02-15 19:18:31 -08003155 @Override
3156 public void handleMessage(Message msg) {
3157 switch (msg.what) {
3158 case MSG_INVALIDATE:
3159 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003161 case MSG_INVALIDATE_RECT:
3162 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3163 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003164 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003165 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003166 case MSG_PROCESS_INPUT_EVENTS:
3167 mProcessInputEventsScheduled = false;
3168 doProcessInputEvents();
3169 break;
3170 case MSG_DISPATCH_APP_VISIBILITY:
3171 handleAppVisibility(msg.arg1 != 0);
3172 break;
3173 case MSG_DISPATCH_GET_NEW_SURFACE:
3174 handleGetNewSurface();
3175 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003176 case MSG_RESIZED: {
3177 // Recycled in the fall through...
3178 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003179 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003180 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003181 && mPendingContentInsets.equals(args.arg2)
Adrian Roosfa104232014-06-20 16:10:14 -07003182 && mPendingStableInsets.equals(args.arg6)
Romain Guydfab3632012-10-03 14:53:25 -07003183 && mPendingVisibleInsets.equals(args.arg3)
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003184 && mPendingOutsets.equals(args.arg7)
Romain Guydfab3632012-10-03 14:53:25 -07003185 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003186 break;
Romain Guycdb86672010-03-18 18:54:50 -07003187 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003188 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003189 case MSG_RESIZED_REPORT:
3190 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003191 SomeArgs args = (SomeArgs) msg.obj;
3192
3193 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003194 if (config != null) {
3195 updateConfiguration(config, false);
3196 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003197
3198 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003199 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003200 mPendingContentInsets.set((Rect) args.arg2);
Adrian Roosfa104232014-06-20 16:10:14 -07003201 mPendingStableInsets.set((Rect) args.arg6);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003202 mPendingVisibleInsets.set((Rect) args.arg3);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003203 mPendingOutsets.set((Rect) args.arg7);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003204
3205 args.recycle();
3206
Jeff Browna175a5b2012-02-15 19:18:31 -08003207 if (msg.what == MSG_RESIZED_REPORT) {
3208 mReportNextDraw = true;
3209 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003210
Yohei Yukawad2e56472015-07-28 17:00:33 -07003211 if (mView != null) {
3212 forceLayout(mView);
3213 }
3214
Jeff Browna175a5b2012-02-15 19:18:31 -08003215 requestLayout();
3216 }
3217 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003218 case MSG_WINDOW_MOVED:
3219 if (mAdded) {
3220 final int w = mWinFrame.width();
3221 final int h = mWinFrame.height();
3222 final int l = msg.arg1;
3223 final int t = msg.arg2;
3224 mWinFrame.left = l;
3225 mWinFrame.right = l + w;
3226 mWinFrame.top = t;
3227 mWinFrame.bottom = t + h;
3228
Yohei Yukawad2e56472015-07-28 17:00:33 -07003229 if (mView != null) {
3230 forceLayout(mView);
3231 }
Craig Mautner5702d4d2012-06-30 14:10:16 -07003232 requestLayout();
3233 }
3234 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003235 case MSG_WINDOW_FOCUS_CHANGED: {
3236 if (mAdded) {
3237 boolean hasWindowFocus = msg.arg1 != 0;
3238 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239
Jeff Browna175a5b2012-02-15 19:18:31 -08003240 profileRendering(hasWindowFocus);
3241
3242 if (hasWindowFocus) {
3243 boolean inTouchMode = msg.arg2 != 0;
3244 ensureTouchModeLocally(inTouchMode);
3245
Romain Guye55945e2013-04-04 15:26:04 -07003246 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003247 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003248 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003249 final WindowManager.LayoutParams lp = mWindowAttributes;
Alan Viverette49a22e82014-07-12 20:01:27 -07003250 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
Romain Guy3696779b2013-01-28 14:04:07 -08003251 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003252 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003253 } catch (OutOfResourcesException e) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003254 Log.e(TAG, "OutOfResourcesException locking surface", e);
3255 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003256 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003257 Slog.w(TAG, "No processes killed for memory; killing self");
3258 Process.killProcess(Process.myPid());
3259 }
3260 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003261 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003262 // Retry in a bit.
3263 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3264 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003265 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003266 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
Romain Guy8506ab42009-06-11 17:35:47 -07003268
Jeff Browna175a5b2012-02-15 19:18:31 -08003269 mLastWasImTarget = WindowManager.LayoutParams
3270 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003271
Jeff Browna175a5b2012-02-15 19:18:31 -08003272 InputMethodManager imm = InputMethodManager.peekInstance();
Yohei Yukawa5f059652015-05-14 22:16:41 -07003273 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
3274 imm.onPreWindowFocus(mView, hasWindowFocus);
3275 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003276 if (mView != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003277 mAttachInfo.mKeyDispatchState.reset();
3278 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003279 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003281
Jeff Browna175a5b2012-02-15 19:18:31 -08003282 // Note: must be done after the focus change callbacks,
3283 // so all of the view state is set up correctly.
3284 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003285 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07003286 imm.onPostWindowFocus(mView, mView.findFocus(),
Jeff Browna175a5b2012-02-15 19:18:31 -08003287 mWindowAttributes.softInputMode,
3288 !mHasHadWindowFocus, mWindowAttributes.flags);
3289 }
3290 // Clear the forward bit. We can just do this directly, since
3291 // the window manager doesn't care about it.
3292 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003294 ((WindowManager.LayoutParams)mView.getLayoutParams())
3295 .softInputMode &=
3296 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3297 mHasHadWindowFocus = true;
3298 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003299
Svetoslav Ganov42138042012-03-20 11:51:39 -07003300 if (mView != null && mAccessibilityManager.isEnabled()) {
3301 if (hasWindowFocus) {
3302 mView.sendAccessibilityEvent(
3303 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003304 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003305 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003306 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003307 } break;
3308 case MSG_DIE:
3309 doDie();
3310 break;
keunyoung30f420f2013-08-02 14:23:10 -07003311 case MSG_DISPATCH_INPUT_EVENT: {
Jae Seo6a6059a2014-04-17 21:35:29 -07003312 SomeArgs args = (SomeArgs)msg.obj;
3313 InputEvent event = (InputEvent)args.arg1;
3314 InputEventReceiver receiver = (InputEventReceiver)args.arg2;
3315 enqueueInputEvent(event, receiver, 0, true);
3316 args.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003317 } break;
Michael Wright899d7052014-04-23 17:23:39 -07003318 case MSG_SYNTHESIZE_INPUT_EVENT: {
3319 InputEvent event = (InputEvent)msg.obj;
3320 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
3321 } break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003322 case MSG_DISPATCH_KEY_FROM_IME: {
3323 if (LOCAL_LOGV) Log.v(
3324 TAG, "Dispatching key "
3325 + msg.obj + " from IME to " + mView);
3326 KeyEvent event = (KeyEvent)msg.obj;
3327 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3328 // The IME is trying to say this event is from the
3329 // system! Bad bad bad!
3330 //noinspection UnusedAssignment
Michael Wright899d7052014-04-23 17:23:39 -07003331 event = KeyEvent.changeFlags(event, event.getFlags() &
3332 ~KeyEvent.FLAG_FROM_SYSTEM);
Jeff Browna175a5b2012-02-15 19:18:31 -08003333 }
3334 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3335 } break;
3336 case MSG_FINISH_INPUT_CONNECTION: {
3337 InputMethodManager imm = InputMethodManager.peekInstance();
3338 if (imm != null) {
3339 imm.reportFinishInputConnection((InputConnection)msg.obj);
3340 }
3341 } break;
3342 case MSG_CHECK_FOCUS: {
3343 InputMethodManager imm = InputMethodManager.peekInstance();
3344 if (imm != null) {
3345 imm.checkFocus();
3346 }
3347 } break;
3348 case MSG_CLOSE_SYSTEM_DIALOGS: {
3349 if (mView != null) {
3350 mView.onCloseSystemDialogs((String)msg.obj);
3351 }
3352 } break;
3353 case MSG_DISPATCH_DRAG_EVENT:
3354 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3355 DragEvent event = (DragEvent)msg.obj;
3356 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3357 handleDragEvent(event);
3358 } break;
3359 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003360 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003361 } break;
3362 case MSG_UPDATE_CONFIGURATION: {
3363 Configuration config = (Configuration)msg.obj;
3364 if (config.isOtherSeqNewer(mLastConfiguration)) {
3365 config = mLastConfiguration;
3366 }
3367 updateConfiguration(config, false);
3368 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003369 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003370 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003371 } break;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003372 case MSG_DISPATCH_WINDOW_ANIMATION_STARTED: {
3373 int remainingFrameCount = msg.arg1;
3374 handleDispatchWindowAnimationStarted(remainingFrameCount);
3375 } break;
3376 case MSG_DISPATCH_WINDOW_ANIMATION_STOPPED: {
3377 handleDispatchWindowAnimationStopped();
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003378 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003379 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003380 if (mView != null) {
3381 invalidateWorld(mView);
3382 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003383 } break;
Craig Mautner9c795042014-10-28 19:59:59 -07003384 case MSG_DISPATCH_WINDOW_SHOWN: {
3385 handleDispatchWindowShown();
3386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003388 }
3389 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003390
Jeff Browna175a5b2012-02-15 19:18:31 -08003391 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 /**
3394 * Something in the current window tells us we need to change the touch mode. For
3395 * example, we are not in touch mode, and the user touches the screen.
3396 *
3397 * If the touch mode has changed, tell the window manager, and handle it locally.
3398 *
3399 * @param inTouchMode Whether we want to be in touch mode.
3400 * @return True if the touch mode changed and focus changed was changed as a result
3401 */
3402 boolean ensureTouchMode(boolean inTouchMode) {
3403 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3404 + "touch mode is " + mAttachInfo.mInTouchMode);
3405 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3406
3407 // tell the window manager
3408 try {
keunyoung30f420f2013-08-02 14:23:10 -07003409 if (!isInLocalFocusMode()) {
3410 mWindowSession.setInTouchMode(inTouchMode);
3411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 } catch (RemoteException e) {
3413 throw new RuntimeException(e);
3414 }
3415
3416 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003417 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 }
3419
3420 /**
3421 * Ensure that the touch mode for this window is set, and if it is changing,
3422 * take the appropriate action.
3423 * @param inTouchMode Whether we want to be in touch mode.
3424 * @return True if the touch mode changed and focus changed was changed as a result
3425 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003426 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3428 + "touch mode is " + mAttachInfo.mInTouchMode);
3429
3430 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3431
3432 mAttachInfo.mInTouchMode = inTouchMode;
3433 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3434
Romain Guy2d4cff62010-04-09 15:39:00 -07003435 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 }
3437
3438 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003439 if (mView != null && mView.hasFocus()) {
3440 // note: not relying on mFocusedView here because this could
3441 // be when the window is first being added, and mFocused isn't
3442 // set yet.
3443 final View focused = mView.findFocus();
3444 if (focused != null && !focused.isFocusableInTouchMode()) {
3445 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3446 if (ancestorToTakeFocus != null) {
3447 // there is an ancestor that wants focus after its
3448 // descendants that is focusable in touch mode.. give it
3449 // focus
3450 return ancestorToTakeFocus.requestFocus();
3451 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003452 // There's nothing to focus. Clear and propagate through the
3453 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08003454 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003455 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 }
3457 }
3458 }
3459 return false;
3460 }
3461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 /**
3463 * Find an ancestor of focused that wants focus after its descendants and is
3464 * focusable in touch mode.
3465 * @param focused The currently focused view.
3466 * @return An appropriate view, or null if no such view exists.
3467 */
Romain Guya998dff2012-03-23 18:58:36 -07003468 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 ViewParent parent = focused.getParent();
3470 while (parent instanceof ViewGroup) {
3471 final ViewGroup vgParent = (ViewGroup) parent;
3472 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3473 && vgParent.isFocusableInTouchMode()) {
3474 return vgParent;
3475 }
3476 if (vgParent.isRootNamespace()) {
3477 return null;
3478 } else {
3479 parent = vgParent.getParent();
3480 }
3481 }
3482 return null;
3483 }
3484
3485 private boolean leaveTouchMode() {
3486 if (mView != null) {
3487 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003488 View focusedView = mView.findFocus();
3489 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003491 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003492 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3494 // some view group has focus, and doesn't prefer its children
3495 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003496 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 }
3498 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003499
3500 // find the best view to give focus to in this brave new non-touch-mode
3501 // world
3502 final View focused = focusSearch(null, View.FOCUS_DOWN);
3503 if (focused != null) {
3504 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 }
3506 }
3507 return false;
3508 }
3509
Jeff Brownf9e989d2013-04-04 23:04:03 -07003510 /**
3511 * Base class for implementing a stage in the chain of responsibility
3512 * for processing input events.
3513 * <p>
3514 * Events are delivered to the stage by the {@link #deliver} method. The stage
3515 * then has the choice of finishing the event or forwarding it to the next stage.
3516 * </p>
3517 */
3518 abstract class InputStage {
3519 private final InputStage mNext;
3520
3521 protected static final int FORWARD = 0;
3522 protected static final int FINISH_HANDLED = 1;
3523 protected static final int FINISH_NOT_HANDLED = 2;
3524
3525 /**
3526 * Creates an input stage.
3527 * @param next The next stage to which events should be forwarded.
3528 */
3529 public InputStage(InputStage next) {
3530 mNext = next;
3531 }
3532
3533 /**
3534 * Delivers an event to be processed.
3535 */
3536 public final void deliver(QueuedInputEvent q) {
3537 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3538 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003539 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003540 finish(q, false);
3541 } else {
3542 apply(q, onProcess(q));
3543 }
3544 }
3545
3546 /**
3547 * Marks the the input event as finished then forwards it to the next stage.
3548 */
3549 protected void finish(QueuedInputEvent q, boolean handled) {
3550 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3551 if (handled) {
3552 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3553 }
3554 forward(q);
3555 }
3556
3557 /**
3558 * Forwards the event to the next stage.
3559 */
3560 protected void forward(QueuedInputEvent q) {
3561 onDeliverToNext(q);
3562 }
3563
3564 /**
3565 * Applies a result code from {@link #onProcess} to the specified event.
3566 */
3567 protected void apply(QueuedInputEvent q, int result) {
3568 if (result == FORWARD) {
3569 forward(q);
3570 } else if (result == FINISH_HANDLED) {
3571 finish(q, true);
3572 } else if (result == FINISH_NOT_HANDLED) {
3573 finish(q, false);
3574 } else {
3575 throw new IllegalArgumentException("Invalid result: " + result);
3576 }
3577 }
3578
3579 /**
3580 * Called when an event is ready to be processed.
3581 * @return A result code indicating how the event was handled.
3582 */
3583 protected int onProcess(QueuedInputEvent q) {
3584 return FORWARD;
3585 }
3586
3587 /**
3588 * Called when an event is being delivered to the next stage.
3589 */
3590 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07003591 if (DEBUG_INPUT_STAGES) {
3592 Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
3593 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003594 if (mNext != null) {
3595 mNext.deliver(q);
3596 } else {
3597 finishInputEvent(q);
3598 }
3599 }
Jeff Brown5182c782013-10-15 20:31:52 -07003600
Michael Wright17d28ca2013-10-31 17:47:45 -07003601 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3602 if (mView == null || !mAdded) {
3603 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3604 return true;
George Mount41725de2015-04-09 08:23:05 -07003605 } else if ((!mAttachInfo.mHasWindowFocus
3606 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
3607 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08003608 // This is a focus event and the window doesn't currently have input focus or
3609 // has stopped. This could be an event that came back from the previous stage
3610 // but the window has lost focus or stopped in the meantime.
3611 if (isTerminalInputEvent(q.mEvent)) {
3612 // Don't drop terminal input events, however mark them as canceled.
3613 q.mEvent.cancel();
3614 Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);
3615 return false;
3616 }
3617
3618 // Drop non-terminal input events.
Michael Wright17d28ca2013-10-31 17:47:45 -07003619 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
3620 return true;
3621 }
3622 return false;
3623 }
3624
Jeff Brown5182c782013-10-15 20:31:52 -07003625 void dump(String prefix, PrintWriter writer) {
3626 if (mNext != null) {
3627 mNext.dump(prefix, writer);
3628 }
3629 }
George Mount41725de2015-04-09 08:23:05 -07003630
3631 private boolean isBack(InputEvent event) {
3632 if (event instanceof KeyEvent) {
3633 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
3634 } else {
3635 return false;
3636 }
3637 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003638 }
3639
3640 /**
3641 * Base class for implementing an input pipeline stage that supports
3642 * asynchronous and out-of-order processing of input events.
3643 * <p>
3644 * In addition to what a normal input stage can do, an asynchronous
3645 * input stage may also defer an input event that has been delivered to it
3646 * and finish or forward it later.
3647 * </p>
3648 */
3649 abstract class AsyncInputStage extends InputStage {
3650 private final String mTraceCounter;
3651
3652 private QueuedInputEvent mQueueHead;
3653 private QueuedInputEvent mQueueTail;
3654 private int mQueueLength;
3655
3656 protected static final int DEFER = 3;
3657
3658 /**
3659 * Creates an asynchronous input stage.
3660 * @param next The next stage to which events should be forwarded.
3661 * @param traceCounter The name of a counter to record the size of
3662 * the queue of pending events.
3663 */
3664 public AsyncInputStage(InputStage next, String traceCounter) {
3665 super(next);
3666 mTraceCounter = traceCounter;
3667 }
3668
3669 /**
3670 * Marks the event as deferred, which is to say that it will be handled
3671 * asynchronously. The caller is responsible for calling {@link #forward}
3672 * or {@link #finish} later when it is done handling the event.
3673 */
3674 protected void defer(QueuedInputEvent q) {
3675 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3676 enqueue(q);
3677 }
3678
3679 @Override
3680 protected void forward(QueuedInputEvent q) {
3681 // Clear the deferred flag.
3682 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3683
3684 // Fast path if the queue is empty.
3685 QueuedInputEvent curr = mQueueHead;
3686 if (curr == null) {
3687 super.forward(q);
3688 return;
3689 }
3690
3691 // Determine whether the event must be serialized behind any others
3692 // before it can be delivered to the next stage. This is done because
3693 // deferred events might be handled out of order by the stage.
3694 final int deviceId = q.mEvent.getDeviceId();
3695 QueuedInputEvent prev = null;
3696 boolean blocked = false;
3697 while (curr != null && curr != q) {
3698 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3699 blocked = true;
3700 }
3701 prev = curr;
3702 curr = curr.mNext;
3703 }
3704
3705 // If the event is blocked, then leave it in the queue to be delivered later.
3706 // Note that the event might not yet be in the queue if it was not previously
3707 // deferred so we will enqueue it if needed.
3708 if (blocked) {
3709 if (curr == null) {
3710 enqueue(q);
3711 }
3712 return;
3713 }
3714
3715 // The event is not blocked. Deliver it immediately.
3716 if (curr != null) {
3717 curr = curr.mNext;
3718 dequeue(q, prev);
3719 }
3720 super.forward(q);
3721
3722 // Dequeuing this event may have unblocked successors. Deliver them.
3723 while (curr != null) {
3724 if (deviceId == curr.mEvent.getDeviceId()) {
3725 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3726 break;
3727 }
3728 QueuedInputEvent next = curr.mNext;
3729 dequeue(curr, prev);
3730 super.forward(curr);
3731 curr = next;
3732 } else {
3733 prev = curr;
3734 curr = curr.mNext;
3735 }
3736 }
3737 }
3738
3739 @Override
3740 protected void apply(QueuedInputEvent q, int result) {
3741 if (result == DEFER) {
3742 defer(q);
3743 } else {
3744 super.apply(q, result);
3745 }
3746 }
3747
3748 private void enqueue(QueuedInputEvent q) {
3749 if (mQueueTail == null) {
3750 mQueueHead = q;
3751 mQueueTail = q;
3752 } else {
3753 mQueueTail.mNext = q;
3754 mQueueTail = q;
3755 }
3756
3757 mQueueLength += 1;
3758 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3759 }
3760
3761 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3762 if (prev == null) {
3763 mQueueHead = q.mNext;
3764 } else {
3765 prev.mNext = q.mNext;
3766 }
3767 if (mQueueTail == q) {
3768 mQueueTail = prev;
3769 }
3770 q.mNext = null;
3771
3772 mQueueLength -= 1;
3773 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3774 }
Jeff Brown5182c782013-10-15 20:31:52 -07003775
3776 @Override
3777 void dump(String prefix, PrintWriter writer) {
3778 writer.print(prefix);
3779 writer.print(getClass().getName());
3780 writer.print(": mQueueLength=");
3781 writer.println(mQueueLength);
3782
3783 super.dump(prefix, writer);
3784 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003785 }
3786
3787 /**
3788 * Delivers pre-ime input events to a native activity.
3789 * Does not support pointer events.
3790 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003791 final class NativePreImeInputStage extends AsyncInputStage
3792 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003793 public NativePreImeInputStage(InputStage next, String traceCounter) {
3794 super(next, traceCounter);
3795 }
3796
3797 @Override
3798 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003799 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3800 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3801 return DEFER;
3802 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003803 return FORWARD;
3804 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003805
3806 @Override
3807 public void onFinishedInputEvent(Object token, boolean handled) {
3808 QueuedInputEvent q = (QueuedInputEvent)token;
3809 if (handled) {
3810 finish(q, true);
3811 return;
3812 }
3813 forward(q);
3814 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003815 }
3816
3817 /**
3818 * Delivers pre-ime input events to the view hierarchy.
3819 * Does not support pointer events.
3820 */
3821 final class ViewPreImeInputStage extends InputStage {
3822 public ViewPreImeInputStage(InputStage next) {
3823 super(next);
3824 }
3825
3826 @Override
3827 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003828 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003829 return processKeyEvent(q);
3830 }
3831 return FORWARD;
3832 }
3833
3834 private int processKeyEvent(QueuedInputEvent q) {
3835 final KeyEvent event = (KeyEvent)q.mEvent;
3836 if (mView.dispatchKeyEventPreIme(event)) {
3837 return FINISH_HANDLED;
3838 }
3839 return FORWARD;
3840 }
3841 }
3842
3843 /**
3844 * Delivers input events to the ime.
3845 * Does not support pointer events.
3846 */
3847 final class ImeInputStage extends AsyncInputStage
3848 implements InputMethodManager.FinishedInputEventCallback {
3849 public ImeInputStage(InputStage next, String traceCounter) {
3850 super(next, traceCounter);
3851 }
3852
3853 @Override
3854 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07003855 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003856 InputMethodManager imm = InputMethodManager.peekInstance();
3857 if (imm != null) {
3858 final InputEvent event = q.mEvent;
3859 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3860 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3861 if (result == InputMethodManager.DISPATCH_HANDLED) {
3862 return FINISH_HANDLED;
3863 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07003864 // The IME could not handle it, so skip along to the next InputStage
3865 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003866 } else {
3867 return DEFER; // callback will be invoked later
3868 }
3869 }
3870 }
3871 return FORWARD;
3872 }
3873
3874 @Override
3875 public void onFinishedInputEvent(Object token, boolean handled) {
3876 QueuedInputEvent q = (QueuedInputEvent)token;
3877 if (handled) {
3878 finish(q, true);
3879 return;
3880 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003881 forward(q);
3882 }
3883 }
3884
3885 /**
3886 * Performs early processing of post-ime input events.
3887 */
3888 final class EarlyPostImeInputStage extends InputStage {
3889 public EarlyPostImeInputStage(InputStage next) {
3890 super(next);
3891 }
3892
3893 @Override
3894 protected int onProcess(QueuedInputEvent q) {
3895 if (q.mEvent instanceof KeyEvent) {
3896 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003897 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003898 final int source = q.mEvent.getSource();
3899 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003900 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003901 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003902 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003903 return FORWARD;
3904 }
3905
3906 private int processKeyEvent(QueuedInputEvent q) {
3907 final KeyEvent event = (KeyEvent)q.mEvent;
3908
3909 // If the key's purpose is to exit touch mode then we consume it
3910 // and consider it handled.
3911 if (checkForLeavingTouchModeAndConsume(event)) {
3912 return FINISH_HANDLED;
3913 }
3914
3915 // Make sure the fallback event policy sees all keys that will be
3916 // delivered to the view hierarchy.
3917 mFallbackEventHandler.preDispatchKeyEvent(event);
3918 return FORWARD;
3919 }
3920
3921 private int processPointerEvent(QueuedInputEvent q) {
3922 final MotionEvent event = (MotionEvent)q.mEvent;
3923
3924 // Translate the pointer event for compatibility, if needed.
3925 if (mTranslator != null) {
3926 mTranslator.translateEventInScreenToAppWindow(event);
3927 }
3928
3929 // Enter touch mode on down or scroll.
3930 final int action = event.getAction();
3931 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3932 ensureTouchMode(true);
3933 }
3934
3935 // Offset the scroll position.
3936 if (mCurScrollY != 0) {
3937 event.offsetLocation(0, mCurScrollY);
3938 }
3939
3940 // Remember the touch position for possible drag-initiation.
3941 if (event.isTouchEvent()) {
3942 mLastTouchPoint.x = event.getRawX();
3943 mLastTouchPoint.y = event.getRawY();
3944 }
3945 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003946 }
3947 }
3948
Jeff Brownf9e989d2013-04-04 23:04:03 -07003949 /**
3950 * Delivers post-ime input events to a native activity.
3951 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003952 final class NativePostImeInputStage extends AsyncInputStage
3953 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003954 public NativePostImeInputStage(InputStage next, String traceCounter) {
3955 super(next, traceCounter);
3956 }
3957
3958 @Override
3959 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003960 if (mInputQueue != null) {
3961 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3962 return DEFER;
3963 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003964 return FORWARD;
3965 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003966
3967 @Override
3968 public void onFinishedInputEvent(Object token, boolean handled) {
3969 QueuedInputEvent q = (QueuedInputEvent)token;
3970 if (handled) {
3971 finish(q, true);
3972 return;
3973 }
3974 forward(q);
3975 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003976 }
3977
3978 /**
3979 * Delivers post-ime input events to the view hierarchy.
3980 */
3981 final class ViewPostImeInputStage extends InputStage {
3982 public ViewPostImeInputStage(InputStage next) {
3983 super(next);
3984 }
3985
3986 @Override
3987 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003988 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003989 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003990 } else {
Dianne Hackborn021d2432013-10-13 15:20:09 -07003991 // If delivering a new non-key event, make sure the window is
3992 // now allowed to start updating.
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003993 handleDispatchWindowAnimationStopped();
Jeff Brown29c0ed22013-01-14 13:50:37 -08003994 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003995 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3996 return processPointerEvent(q);
3997 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3998 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003999 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004000 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004001 }
4002 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004003 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004004
Michael Wright9d744c72014-02-18 21:27:42 -08004005 @Override
4006 protected void onDeliverToNext(QueuedInputEvent q) {
4007 if (mUnbufferedInputDispatch
4008 && q.mEvent instanceof MotionEvent
4009 && ((MotionEvent)q.mEvent).isTouchEvent()
4010 && isTerminalInputEvent(q.mEvent)) {
4011 mUnbufferedInputDispatch = false;
4012 scheduleConsumeBatchedInput();
4013 }
4014 super.onDeliverToNext(q);
4015 }
4016
Jeff Brownf9e989d2013-04-04 23:04:03 -07004017 private int processKeyEvent(QueuedInputEvent q) {
4018 final KeyEvent event = (KeyEvent)q.mEvent;
4019
Dianne Hackborn021d2432013-10-13 15:20:09 -07004020 if (event.getAction() != KeyEvent.ACTION_UP) {
4021 // If delivering a new key event, make sure the window is
4022 // now allowed to start updating.
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07004023 handleDispatchWindowAnimationStopped();
Dianne Hackborn021d2432013-10-13 15:20:09 -07004024 }
4025
Jeff Brownf9e989d2013-04-04 23:04:03 -07004026 // Deliver the key to the view hierarchy.
4027 if (mView.dispatchKeyEvent(event)) {
4028 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004029 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004030
Michael Wright17d28ca2013-10-31 17:47:45 -07004031 if (shouldDropInputEvent(q)) {
4032 return FINISH_NOT_HANDLED;
4033 }
4034
Jeff Brownf9e989d2013-04-04 23:04:03 -07004035 // If the Control modifier is held, try to interpret the key as a shortcut.
4036 if (event.getAction() == KeyEvent.ACTION_DOWN
4037 && event.isCtrlPressed()
4038 && event.getRepeatCount() == 0
4039 && !KeyEvent.isModifierKey(event.getKeyCode())) {
4040 if (mView.dispatchKeyShortcutEvent(event)) {
4041 return FINISH_HANDLED;
4042 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004043 if (shouldDropInputEvent(q)) {
4044 return FINISH_NOT_HANDLED;
4045 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004046 }
4047
4048 // Apply the fallback event policy.
4049 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
4050 return FINISH_HANDLED;
4051 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004052 if (shouldDropInputEvent(q)) {
4053 return FINISH_NOT_HANDLED;
4054 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004055
4056 // Handle automatic focus changes.
4057 if (event.getAction() == KeyEvent.ACTION_DOWN) {
4058 int direction = 0;
4059 switch (event.getKeyCode()) {
4060 case KeyEvent.KEYCODE_DPAD_LEFT:
4061 if (event.hasNoModifiers()) {
4062 direction = View.FOCUS_LEFT;
4063 }
4064 break;
4065 case KeyEvent.KEYCODE_DPAD_RIGHT:
4066 if (event.hasNoModifiers()) {
4067 direction = View.FOCUS_RIGHT;
4068 }
4069 break;
4070 case KeyEvent.KEYCODE_DPAD_UP:
4071 if (event.hasNoModifiers()) {
4072 direction = View.FOCUS_UP;
4073 }
4074 break;
4075 case KeyEvent.KEYCODE_DPAD_DOWN:
4076 if (event.hasNoModifiers()) {
4077 direction = View.FOCUS_DOWN;
4078 }
4079 break;
4080 case KeyEvent.KEYCODE_TAB:
4081 if (event.hasNoModifiers()) {
4082 direction = View.FOCUS_FORWARD;
4083 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4084 direction = View.FOCUS_BACKWARD;
4085 }
4086 break;
4087 }
4088 if (direction != 0) {
4089 View focused = mView.findFocus();
4090 if (focused != null) {
4091 View v = focused.focusSearch(direction);
4092 if (v != null && v != focused) {
4093 // do the math the get the interesting rect
4094 // of previous focused into the coord system of
4095 // newly focused view
4096 focused.getFocusedRect(mTempRect);
4097 if (mView instanceof ViewGroup) {
4098 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4099 focused, mTempRect);
4100 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
4101 v, mTempRect);
4102 }
4103 if (v.requestFocus(direction, mTempRect)) {
4104 playSoundEffect(SoundEffectConstants
4105 .getContantForFocusDirection(direction));
4106 return FINISH_HANDLED;
4107 }
4108 }
4109
4110 // Give the focused view a last chance to handle the dpad key.
4111 if (mView.dispatchUnhandledMove(focused, direction)) {
4112 return FINISH_HANDLED;
4113 }
4114 } else {
4115 // find the best view to give focus to in this non-touch-mode with no-focus
4116 View v = focusSearch(null, direction);
4117 if (v != null && v.requestFocus(direction)) {
4118 return FINISH_HANDLED;
4119 }
4120 }
4121 }
4122 }
4123 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004124 }
4125
Jeff Brownf9e989d2013-04-04 23:04:03 -07004126 private int processPointerEvent(QueuedInputEvent q) {
4127 final MotionEvent event = (MotionEvent)q.mEvent;
4128
Michael Wright9d744c72014-02-18 21:27:42 -08004129 mAttachInfo.mUnbufferedDispatchRequested = false;
4130 boolean handled = mView.dispatchPointerEvent(event);
4131 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
4132 mUnbufferedInputDispatch = true;
4133 if (mConsumeBatchedInputScheduled) {
4134 scheduleConsumeBatchedInputImmediately();
4135 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004136 }
Michael Wright9d744c72014-02-18 21:27:42 -08004137 return handled ? FINISH_HANDLED : FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004138 }
4139
Jeff Brownf9e989d2013-04-04 23:04:03 -07004140 private int processTrackballEvent(QueuedInputEvent q) {
4141 final MotionEvent event = (MotionEvent)q.mEvent;
4142
4143 if (mView.dispatchTrackballEvent(event)) {
4144 return FINISH_HANDLED;
4145 }
4146 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004147 }
4148
Jeff Brownf9e989d2013-04-04 23:04:03 -07004149 private int processGenericMotionEvent(QueuedInputEvent q) {
4150 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004151
Jeff Brownf9e989d2013-04-04 23:04:03 -07004152 // Deliver the event to the view.
4153 if (mView.dispatchGenericMotionEvent(event)) {
4154 return FINISH_HANDLED;
4155 }
4156 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004157 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004158 }
4159
Jeff Brownf9e989d2013-04-04 23:04:03 -07004160 /**
Jeff Brown678a1252013-04-09 17:46:25 -07004161 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004162 */
4163 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07004164 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
4165 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
4166 private final SyntheticTouchNavigationHandler mTouchNavigation =
4167 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07004168 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004169
4170 public SyntheticInputStage() {
4171 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08004172 }
4173
Jeff Brownf9e989d2013-04-04 23:04:03 -07004174 @Override
4175 protected int onProcess(QueuedInputEvent q) {
4176 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
4177 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004178 final MotionEvent event = (MotionEvent)q.mEvent;
4179 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004180 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004181 mTrackball.process(event);
4182 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004183 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004184 mJoystick.process(event);
4185 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004186 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4187 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004188 mTouchNavigation.process(event);
4189 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004190 }
Michael Wright899d7052014-04-23 17:23:39 -07004191 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
4192 mKeyboard.process((KeyEvent)q.mEvent);
4193 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004194 }
Michael Wright899d7052014-04-23 17:23:39 -07004195
Jeff Brownf9e989d2013-04-04 23:04:03 -07004196 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197 }
4198
Jeff Brownf9e989d2013-04-04 23:04:03 -07004199 @Override
4200 protected void onDeliverToNext(QueuedInputEvent q) {
4201 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4202 // Cancel related synthetic events if any prior stage has handled the event.
4203 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004204 final MotionEvent event = (MotionEvent)q.mEvent;
4205 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004206 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004207 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004208 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004209 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004210 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4211 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004212 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004213 }
4214 }
4215 }
4216 super.onDeliverToNext(q);
4217 }
Jeff Brown678a1252013-04-09 17:46:25 -07004218 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004219
Jeff Brown678a1252013-04-09 17:46:25 -07004220 /**
4221 * Creates dpad events from unhandled trackball movements.
4222 */
4223 final class SyntheticTrackballHandler {
4224 private final TrackballAxis mX = new TrackballAxis();
4225 private final TrackballAxis mY = new TrackballAxis();
4226 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004227
Jeff Brown678a1252013-04-09 17:46:25 -07004228 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004229 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004230 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004231 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004232 // It has been too long since the last movement,
4233 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004234 mX.reset(0);
4235 mY.reset(0);
4236 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004237 }
4238
4239 final int action = event.getAction();
4240 final int metaState = event.getMetaState();
4241 switch (action) {
4242 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004243 mX.reset(2);
4244 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004245 enqueueInputEvent(new KeyEvent(curTime, curTime,
4246 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4247 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4248 InputDevice.SOURCE_KEYBOARD));
4249 break;
4250 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004251 mX.reset(2);
4252 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004253 enqueueInputEvent(new KeyEvent(curTime, curTime,
4254 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4255 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4256 InputDevice.SOURCE_KEYBOARD));
4257 break;
4258 }
4259
Jeff Brown678a1252013-04-09 17:46:25 -07004260 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4261 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004262 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004263 + " / Y=" + mY.position + " step="
4264 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004265 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004266 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4267 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004268
4269 // Generate DPAD events based on the trackball movement.
4270 // We pick the axis that has moved the most as the direction of
4271 // the DPAD. When we generate DPAD events for one axis, then the
4272 // other axis is reset -- we don't want to perform DPAD jumps due
4273 // to slight movements in the trackball when making major movements
4274 // along the other axis.
4275 int keycode = 0;
4276 int movement = 0;
4277 float accel = 1;
4278 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004279 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004280 if (movement != 0) {
4281 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4282 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004283 accel = mX.acceleration;
4284 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004285 }
4286 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004287 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004288 if (movement != 0) {
4289 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4290 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004291 accel = mY.acceleration;
4292 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004293 }
4294 }
4295
4296 if (keycode != 0) {
4297 if (movement < 0) movement = -movement;
4298 int accelMovement = (int)(movement * accel);
4299 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4300 + " accelMovement=" + accelMovement
4301 + " accel=" + accel);
4302 if (accelMovement > movement) {
4303 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4304 + keycode);
4305 movement--;
4306 int repeatCount = accelMovement - movement;
4307 enqueueInputEvent(new KeyEvent(curTime, curTime,
4308 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4309 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4310 InputDevice.SOURCE_KEYBOARD));
4311 }
4312 while (movement > 0) {
4313 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4314 + keycode);
4315 movement--;
4316 curTime = SystemClock.uptimeMillis();
4317 enqueueInputEvent(new KeyEvent(curTime, curTime,
4318 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4319 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4320 InputDevice.SOURCE_KEYBOARD));
4321 enqueueInputEvent(new KeyEvent(curTime, curTime,
4322 KeyEvent.ACTION_UP, keycode, 0, metaState,
4323 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4324 InputDevice.SOURCE_KEYBOARD));
4325 }
Jeff Brown678a1252013-04-09 17:46:25 -07004326 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004327 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004328 }
4329
Jeff Brown678a1252013-04-09 17:46:25 -07004330 public void cancel(MotionEvent event) {
4331 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004332
Jeff Brownf9e989d2013-04-04 23:04:03 -07004333 // If we reach this, we consumed a trackball event.
4334 // Because we will not translate the trackball event into a key event,
4335 // touch mode will not exit, so we exit touch mode here.
4336 if (mView != null && mAdded) {
4337 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004338 }
4339 }
Jeff Brown678a1252013-04-09 17:46:25 -07004340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004341
Jeff Brown678a1252013-04-09 17:46:25 -07004342 /**
4343 * Maintains state information for a single trackball axis, generating
4344 * discrete (DPAD) movements based on raw trackball motion.
4345 */
4346 static final class TrackballAxis {
4347 /**
4348 * The maximum amount of acceleration we will apply.
4349 */
4350 static final float MAX_ACCELERATION = 20;
4351
4352 /**
4353 * The maximum amount of time (in milliseconds) between events in order
4354 * for us to consider the user to be doing fast trackball movements,
4355 * and thus apply an acceleration.
4356 */
4357 static final long FAST_MOVE_TIME = 150;
4358
4359 /**
4360 * Scaling factor to the time (in milliseconds) between events to how
4361 * much to multiple/divide the current acceleration. When movement
4362 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4363 * FAST_MOVE_TIME it divides it.
4364 */
4365 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4366
4367 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4368 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4369 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4370
4371 float position;
4372 float acceleration = 1;
4373 long lastMoveTime = 0;
4374 int step;
4375 int dir;
4376 int nonAccelMovement;
4377
4378 void reset(int _step) {
4379 position = 0;
4380 acceleration = 1;
4381 lastMoveTime = 0;
4382 step = _step;
4383 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004384 }
4385
Jeff Brown678a1252013-04-09 17:46:25 -07004386 /**
4387 * Add trackball movement into the state. If the direction of movement
4388 * has been reversed, the state is reset before adding the
4389 * movement (so that you don't have to compensate for any previously
4390 * collected movement before see the result of the movement in the
4391 * new direction).
4392 *
4393 * @return Returns the absolute value of the amount of movement
4394 * collected so far.
4395 */
4396 float collect(float off, long time, String axis) {
4397 long normTime;
4398 if (off > 0) {
4399 normTime = (long)(off * FAST_MOVE_TIME);
4400 if (dir < 0) {
4401 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4402 position = 0;
4403 step = 0;
4404 acceleration = 1;
4405 lastMoveTime = 0;
4406 }
4407 dir = 1;
4408 } else if (off < 0) {
4409 normTime = (long)((-off) * FAST_MOVE_TIME);
4410 if (dir > 0) {
4411 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4412 position = 0;
4413 step = 0;
4414 acceleration = 1;
4415 lastMoveTime = 0;
4416 }
4417 dir = -1;
4418 } else {
4419 normTime = 0;
4420 }
4421
4422 // The number of milliseconds between each movement that is
4423 // considered "normal" and will not result in any acceleration
4424 // or deceleration, scaled by the offset we have here.
4425 if (normTime > 0) {
4426 long delta = time - lastMoveTime;
4427 lastMoveTime = time;
4428 float acc = acceleration;
4429 if (delta < normTime) {
4430 // The user is scrolling rapidly, so increase acceleration.
4431 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4432 if (scale > 1) acc *= scale;
4433 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4434 + off + " normTime=" + normTime + " delta=" + delta
4435 + " scale=" + scale + " acc=" + acc);
4436 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4437 } else {
4438 // The user is scrolling slowly, so decrease acceleration.
4439 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4440 if (scale > 1) acc /= scale;
4441 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4442 + off + " normTime=" + normTime + " delta=" + delta
4443 + " scale=" + scale + " acc=" + acc);
4444 acceleration = acc > 1 ? acc : 1;
4445 }
4446 }
4447 position += off;
4448 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004449 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004450
Jeff Brown678a1252013-04-09 17:46:25 -07004451 /**
4452 * Generate the number of discrete movement events appropriate for
4453 * the currently collected trackball movement.
4454 *
4455 * @return Returns the number of discrete movements, either positive
4456 * or negative, or 0 if there is not enough trackball movement yet
4457 * for a discrete movement.
4458 */
4459 int generate() {
4460 int movement = 0;
4461 nonAccelMovement = 0;
4462 do {
4463 final int dir = position >= 0 ? 1 : -1;
4464 switch (step) {
4465 // If we are going to execute the first step, then we want
4466 // to do this as soon as possible instead of waiting for
4467 // a full movement, in order to make things look responsive.
4468 case 0:
4469 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4470 return movement;
4471 }
4472 movement += dir;
4473 nonAccelMovement += dir;
4474 step = 1;
4475 break;
4476 // If we have generated the first movement, then we need
4477 // to wait for the second complete trackball motion before
4478 // generating the second discrete movement.
4479 case 1:
4480 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4481 return movement;
4482 }
4483 movement += dir;
4484 nonAccelMovement += dir;
4485 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4486 step = 2;
4487 break;
4488 // After the first two, we generate discrete movements
4489 // consistently with the trackball, applying an acceleration
4490 // if the trackball is moving quickly. This is a simple
4491 // acceleration on top of what we already compute based
4492 // on how quickly the wheel is being turned, to apply
4493 // a longer increasing acceleration to continuous movement
4494 // in one direction.
4495 default:
4496 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4497 return movement;
4498 }
4499 movement += dir;
4500 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4501 float acc = acceleration;
4502 acc *= 1.1f;
4503 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4504 break;
4505 }
4506 } while (true);
4507 }
4508 }
4509
4510 /**
4511 * Creates dpad events from unhandled joystick movements.
4512 */
4513 final class SyntheticJoystickHandler extends Handler {
Michael Wright9adca062014-03-19 11:51:26 -07004514 private final static String TAG = "SyntheticJoystickHandler";
Jeff Brown678a1252013-04-09 17:46:25 -07004515 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4516 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4517
4518 private int mLastXDirection;
4519 private int mLastYDirection;
4520 private int mLastXKeyCode;
4521 private int mLastYKeyCode;
4522
4523 public SyntheticJoystickHandler() {
4524 super(true);
4525 }
4526
4527 @Override
4528 public void handleMessage(Message msg) {
4529 switch (msg.what) {
4530 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4531 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4532 KeyEvent oldEvent = (KeyEvent)msg.obj;
4533 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4534 SystemClock.uptimeMillis(),
4535 oldEvent.getRepeatCount() + 1);
4536 if (mAttachInfo.mHasWindowFocus) {
4537 enqueueInputEvent(e);
4538 Message m = obtainMessage(msg.what, e);
4539 m.setAsynchronous(true);
4540 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4541 }
4542 } break;
4543 }
4544 }
4545
4546 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07004547 switch(event.getActionMasked()) {
4548 case MotionEvent.ACTION_CANCEL:
4549 cancel(event);
4550 break;
4551 case MotionEvent.ACTION_MOVE:
4552 update(event, true);
4553 break;
4554 default:
4555 Log.w(TAG, "Unexpected action: " + event.getActionMasked());
4556 }
Jeff Brown678a1252013-04-09 17:46:25 -07004557 }
4558
Michael Wright9adca062014-03-19 11:51:26 -07004559 private void cancel(MotionEvent event) {
4560 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
4561 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brown678a1252013-04-09 17:46:25 -07004562 update(event, false);
4563 }
4564
4565 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004566 final long time = event.getEventTime();
4567 final int metaState = event.getMetaState();
4568 final int deviceId = event.getDeviceId();
4569 final int source = event.getSource();
4570
4571 int xDirection = joystickAxisValueToDirection(
4572 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4573 if (xDirection == 0) {
4574 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004575 }
4576
Jeff Brownf9e989d2013-04-04 23:04:03 -07004577 int yDirection = joystickAxisValueToDirection(
4578 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4579 if (yDirection == 0) {
4580 yDirection = joystickAxisValueToDirection(event.getY());
4581 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004582
Jeff Brown678a1252013-04-09 17:46:25 -07004583 if (xDirection != mLastXDirection) {
4584 if (mLastXKeyCode != 0) {
4585 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004586 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004587 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004588 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004589 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004590 }
4591
Jeff Brown678a1252013-04-09 17:46:25 -07004592 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004593
4594 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004595 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004596 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4597 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004598 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004599 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4600 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004601 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004602 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004603 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004604 }
4605 }
4606
Jeff Brown678a1252013-04-09 17:46:25 -07004607 if (yDirection != mLastYDirection) {
4608 if (mLastYKeyCode != 0) {
4609 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004610 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004611 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004612 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004613 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004614 }
4615
Jeff Brown678a1252013-04-09 17:46:25 -07004616 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004617
4618 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004619 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004620 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4621 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004622 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004623 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4624 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004625 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004626 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004627 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004628 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004629 }
4630 }
4631
Jeff Brownf9e989d2013-04-04 23:04:03 -07004632 private int joystickAxisValueToDirection(float value) {
4633 if (value >= 0.5f) {
4634 return 1;
4635 } else if (value <= -0.5f) {
4636 return -1;
4637 } else {
4638 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004639 }
4640 }
Jeff Brown678a1252013-04-09 17:46:25 -07004641 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004642
Jeff Brown678a1252013-04-09 17:46:25 -07004643 /**
4644 * Creates dpad events from unhandled touch navigation movements.
4645 */
4646 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004647 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4648 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004649
Jeff Brown4dac9012013-04-10 01:03:19 -07004650 // Assumed nominal width and height in millimeters of a touch navigation pad,
4651 // if no resolution information is available from the input system.
4652 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4653 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004654
Jeff Brown4dac9012013-04-10 01:03:19 -07004655 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004656
Jeff Brown4dac9012013-04-10 01:03:19 -07004657 // The nominal distance traveled to move by one unit.
4658 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4659
4660 // Minimum and maximum fling velocity in ticks per second.
4661 // The minimum velocity should be set such that we perform enough ticks per
4662 // second that the fling appears to be fluid. For example, if we set the minimum
4663 // to 2 ticks per second, then there may be up to half a second delay between the next
4664 // to last and last ticks which is noticeably discrete and jerky. This value should
4665 // probably not be set to anything less than about 4.
4666 // If fling accuracy is a problem then consider tuning the tick distance instead.
4667 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4668 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4669
4670 // Fling velocity decay factor applied after each new key is emitted.
4671 // This parameter controls the deceleration and overall duration of the fling.
4672 // The fling stops automatically when its velocity drops below the minimum
4673 // fling velocity defined above.
4674 private static final float FLING_TICK_DECAY = 0.8f;
4675
4676 /* The input device that we are tracking. */
4677
4678 private int mCurrentDeviceId = -1;
4679 private int mCurrentSource;
4680 private boolean mCurrentDeviceSupported;
4681
4682 /* Configuration for the current input device. */
4683
Jeff Brown4dac9012013-04-10 01:03:19 -07004684 // The scaled tick distance. A movement of this amount should generally translate
4685 // into a single dpad event in a given direction.
4686 private float mConfigTickDistance;
4687
4688 // The minimum and maximum scaled fling velocity.
4689 private float mConfigMinFlingVelocity;
4690 private float mConfigMaxFlingVelocity;
4691
4692 /* Tracking state. */
4693
4694 // The velocity tracker for detecting flings.
4695 private VelocityTracker mVelocityTracker;
4696
4697 // The active pointer id, or -1 if none.
4698 private int mActivePointerId = -1;
4699
John Reck79d81e62013-11-05 13:26:57 -08004700 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07004701 private float mStartX;
4702 private float mStartY;
4703
4704 // Most recently observed position.
4705 private float mLastX;
4706 private float mLastY;
4707
4708 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004709 private float mAccumulatedX;
4710 private float mAccumulatedY;
4711
Jeff Brown4dac9012013-04-10 01:03:19 -07004712 // Set to true if any movement was delivered to the app.
4713 // Implies that tap slop was exceeded.
4714 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004715
Jeff Brown4dac9012013-04-10 01:03:19 -07004716 // The most recently sent key down event.
4717 // The keycode remains set until the direction changes or a fling ends
4718 // so that repeated key events may be generated as required.
4719 private long mPendingKeyDownTime;
4720 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4721 private int mPendingKeyRepeatCount;
4722 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004723
Jeff Brown4dac9012013-04-10 01:03:19 -07004724 // The current fling velocity while a fling is in progress.
4725 private boolean mFlinging;
4726 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004727
4728 public SyntheticTouchNavigationHandler() {
4729 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004730 }
4731
4732 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004733 // Update the current device information.
4734 final long time = event.getEventTime();
4735 final int deviceId = event.getDeviceId();
4736 final int source = event.getSource();
4737 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4738 finishKeys(time);
4739 finishTracking(time);
4740 mCurrentDeviceId = deviceId;
4741 mCurrentSource = source;
4742 mCurrentDeviceSupported = false;
4743 InputDevice device = event.getDevice();
4744 if (device != null) {
4745 // In order to support an input device, we must know certain
4746 // characteristics about it, such as its size and resolution.
4747 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4748 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4749 if (xRange != null && yRange != null) {
4750 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004751
Jeff Brown4dac9012013-04-10 01:03:19 -07004752 // Infer the resolution if it not actually known.
4753 float xRes = xRange.getResolution();
4754 if (xRes <= 0) {
4755 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4756 }
4757 float yRes = yRange.getResolution();
4758 if (yRes <= 0) {
4759 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4760 }
4761 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004762
Jeff Brown4dac9012013-04-10 01:03:19 -07004763 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07004764 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4765 mConfigMinFlingVelocity =
4766 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4767 mConfigMaxFlingVelocity =
4768 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4769
4770 if (LOCAL_DEBUG) {
4771 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4772 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07004773 + ", mConfigTickDistance=" + mConfigTickDistance
4774 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4775 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4776 }
4777 }
4778 }
Jeff Brown678a1252013-04-09 17:46:25 -07004779 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004780 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004781 return;
4782 }
4783
Jeff Brown4dac9012013-04-10 01:03:19 -07004784 // Handle the event.
4785 final int action = event.getActionMasked();
4786 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004787 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004788 boolean caughtFling = mFlinging;
4789 finishKeys(time);
4790 finishTracking(time);
4791 mActivePointerId = event.getPointerId(0);
4792 mVelocityTracker = VelocityTracker.obtain();
4793 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07004794 mStartX = event.getX();
4795 mStartY = event.getY();
4796 mLastX = mStartX;
4797 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004798 mAccumulatedX = 0;
4799 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004800
4801 // If we caught a fling, then pretend that the tap slop has already
4802 // been exceeded to suppress taps whose only purpose is to stop the fling.
4803 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004804 break;
4805 }
4806
Jeff Brown4dac9012013-04-10 01:03:19 -07004807 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004808 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004809 if (mActivePointerId < 0) {
4810 break;
4811 }
4812 final int index = event.findPointerIndex(mActivePointerId);
4813 if (index < 0) {
4814 finishKeys(time);
4815 finishTracking(time);
4816 break;
4817 }
Jeff Brown678a1252013-04-09 17:46:25 -07004818
Jeff Brown4dac9012013-04-10 01:03:19 -07004819 mVelocityTracker.addMovement(event);
4820 final float x = event.getX(index);
4821 final float y = event.getY(index);
4822 mAccumulatedX += x - mLastX;
4823 mAccumulatedY += y - mLastY;
4824 mLastX = x;
4825 mLastY = y;
4826
4827 // Consume any accumulated movement so far.
4828 final int metaState = event.getMetaState();
4829 consumeAccumulatedMovement(time, metaState);
4830
4831 // Detect taps and flings.
4832 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07004833 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004834 // It might be a fling.
4835 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4836 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4837 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4838 if (!startFling(time, vx, vy)) {
4839 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004840 }
4841 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004842 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004843 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004844 break;
4845 }
4846
4847 case MotionEvent.ACTION_CANCEL: {
4848 finishKeys(time);
4849 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004850 break;
4851 }
4852 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004853 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004854
4855 public void cancel(MotionEvent event) {
4856 if (mCurrentDeviceId == event.getDeviceId()
4857 && mCurrentSource == event.getSource()) {
4858 final long time = event.getEventTime();
4859 finishKeys(time);
4860 finishTracking(time);
4861 }
4862 }
4863
4864 private void finishKeys(long time) {
4865 cancelFling();
4866 sendKeyUp(time);
4867 }
4868
4869 private void finishTracking(long time) {
4870 if (mActivePointerId >= 0) {
4871 mActivePointerId = -1;
4872 mVelocityTracker.recycle();
4873 mVelocityTracker = null;
4874 }
4875 }
4876
4877 private void consumeAccumulatedMovement(long time, int metaState) {
4878 final float absX = Math.abs(mAccumulatedX);
4879 final float absY = Math.abs(mAccumulatedY);
4880 if (absX >= absY) {
4881 if (absX >= mConfigTickDistance) {
4882 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4883 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4884 mAccumulatedY = 0;
4885 mConsumedMovement = true;
4886 }
4887 } else {
4888 if (absY >= mConfigTickDistance) {
4889 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4890 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4891 mAccumulatedX = 0;
4892 mConsumedMovement = true;
4893 }
4894 }
4895 }
4896
4897 private float consumeAccumulatedMovement(long time, int metaState,
4898 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4899 while (accumulator <= -mConfigTickDistance) {
4900 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4901 accumulator += mConfigTickDistance;
4902 }
4903 while (accumulator >= mConfigTickDistance) {
4904 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4905 accumulator -= mConfigTickDistance;
4906 }
4907 return accumulator;
4908 }
4909
4910 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4911 if (mPendingKeyCode != keyCode) {
4912 sendKeyUp(time);
4913 mPendingKeyDownTime = time;
4914 mPendingKeyCode = keyCode;
4915 mPendingKeyRepeatCount = 0;
4916 } else {
4917 mPendingKeyRepeatCount += 1;
4918 }
4919 mPendingKeyMetaState = metaState;
4920
4921 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4922 // but it doesn't quite make sense when simulating the events in this way.
4923 if (LOCAL_DEBUG) {
4924 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4925 + ", repeatCount=" + mPendingKeyRepeatCount
4926 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4927 }
4928 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4929 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4930 mPendingKeyMetaState, mCurrentDeviceId,
4931 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4932 }
4933
4934 private void sendKeyUp(long time) {
4935 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4936 if (LOCAL_DEBUG) {
4937 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4938 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4939 }
4940 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4941 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4942 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4943 mCurrentSource));
4944 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4945 }
4946 }
4947
4948 private boolean startFling(long time, float vx, float vy) {
4949 if (LOCAL_DEBUG) {
4950 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4951 + ", min=" + mConfigMinFlingVelocity);
4952 }
4953
4954 // Flings must be oriented in the same direction as the preceding movements.
4955 switch (mPendingKeyCode) {
4956 case KeyEvent.KEYCODE_DPAD_LEFT:
4957 if (-vx >= mConfigMinFlingVelocity
4958 && Math.abs(vy) < mConfigMinFlingVelocity) {
4959 mFlingVelocity = -vx;
4960 break;
4961 }
4962 return false;
4963
4964 case KeyEvent.KEYCODE_DPAD_RIGHT:
4965 if (vx >= mConfigMinFlingVelocity
4966 && Math.abs(vy) < mConfigMinFlingVelocity) {
4967 mFlingVelocity = vx;
4968 break;
4969 }
4970 return false;
4971
4972 case KeyEvent.KEYCODE_DPAD_UP:
4973 if (-vy >= mConfigMinFlingVelocity
4974 && Math.abs(vx) < mConfigMinFlingVelocity) {
4975 mFlingVelocity = -vy;
4976 break;
4977 }
4978 return false;
4979
4980 case KeyEvent.KEYCODE_DPAD_DOWN:
4981 if (vy >= mConfigMinFlingVelocity
4982 && Math.abs(vx) < mConfigMinFlingVelocity) {
4983 mFlingVelocity = vy;
4984 break;
4985 }
4986 return false;
4987 }
4988
4989 // Post the first fling event.
4990 mFlinging = postFling(time);
4991 return mFlinging;
4992 }
4993
4994 private boolean postFling(long time) {
4995 // The idea here is to estimate the time when the pointer would have
4996 // traveled one tick distance unit given the current fling velocity.
4997 // This effect creates continuity of motion.
4998 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4999 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
5000 postAtTime(mFlingRunnable, time + delay);
5001 if (LOCAL_DEBUG) {
5002 Log.d(LOCAL_TAG, "Posted fling: velocity="
5003 + mFlingVelocity + ", delay=" + delay
5004 + ", keyCode=" + mPendingKeyCode);
5005 }
5006 return true;
5007 }
5008 return false;
5009 }
5010
5011 private void cancelFling() {
5012 if (mFlinging) {
5013 removeCallbacks(mFlingRunnable);
5014 mFlinging = false;
5015 }
5016 }
5017
5018 private final Runnable mFlingRunnable = new Runnable() {
5019 @Override
5020 public void run() {
5021 final long time = SystemClock.uptimeMillis();
5022 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
5023 mFlingVelocity *= FLING_TICK_DECAY;
5024 if (!postFling(time)) {
5025 mFlinging = false;
5026 finishKeys(time);
5027 }
5028 }
5029 };
Jeff Browncb1404e2011-01-15 18:14:15 -08005030 }
5031
Michael Wright899d7052014-04-23 17:23:39 -07005032 final class SyntheticKeyboardHandler {
5033 public void process(KeyEvent event) {
5034 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
5035 return;
5036 }
5037
5038 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5039 final int keyCode = event.getKeyCode();
5040 final int metaState = event.getMetaState();
5041
5042 // Check for fallback actions specified by the key character map.
5043 KeyCharacterMap.FallbackAction fallbackAction =
5044 kcm.getFallbackAction(keyCode, metaState);
5045 if (fallbackAction != null) {
5046 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5047 KeyEvent fallbackEvent = KeyEvent.obtain(
5048 event.getDownTime(), event.getEventTime(),
5049 event.getAction(), fallbackAction.keyCode,
5050 event.getRepeatCount(), fallbackAction.metaState,
5051 event.getDeviceId(), event.getScanCode(),
5052 flags, event.getSource(), null);
5053 fallbackAction.recycle();
5054 enqueueInputEvent(fallbackEvent);
5055 }
5056 }
5057 }
5058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005059 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005060 * Returns true if the key is used for keyboard navigation.
5061 * @param keyEvent The key event.
5062 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005063 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005064 private static boolean isNavigationKey(KeyEvent keyEvent) {
5065 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005066 case KeyEvent.KEYCODE_DPAD_LEFT:
5067 case KeyEvent.KEYCODE_DPAD_RIGHT:
5068 case KeyEvent.KEYCODE_DPAD_UP:
5069 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08005070 case KeyEvent.KEYCODE_DPAD_CENTER:
5071 case KeyEvent.KEYCODE_PAGE_UP:
5072 case KeyEvent.KEYCODE_PAGE_DOWN:
5073 case KeyEvent.KEYCODE_MOVE_HOME:
5074 case KeyEvent.KEYCODE_MOVE_END:
5075 case KeyEvent.KEYCODE_TAB:
5076 case KeyEvent.KEYCODE_SPACE:
5077 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 return true;
5079 }
5080 return false;
5081 }
5082
5083 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005084 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005085 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08005086 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005087 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005088 private static boolean isTypingKey(KeyEvent keyEvent) {
5089 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005090 }
5091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005092 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005093 * 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 -08005094 * @param event The key event.
5095 * @return Whether this key event should be consumed (meaning the act of
5096 * leaving touch mode alone is considered the event).
5097 */
5098 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08005099 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005100 if (!mAttachInfo.mInTouchMode) {
5101 return false;
5102 }
5103
Jeff Brown4e6319b2010-12-13 10:36:51 -08005104 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
5105 final int action = event.getAction();
5106 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005107 return false;
5108 }
5109
Jeff Brown4e6319b2010-12-13 10:36:51 -08005110 // Don't leave touch mode if the IME told us not to.
5111 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
5112 return false;
5113 }
5114
5115 // If the key can be used for keyboard navigation then leave touch mode
5116 // and select a focused view if needed (in ensureTouchMode).
5117 // When a new focused view is selected, we consume the navigation key because
5118 // navigation doesn't make much sense unless a view already has focus so
5119 // the key's purpose is to set focus.
5120 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005121 return ensureTouchMode(false);
5122 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08005123
5124 // If the key can be used for typing then leave touch mode
5125 // and select a focused view if needed (in ensureTouchMode).
5126 // Always allow the view to process the typing key.
5127 if (isTypingKey(event)) {
5128 ensureTouchMode(false);
5129 return false;
5130 }
5131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005132 return false;
5133 }
5134
Christopher Tatea53146c2010-09-07 11:57:52 -07005135 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08005136 void setLocalDragState(Object obj) {
5137 mLocalDragState = obj;
5138 }
5139
Christopher Tatea53146c2010-09-07 11:57:52 -07005140 private void handleDragEvent(DragEvent event) {
5141 // From the root, only drag start/end/location are dispatched. entered/exited
5142 // are determined and dispatched by the viewgroup hierarchy, who then report
5143 // that back here for ultimate reporting back to the framework.
5144 if (mView != null && mAdded) {
5145 final int what = event.mAction;
5146
5147 if (what == DragEvent.ACTION_DRAG_EXITED) {
5148 // A direct EXITED event means that the window manager knows we've just crossed
5149 // a window boundary, so the current drag target within this one must have
5150 // just been exited. Send it the usual notifications and then we're done
5151 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07005152 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005153 } else {
5154 // Cache the drag description when the operation starts, then fill it in
5155 // on subsequent calls as a convenience
5156 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005157 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005158 mDragDescription = event.mClipDescription;
5159 } else {
5160 event.mClipDescription = mDragDescription;
5161 }
5162
5163 // For events with a [screen] location, translate into window coordinates
5164 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5165 mDragPoint.set(event.mX, event.mY);
5166 if (mTranslator != null) {
5167 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5168 }
5169
5170 if (mCurScrollY != 0) {
5171 mDragPoint.offset(0, mCurScrollY);
5172 }
5173
5174 event.mX = mDragPoint.x;
5175 event.mY = mDragPoint.y;
5176 }
5177
5178 // Remember who the current drag target is pre-dispatch
5179 final View prevDragView = mCurrentDragView;
5180
5181 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005182 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005183
5184 // If we changed apparent drag target, tell the OS about it
5185 if (prevDragView != mCurrentDragView) {
5186 try {
5187 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005188 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005189 }
5190 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005191 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005192 }
5193 } catch (RemoteException e) {
5194 Slog.e(TAG, "Unable to note drag target change");
5195 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005196 }
Chris Tated4533f12010-10-19 15:15:08 -07005197
Christopher Tate407b4e92010-11-30 17:14:08 -08005198 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005199 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005200 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005201 try {
5202 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005203 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005204 } catch (RemoteException e) {
5205 Log.e(TAG, "Unable to report drop result");
5206 }
5207 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005208
5209 // When the drag operation ends, release any local state object
5210 // that may have been in use
5211 if (what == DragEvent.ACTION_DRAG_ENDED) {
5212 setLocalDragState(null);
5213 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005214 }
5215 }
5216 event.recycle();
5217 }
5218
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005219 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5220 if (mSeq != args.seq) {
5221 // The sequence has changed, so we need to update our value and make
5222 // sure to do a traversal afterward so the window manager is given our
5223 // most recent data.
5224 mSeq = args.seq;
5225 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005226 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005227 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005228 if (mView == null) return;
5229 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005230 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005231 }
Chris Craikd36a81f2014-07-17 10:16:51 -07005232
5233 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5234 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5235 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5236 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07005237 }
Joe Onorato664644d2011-01-23 17:53:23 -08005238 }
5239
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07005240 public void handleDispatchWindowAnimationStarted(int remainingFrameCount) {
Jorim Jaggic5af4f82015-07-01 17:16:27 -07005241 if (!mDrawDuringWindowsAnimating && remainingFrameCount != -1) {
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07005242 mRemainingFrameCount = remainingFrameCount;
5243 mWindowsAnimating = true;
5244 }
5245 }
5246
5247 public void handleDispatchWindowAnimationStopped() {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005248 if (mWindowsAnimating) {
5249 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07005250 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005251 scheduleTraversals();
5252 }
5253 }
5254 }
5255
Craig Mautner9c795042014-10-28 19:59:59 -07005256 public void handleDispatchWindowShown() {
5257 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
5258 }
5259
Christopher Tate2c095f32010-10-04 14:13:40 -07005260 public void getLastTouchPoint(Point outLocation) {
5261 outLocation.x = (int) mLastTouchPoint.x;
5262 outLocation.y = (int) mLastTouchPoint.y;
5263 }
5264
Chris Tate9d1ab882010-11-02 15:55:39 -07005265 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005266 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005267 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005268 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005269 }
5270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005271 private AudioManager getAudioManager() {
5272 if (mView == null) {
5273 throw new IllegalStateException("getAudioManager called when there is no mView");
5274 }
5275 if (mAudioManager == null) {
5276 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5277 }
5278 return mAudioManager;
5279 }
5280
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005281 public AccessibilityInteractionController getAccessibilityInteractionController() {
5282 if (mView == null) {
5283 throw new IllegalStateException("getAccessibilityInteractionController"
5284 + " called when there is no mView");
5285 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005286 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005287 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005288 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005289 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005290 }
5291
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005292 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5293 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005294
5295 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005296 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005297 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005298 restore = true;
5299 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005300 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005301 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005302 if (params != null) {
5303 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005304 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005305 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005306 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005307 if (params != null && mOrigWindowType != params.type) {
5308 // For compatibility with old apps, don't crash here.
Michael Wright5bd69e62015-05-14 14:48:08 +01005309 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Dianne Hackborn180c4842011-09-13 12:39:25 -07005310 Slog.w(TAG, "Window type can not be changed after "
5311 + "the window is added; ignoring change of " + mView);
5312 params.type = mOrigWindowType;
5313 }
5314 }
Jeff Brown98365d72012-08-19 20:30:52 -07005315 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005316 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005317 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5318 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005319 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005320 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005321 mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005322 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005323 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005324 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005325 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005326
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005327 if (mTranslator != null) {
5328 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005329 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005330 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5331 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07005332 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005333 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005334 return relayoutResult;
5335 }
Romain Guy8506ab42009-06-11 17:35:47 -07005336
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005337 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005338 * {@inheritDoc}
5339 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005340 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005341 public void playSoundEffect(int effectId) {
5342 checkThread();
5343
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005344 try {
5345 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005346
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005347 switch (effectId) {
5348 case SoundEffectConstants.CLICK:
5349 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5350 return;
5351 case SoundEffectConstants.NAVIGATION_DOWN:
5352 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5353 return;
5354 case SoundEffectConstants.NAVIGATION_LEFT:
5355 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5356 return;
5357 case SoundEffectConstants.NAVIGATION_RIGHT:
5358 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5359 return;
5360 case SoundEffectConstants.NAVIGATION_UP:
5361 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5362 return;
5363 default:
5364 throw new IllegalArgumentException("unknown effect id " + effectId +
5365 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5366 }
5367 } catch (IllegalStateException e) {
5368 // Exception thrown by getAudioManager() when mView is null
5369 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5370 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005371 }
5372 }
5373
5374 /**
5375 * {@inheritDoc}
5376 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005377 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005378 public boolean performHapticFeedback(int effectId, boolean always) {
5379 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005380 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005381 } catch (RemoteException e) {
5382 return false;
5383 }
5384 }
5385
5386 /**
5387 * {@inheritDoc}
5388 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005389 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005390 public View focusSearch(View focused, int direction) {
5391 checkThread();
5392 if (!(mView instanceof ViewGroup)) {
5393 return null;
5394 }
5395 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5396 }
5397
5398 public void debug() {
5399 mView.debug();
5400 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005401
Jeff Brown5182c782013-10-15 20:31:52 -07005402 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5403 String innerPrefix = prefix + " ";
5404 writer.print(prefix); writer.println("ViewRoot:");
5405 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5406 writer.print(" mRemoved="); writer.println(mRemoved);
5407 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5408 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08005409 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
5410 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07005411 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5412 writer.println(mPendingInputEventCount);
5413 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5414 writer.println(mProcessInputEventsScheduled);
5415 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5416 writer.print(mTraversalScheduled);
5417 if (mTraversalScheduled) {
5418 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5419 } else {
5420 writer.println();
5421 }
5422 mFirstInputStage.dump(innerPrefix, writer);
5423
5424 mChoreographer.dump(prefix, writer);
5425
5426 writer.print(prefix); writer.println("View Hierarchy:");
5427 dumpViewHierarchy(innerPrefix, writer, mView);
5428 }
5429
5430 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5431 writer.print(prefix);
5432 if (view == null) {
5433 writer.println("null");
5434 return;
5435 }
5436 writer.println(view.toString());
5437 if (!(view instanceof ViewGroup)) {
5438 return;
5439 }
5440 ViewGroup grp = (ViewGroup)view;
5441 final int N = grp.getChildCount();
5442 if (N <= 0) {
5443 return;
5444 }
5445 prefix = prefix + " ";
5446 for (int i=0; i<N; i++) {
5447 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5448 }
5449 }
5450
Romain Guy211370f2012-02-01 16:10:55 -08005451 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005452 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005453 if (mView != null) {
5454 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005455 }
5456 }
5457
Romain Guya998dff2012-03-23 18:58:36 -07005458 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07005459 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07005460 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07005461 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07005462 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07005463 }
5464
5465 if (view instanceof ViewGroup) {
5466 ViewGroup group = (ViewGroup) view;
5467
5468 int count = group.getChildCount();
5469 for (int i = 0; i < count; i++) {
5470 getGfxInfo(group.getChildAt(i), info);
5471 }
5472 }
5473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474
Craig Mautner8f303ad2013-06-14 11:32:22 -07005475 /**
5476 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5477 * @return True, request has been queued. False, request has been completed.
5478 */
5479 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005480 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5481 // done by dispatchDetachedFromWindow will cause havoc on return.
5482 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005483 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005484 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005485 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005486
5487 if (!mIsDrawing) {
5488 destroyHardwareRenderer();
5489 } else {
5490 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5491 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5492 }
5493 mHandler.sendEmptyMessage(MSG_DIE);
5494 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005495 }
5496
5497 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005498 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005499 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005500 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005501 if (mRemoved) {
5502 return;
5503 }
5504 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005505 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005506 dispatchDetachedFromWindow();
5507 }
5508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005509 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07005510 destroyHardwareRenderer();
5511
Romain Guyedbca122012-04-04 18:25:53 -07005512 if (mView != null) {
5513 int viewVisibility = mView.getVisibility();
5514 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5515 if (mWindowAttributesChanged || viewVisibilityChanged) {
5516 // If layout params have been changed, first give them
5517 // to the window manager to make sure it has the correct
5518 // animation info.
5519 try {
5520 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005521 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5522 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005523 }
5524 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005526 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005527
Romain Guyedbca122012-04-04 18:25:53 -07005528 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005530 }
Romain Guyedbca122012-04-04 18:25:53 -07005531
5532 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005534 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005535 }
5536
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005537 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005538 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5539 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005540 }
5541
Dianne Hackborna53de062012-05-08 18:53:51 -07005542 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005543 mHandler.post(new Runnable() {
5544 @Override
5545 public void run() {
5546 // Profiling
5547 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5548 profileRendering(mAttachInfo.mHasWindowFocus);
5549
5550 // Hardware rendering
5551 if (mAttachInfo.mHardwareRenderer != null) {
John Reckcec24ae2013-11-05 13:27:50 -08005552 if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08005553 invalidate();
5554 }
5555 }
5556
5557 // Layout debugging
5558 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5559 if (layout != mAttachInfo.mDebugLayout) {
5560 mAttachInfo.mDebugLayout = layout;
5561 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5562 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5563 }
5564 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005565 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005566 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005567 }
5568
Romain Guy29d89972010-09-22 16:10:57 -07005569 private void destroyHardwareRenderer() {
Chris Craikd36a81f2014-07-17 10:16:51 -07005570 HardwareRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07005571
5572 if (hardwareRenderer != null) {
5573 if (mView != null) {
5574 hardwareRenderer.destroyHardwareResources(mView);
5575 }
John Reckf47a5942014-06-30 16:20:04 -07005576 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07005577 hardwareRenderer.setRequested(false);
5578
Chris Craikd36a81f2014-07-17 10:16:51 -07005579 mAttachInfo.mHardwareRenderer = null;
5580 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005581 }
5582 }
5583
Jeff Browna175a5b2012-02-15 19:18:31 -08005584 public void dispatchFinishInputConnection(InputConnection connection) {
5585 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5586 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005587 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005588
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005589 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005590 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
5591 Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005592 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5593 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005594 + " visibleInsets=" + visibleInsets.toShortString()
5595 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005596 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005597 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005598 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005599 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005600 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005601 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005602 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005603 SomeArgs args = SomeArgs.obtain();
5604 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5605 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5606 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5607 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5608 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005609 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07005610 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005611 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005612 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005613 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005614 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005615
Craig Mautner5702d4d2012-06-30 14:10:16 -07005616 public void dispatchMoved(int newX, int newY) {
5617 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5618 if (mTranslator != null) {
5619 PointF point = new PointF(newX, newY);
5620 mTranslator.translatePointInScreenToAppWindow(point);
5621 newX = (int) (point.x + 0.5);
5622 newY = (int) (point.y + 0.5);
5623 }
5624 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5625 mHandler.sendMessage(msg);
5626 }
5627
Jeff Brown4952dfd2011-11-30 19:23:22 -08005628 /**
5629 * Represents a pending input event that is waiting in a queue.
5630 *
5631 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005632 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005633 * one input event to the application at a time and waits for the application
5634 * to finish handling it before delivering the next one.
5635 *
5636 * However, because the application or IME can synthesize and inject multiple
5637 * key events at a time without going through the input dispatcher, we end up
5638 * needing a queue on the application's side.
5639 */
5640 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005641 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5642 public static final int FLAG_DEFERRED = 1 << 1;
5643 public static final int FLAG_FINISHED = 1 << 2;
5644 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5645 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07005646 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005647
5648 public QueuedInputEvent mNext;
5649
5650 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005651 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005652 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005653
5654 public boolean shouldSkipIme() {
5655 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5656 return true;
5657 }
5658 return mEvent instanceof MotionEvent
5659 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5660 }
Michael Wright899d7052014-04-23 17:23:39 -07005661
5662 public boolean shouldSendToSynthesizer() {
5663 if ((mFlags & FLAG_UNHANDLED) != 0) {
5664 return true;
5665 }
5666
5667 return false;
5668 }
Michael Wright06a79252014-05-05 17:45:29 -07005669
5670 @Override
5671 public String toString() {
5672 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
5673 boolean hasPrevious = false;
5674 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
5675 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
5676 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
5677 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
5678 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
5679 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
5680 if (!hasPrevious) {
5681 sb.append("0");
5682 }
5683 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
5684 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
5685 sb.append(", mEvent=" + mEvent + "}");
5686 return sb.toString();
5687 }
5688
5689 private boolean flagToString(String name, int flag,
5690 boolean hasPrevious, StringBuilder sb) {
5691 if ((mFlags & flag) != 0) {
5692 if (hasPrevious) {
5693 sb.append("|");
5694 }
5695 sb.append(name);
5696 return true;
5697 }
5698 return hasPrevious;
5699 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005700 }
5701
5702 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005703 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005704 QueuedInputEvent q = mQueuedInputEventPool;
5705 if (q != null) {
5706 mQueuedInputEventPoolSize -= 1;
5707 mQueuedInputEventPool = q.mNext;
5708 q.mNext = null;
5709 } else {
5710 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005711 }
5712
Jeff Brown4952dfd2011-11-30 19:23:22 -08005713 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005714 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005715 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005716 return q;
5717 }
5718
5719 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5720 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005721 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005722
5723 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5724 mQueuedInputEventPoolSize += 1;
5725 q.mNext = mQueuedInputEventPool;
5726 mQueuedInputEventPool = q;
5727 }
5728 }
5729
Jeff Brownf9261d22012-02-03 13:49:15 -08005730 void enqueueInputEvent(InputEvent event) {
5731 enqueueInputEvent(event, null, 0, false);
5732 }
5733
Jeff Brown4952dfd2011-11-30 19:23:22 -08005734 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005735 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01005736 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005737 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005738
Jeff Brown4952dfd2011-11-30 19:23:22 -08005739 // Always enqueue the input event in order, regardless of its time stamp.
5740 // We do this because the application or the IME may inject key events
5741 // in response to touch events and we want to ensure that the injected keys
5742 // are processed in the order they were received and we cannot trust that
5743 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005744 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005745 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005746 mPendingInputEventHead = q;
5747 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005748 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005749 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005750 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005751 }
Michael Wright95ae9422013-03-14 10:58:50 -07005752 mPendingInputEventCount += 1;
5753 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5754 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005755
Jeff Brownf9261d22012-02-03 13:49:15 -08005756 if (processImmediately) {
5757 doProcessInputEvents();
5758 } else {
5759 scheduleProcessInputEvents();
5760 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005761 }
5762
5763 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005764 if (!mProcessInputEventsScheduled) {
5765 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005766 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5767 msg.setAsynchronous(true);
5768 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005769 }
5770 }
5771
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005772 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005773 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005774 while (mPendingInputEventHead != null) {
5775 QueuedInputEvent q = mPendingInputEventHead;
5776 mPendingInputEventHead = q.mNext;
5777 if (mPendingInputEventHead == null) {
5778 mPendingInputEventTail = null;
5779 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005780 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005781
Michael Wright95ae9422013-03-14 10:58:50 -07005782 mPendingInputEventCount -= 1;
5783 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5784 mPendingInputEventCount);
5785
John Reckba6adf62015-02-19 14:36:50 -08005786 long eventTime = q.mEvent.getEventTimeNano();
5787 long oldestEventTime = eventTime;
5788 if (q.mEvent instanceof MotionEvent) {
5789 MotionEvent me = (MotionEvent)q.mEvent;
5790 if (me.getHistorySize() > 0) {
5791 oldestEventTime = me.getHistoricalEventTimeNano(0);
5792 }
5793 }
5794 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
5795
Jeff Brownf9e989d2013-04-04 23:04:03 -07005796 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005797 }
5798
5799 // We are done processing all input events that we can process right now
5800 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005801 if (mProcessInputEventsScheduled) {
5802 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005803 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005804 }
5805 }
5806
Jeff Brownf9e989d2013-04-04 23:04:03 -07005807 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005808 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
5809 q.mEvent.getSequenceNumber());
5810 if (mInputEventConsistencyVerifier != null) {
5811 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5812 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005813
Michael Wright899d7052014-04-23 17:23:39 -07005814 InputStage stage;
5815 if (q.shouldSendToSynthesizer()) {
5816 stage = mSyntheticInputStage;
5817 } else {
5818 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5819 }
5820
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005821 if (stage != null) {
5822 stage.deliver(q);
5823 } else {
5824 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005825 }
Michael Wrightbf020962013-03-28 17:27:50 -07005826 }
5827
Jeff Brownf9e989d2013-04-04 23:04:03 -07005828 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005829 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
5830 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08005831
Jeff Brown32cbc38552011-12-01 14:01:49 -08005832 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005833 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005834 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005835 } else {
5836 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005837 }
5838
5839 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005840 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005841
Michael Wright5bd69e62015-05-14 14:48:08 +01005842 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07005843 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01005844 MotionEvent motion = (MotionEvent) e;
5845 final int mask =
5846 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
5847 final int buttonState = motion.getButtonState();
5848 final int compatButtonState = (buttonState & mask) >> 4;
5849 if (compatButtonState != 0) {
5850 motion.setButtonState(buttonState | compatButtonState);
5851 }
5852 }
5853 }
5854
Jeff Brownf9e989d2013-04-04 23:04:03 -07005855 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005856 if (event instanceof KeyEvent) {
5857 final KeyEvent keyEvent = (KeyEvent)event;
5858 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5859 } else {
5860 final MotionEvent motionEvent = (MotionEvent)event;
5861 final int action = motionEvent.getAction();
5862 return action == MotionEvent.ACTION_UP
5863 || action == MotionEvent.ACTION_CANCEL
5864 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005865 }
5866 }
5867
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005868 void scheduleConsumeBatchedInput() {
5869 if (!mConsumeBatchedInputScheduled) {
5870 mConsumeBatchedInputScheduled = true;
5871 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5872 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005873 }
5874 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005875
5876 void unscheduleConsumeBatchedInput() {
5877 if (mConsumeBatchedInputScheduled) {
5878 mConsumeBatchedInputScheduled = false;
5879 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5880 mConsumedBatchedInputRunnable, null);
5881 }
5882 }
5883
Michael Wright9d744c72014-02-18 21:27:42 -08005884 void scheduleConsumeBatchedInputImmediately() {
5885 if (!mConsumeBatchedInputImmediatelyScheduled) {
5886 unscheduleConsumeBatchedInput();
5887 mConsumeBatchedInputImmediatelyScheduled = true;
5888 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
5889 }
5890 }
5891
Jeff Brown771526c2012-04-27 15:13:25 -07005892 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005893 if (mConsumeBatchedInputScheduled) {
5894 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005895 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08005896 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
5897 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07005898 // If we consumed a batch here, we want to go ahead and schedule the
5899 // consumption of batched input events on the next frame. Otherwise, we would
5900 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08005901 // things occurring in the process. If the frame time is -1, however, then
5902 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07005903 scheduleConsumeBatchedInput();
5904 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005905 }
Jeff Brown330314c2012-04-27 02:20:22 -07005906 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005907 }
5908 }
5909
5910 final class TraversalRunnable implements Runnable {
5911 @Override
5912 public void run() {
5913 doTraversal();
5914 }
5915 }
5916 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005917
Jeff Brown32cbc38552011-12-01 14:01:49 -08005918 final class WindowInputEventReceiver extends InputEventReceiver {
5919 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5920 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005921 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005922
5923 @Override
5924 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005925 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005926 }
Jeff Brown072ec962012-02-07 14:46:57 -08005927
5928 @Override
5929 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08005930 if (mUnbufferedInputDispatch) {
5931 super.onBatchedInputEventPending();
5932 } else {
5933 scheduleConsumeBatchedInput();
5934 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005935 }
5936
5937 @Override
5938 public void dispose() {
5939 unscheduleConsumeBatchedInput();
5940 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005941 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005942 }
5943 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005944
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005945 final class ConsumeBatchedInputRunnable implements Runnable {
5946 @Override
5947 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005948 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005949 }
5950 }
5951 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5952 new ConsumeBatchedInputRunnable();
5953 boolean mConsumeBatchedInputScheduled;
5954
Michael Wright9d744c72014-02-18 21:27:42 -08005955 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
5956 @Override
5957 public void run() {
5958 doConsumeBatchedInput(-1);
5959 }
5960 }
5961 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
5962 new ConsumeBatchedInputImmediatelyRunnable();
5963 boolean mConsumeBatchedInputImmediatelyScheduled;
5964
Jeff Brown6cb7b462012-03-05 13:21:17 -08005965 final class InvalidateOnAnimationRunnable implements Runnable {
5966 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005967 private final ArrayList<View> mViews = new ArrayList<View>();
5968 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08005969 new ArrayList<AttachInfo.InvalidateInfo>();
5970 private View[] mTempViews;
5971 private AttachInfo.InvalidateInfo[] mTempViewRects;
5972
5973 public void addView(View view) {
5974 synchronized (this) {
5975 mViews.add(view);
5976 postIfNeededLocked();
5977 }
5978 }
5979
5980 public void addViewRect(AttachInfo.InvalidateInfo info) {
5981 synchronized (this) {
5982 mViewRects.add(info);
5983 postIfNeededLocked();
5984 }
5985 }
5986
5987 public void removeView(View view) {
5988 synchronized (this) {
5989 mViews.remove(view);
5990
5991 for (int i = mViewRects.size(); i-- > 0; ) {
5992 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5993 if (info.target == view) {
5994 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005995 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005996 }
5997 }
5998
5999 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006000 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006001 mPosted = false;
6002 }
6003 }
6004 }
6005
6006 @Override
6007 public void run() {
6008 final int viewCount;
6009 final int viewRectCount;
6010 synchronized (this) {
6011 mPosted = false;
6012
6013 viewCount = mViews.size();
6014 if (viewCount != 0) {
6015 mTempViews = mViews.toArray(mTempViews != null
6016 ? mTempViews : new View[viewCount]);
6017 mViews.clear();
6018 }
6019
6020 viewRectCount = mViewRects.size();
6021 if (viewRectCount != 0) {
6022 mTempViewRects = mViewRects.toArray(mTempViewRects != null
6023 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
6024 mViewRects.clear();
6025 }
6026 }
6027
6028 for (int i = 0; i < viewCount; i++) {
6029 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07006030 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08006031 }
6032
6033 for (int i = 0; i < viewRectCount; i++) {
6034 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
6035 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006036 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006037 }
6038 }
6039
6040 private void postIfNeededLocked() {
6041 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006042 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006043 mPosted = true;
6044 }
6045 }
6046 }
6047 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
6048 new InvalidateOnAnimationRunnable();
6049
Jeff Browna175a5b2012-02-15 19:18:31 -08006050 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
6051 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
6052 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6053 }
6054
Jeff Browna175a5b2012-02-15 19:18:31 -08006055 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
6056 long delayMilliseconds) {
6057 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
6058 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6059 }
6060
Jeff Brown6cb7b462012-03-05 13:21:17 -08006061 public void dispatchInvalidateOnAnimation(View view) {
6062 mInvalidateOnAnimationRunnable.addView(view);
6063 }
6064
6065 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
6066 mInvalidateOnAnimationRunnable.addViewRect(info);
6067 }
6068
6069 public void cancelInvalidate(View view) {
6070 mHandler.removeMessages(MSG_INVALIDATE, view);
6071 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
6072 // them to the pool
6073 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
6074 mInvalidateOnAnimationRunnable.removeView(view);
6075 }
6076
keunyoung30f420f2013-08-02 14:23:10 -07006077 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07006078 dispatchInputEvent(event, null);
6079 }
6080
6081 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
6082 SomeArgs args = SomeArgs.obtain();
6083 args.arg1 = event;
6084 args.arg2 = receiver;
6085 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08006086 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006087 mHandler.sendMessage(msg);
6088 }
6089
Michael Wright899d7052014-04-23 17:23:39 -07006090 public void synthesizeInputEvent(InputEvent event) {
6091 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
6092 msg.setAsynchronous(true);
6093 mHandler.sendMessage(msg);
6094 }
6095
Jeff Browna175a5b2012-02-15 19:18:31 -08006096 public void dispatchKeyFromIme(KeyEvent event) {
6097 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08006098 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006099 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08006100 }
6101
Michael Wright899d7052014-04-23 17:23:39 -07006102 /**
6103 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
6104 *
6105 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
6106 * passes in.
6107 */
Michael Wright3da28342014-04-22 17:00:11 -07006108 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07006109 if (event instanceof MotionEvent) {
6110 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07006111 }
Michael Wright899d7052014-04-23 17:23:39 -07006112 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07006113 }
6114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006115 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006116 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006117 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006118 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006119 }
6120
6121 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08006122 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
6123 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006124 }
6125
6126 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
6127 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006128 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006129 msg.arg1 = hasFocus ? 1 : 0;
6130 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006131 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006132 }
6133
Craig Mautner9c795042014-10-28 19:59:59 -07006134 public void dispatchWindowShown() {
6135 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
6136 }
6137
Dianne Hackbornffa42482009-09-23 22:20:11 -07006138 public void dispatchCloseSystemDialogs(String reason) {
6139 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006140 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07006141 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08006142 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006143 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006144
6145 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07006146 final int what;
6147 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006148 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
6149 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07006150 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08006151 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07006152 }
Jeff Browna175a5b2012-02-15 19:18:31 -08006153 Message msg = mHandler.obtainMessage(what, event);
6154 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07006155 }
6156
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006157 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6158 int localValue, int localChanges) {
6159 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
6160 args.seq = seq;
6161 args.globalVisibility = globalVisibility;
6162 args.localValue = localValue;
6163 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08006164 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
6165 }
6166
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07006167 public void dispatchWindowAnimationStarted(int remainingFrameCount) {
6168 mHandler.obtainMessage(MSG_DISPATCH_WINDOW_ANIMATION_STARTED,
6169 remainingFrameCount, 0 /* unused */).sendToTarget();
6170 }
6171
6172 public void dispatchWindowAnimationStopped() {
6173 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_ANIMATION_STOPPED);
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006174 }
6175
Jeff Browna175a5b2012-02-15 19:18:31 -08006176 public void dispatchCheckFocus() {
6177 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
6178 // This will result in a call to checkFocus() below.
6179 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
6180 }
Joe Onorato664644d2011-01-23 17:53:23 -08006181 }
6182
svetoslavganov75986cf2009-05-14 22:28:01 -07006183 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006184 * Post a callback to send a
6185 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07006186 * This event is send at most once every
6187 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006188 */
Alan Viverette77e9a282013-09-12 17:16:09 -07006189 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006190 if (mSendWindowContentChangedAccessibilityEvent == null) {
6191 mSendWindowContentChangedAccessibilityEvent =
6192 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006193 }
Alan Viverette77e9a282013-09-12 17:16:09 -07006194 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006195 }
6196
6197 /**
6198 * Remove a posted callback to send a
6199 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
6200 */
6201 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006202 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006203 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006204 }
6205 }
6206
Igor Murashkina86ab6402013-08-30 12:58:36 -07006207 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006208 public boolean showContextMenuForChild(View originalView) {
6209 return false;
6210 }
6211
Igor Murashkina86ab6402013-08-30 12:58:36 -07006212 @Override
Adam Powell6e346362010-07-23 10:18:23 -07006213 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
6214 return null;
6215 }
6216
Igor Murashkina86ab6402013-08-30 12:58:36 -07006217 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00006218 public ActionMode startActionModeForChild(
6219 View originalView, ActionMode.Callback callback, int type) {
6220 return null;
6221 }
6222
6223 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006224 public void createContextMenu(ContextMenu menu) {
6225 }
6226
Igor Murashkina86ab6402013-08-30 12:58:36 -07006227 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006228 public void childDrawableStateChanged(View child) {
6229 }
6230
Igor Murashkina86ab6402013-08-30 12:58:36 -07006231 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006232 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07006233 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006234 return false;
6235 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006236 // Intercept accessibility focus events fired by virtual nodes to keep
6237 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006238 final int eventType = event.getEventType();
6239 switch (eventType) {
6240 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006241 final long sourceNodeId = event.getSourceNodeId();
6242 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6243 sourceNodeId);
6244 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6245 if (source != null) {
6246 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6247 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07006248 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
6249 sourceNodeId);
6250 final AccessibilityNodeInfo node;
6251 if (virtualNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6252 node = provider.createAccessibilityNodeInfo(
6253 AccessibilityNodeProvider.HOST_VIEW_ID);
6254 } else {
6255 node = provider.createAccessibilityNodeInfo(virtualNodeId);
6256 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006257 setAccessibilityFocus(source, node);
6258 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006259 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006260 } break;
6261 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006262 final long sourceNodeId = event.getSourceNodeId();
6263 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6264 sourceNodeId);
6265 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6266 if (source != null) {
6267 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6268 if (provider != null) {
6269 setAccessibilityFocus(null, null);
6270 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006271 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006272 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07006273
6274
6275 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07006276 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07006277 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006278 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006279 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006280 return true;
6281 }
6282
Alan Viverette34457f52015-03-25 13:09:20 -07006283 /**
6284 * Updates the focused virtual view, when necessary, in response to a
6285 * content changed event.
6286 * <p>
6287 * This is necessary to get updated bounds after a position change.
6288 *
6289 * @param event an accessibility event of type
6290 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
6291 */
6292 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006293 final View focusedHost = mAccessibilityFocusedHost;
6294 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
6295 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07006296 return;
6297 }
6298
Alan Viverette25acc7e2015-05-19 11:32:08 -07006299 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07006300 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006301 // Error state: virtual view with no provider. Clear focus.
6302 mAccessibilityFocusedHost = null;
6303 mAccessibilityFocusedVirtualView = null;
6304 focusedHost.clearAccessibilityFocusNoCallbacks();
Alan Viverette34457f52015-03-25 13:09:20 -07006305 return;
6306 }
6307
6308 // We only care about change types that may affect the bounds of the
6309 // focused virtual view.
6310 final int changes = event.getContentChangeTypes();
6311 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
6312 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
6313 return;
6314 }
6315
6316 final long eventSourceNodeId = event.getSourceNodeId();
6317 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
6318
6319 // Search up the tree for subtree containment.
6320 boolean hostInSubtree = false;
6321 View root = mAccessibilityFocusedHost;
6322 while (root != null && !hostInSubtree) {
6323 if (changedViewId == root.getAccessibilityViewId()) {
6324 hostInSubtree = true;
6325 } else {
6326 final ViewParent parent = root.getParent();
6327 if (parent instanceof View) {
6328 root = (View) parent;
6329 } else {
6330 root = null;
6331 }
6332 }
6333 }
6334
6335 // We care only about changes in subtrees containing the host view.
6336 if (!hostInSubtree) {
6337 return;
6338 }
6339
6340 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
6341 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
6342 if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6343 // TODO: Should we clear the focused virtual view?
6344 focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
6345 }
6346
6347 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006348 final Rect oldBounds = mTempRect;
6349 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07006350 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006351 if (mAccessibilityFocusedVirtualView == null) {
6352 // Error state: The node no longer exists. Clear focus.
6353 mAccessibilityFocusedHost = null;
6354 focusedHost.clearAccessibilityFocusNoCallbacks();
6355
6356 // This will probably fail, but try to keep the provider's internal
6357 // state consistent by clearing focus.
6358 provider.performAction(focusedChildId,
6359 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006360 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006361 } else {
6362 // The node was refreshed, invalidate bounds if necessary.
6363 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
6364 if (!oldBounds.equals(newBounds)) {
6365 oldBounds.union(newBounds);
6366 invalidateRectOnScreen(oldBounds);
6367 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006368 }
Alan Viverette34457f52015-03-25 13:09:20 -07006369 }
6370
Svetoslav Ganov42138042012-03-20 11:51:39 -07006371 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006372 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6373 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006374 }
6375
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006376 @Override
6377 public boolean canResolveLayoutDirection() {
6378 return true;
6379 }
6380
6381 @Override
6382 public boolean isLayoutDirectionResolved() {
6383 return true;
6384 }
6385
6386 @Override
6387 public int getLayoutDirection() {
6388 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6389 }
6390
6391 @Override
6392 public boolean canResolveTextDirection() {
6393 return true;
6394 }
6395
6396 @Override
6397 public boolean isTextDirectionResolved() {
6398 return true;
6399 }
6400
6401 @Override
6402 public int getTextDirection() {
6403 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6404 }
6405
6406 @Override
6407 public boolean canResolveTextAlignment() {
6408 return true;
6409 }
6410
6411 @Override
6412 public boolean isTextAlignmentResolved() {
6413 return true;
6414 }
6415
6416 @Override
6417 public int getTextAlignment() {
6418 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6419 }
6420
Svetoslav Ganov42138042012-03-20 11:51:39 -07006421 private View getCommonPredecessor(View first, View second) {
Chris Craikd36a81f2014-07-17 10:16:51 -07006422 if (mTempHashSet == null) {
6423 mTempHashSet = new HashSet<View>();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006424 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006425 HashSet<View> seen = mTempHashSet;
6426 seen.clear();
6427 View firstCurrent = first;
6428 while (firstCurrent != null) {
6429 seen.add(firstCurrent);
6430 ViewParent firstCurrentParent = firstCurrent.mParent;
6431 if (firstCurrentParent instanceof View) {
6432 firstCurrent = (View) firstCurrentParent;
6433 } else {
6434 firstCurrent = null;
6435 }
6436 }
6437 View secondCurrent = second;
6438 while (secondCurrent != null) {
6439 if (seen.contains(secondCurrent)) {
6440 seen.clear();
6441 return secondCurrent;
6442 }
6443 ViewParent secondCurrentParent = secondCurrent.mParent;
6444 if (secondCurrentParent instanceof View) {
6445 secondCurrent = (View) secondCurrentParent;
6446 } else {
6447 secondCurrent = null;
6448 }
6449 }
6450 seen.clear();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006451 return null;
6452 }
6453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006454 void checkThread() {
6455 if (mThread != Thread.currentThread()) {
6456 throw new CalledFromWrongThreadException(
6457 "Only the original thread that created a view hierarchy can touch its views.");
6458 }
6459 }
6460
Igor Murashkina86ab6402013-08-30 12:58:36 -07006461 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006462 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006463 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006464 }
6465
Igor Murashkina86ab6402013-08-30 12:58:36 -07006466 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006467 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
6468 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
6469 if (rectangle != null) {
6470 mTempRect.set(rectangle);
6471 mTempRect.offset(0, -mCurScrollY);
6472 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6473 try {
Svetoslavf7174e82014-06-12 11:29:35 -07006474 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006475 } catch (RemoteException re) {
6476 /* ignore */
6477 }
6478 }
6479 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006480 }
Romain Guy8506ab42009-06-11 17:35:47 -07006481
Igor Murashkina86ab6402013-08-30 12:58:36 -07006482 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006483 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6484 // Do nothing.
6485 }
6486
Adam Powell10ba2772014-04-15 09:46:51 -07006487 @Override
6488 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6489 return false;
6490 }
6491
6492 @Override
6493 public void onStopNestedScroll(View target) {
6494 }
6495
6496 @Override
6497 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
6498 }
6499
6500 @Override
6501 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6502 int dxUnconsumed, int dyUnconsumed) {
6503 }
6504
6505 @Override
6506 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6507 }
6508
6509 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006510 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006511 return false;
6512 }
6513
Adam Powellb72be592014-07-16 21:41:31 -07006514 @Override
6515 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6516 return false;
6517 }
6518
Adam Powellb6ab0982015-01-07 17:00:12 -08006519 @Override
6520 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
6521 return false;
6522 }
6523
Jorim Jaggib774e552015-08-24 14:52:45 -07006524 /**
6525 * Force the window to report its next draw.
6526 * <p>
6527 * This method is only supposed to be used to speed up the interaction from SystemUI and window
6528 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
6529 * unless you fully understand this interaction.
6530 * @hide
6531 */
6532 public void setReportNextDraw() {
6533 mReportNextDraw = true;
6534 invalidate();
6535 }
6536
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006537 void changeCanvasOpacity(boolean opaque) {
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006538 Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
John Reck63a06672014-05-07 13:45:54 -07006539 if (mAttachInfo.mHardwareRenderer != null) {
6540 mAttachInfo.mHardwareRenderer.setOpaque(opaque);
6541 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006542 }
6543
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006544 class TakenSurfaceHolder extends BaseSurfaceHolder {
6545 @Override
6546 public boolean onAllowLockCanvas() {
6547 return mDrawingAllowed;
6548 }
6549
6550 @Override
6551 public void onRelayoutContainer() {
6552 // Not currently interesting -- from changing between fixed and layout size.
6553 }
6554
Igor Murashkina86ab6402013-08-30 12:58:36 -07006555 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006556 public void setFormat(int format) {
6557 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6558 }
6559
Igor Murashkina86ab6402013-08-30 12:58:36 -07006560 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006561 public void setType(int type) {
6562 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6563 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006564
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006565 @Override
6566 public void onUpdateSurface() {
6567 // We take care of format and type changes on our own.
6568 throw new IllegalStateException("Shouldn't be here");
6569 }
6570
Igor Murashkina86ab6402013-08-30 12:58:36 -07006571 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006572 public boolean isCreating() {
6573 return mIsCreating;
6574 }
6575
6576 @Override
6577 public void setFixedSize(int width, int height) {
6578 throw new UnsupportedOperationException(
6579 "Currently only support sizing from layout");
6580 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006581
6582 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006583 public void setKeepScreenOn(boolean screenOn) {
6584 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6585 }
6586 }
Romain Guy8506ab42009-06-11 17:35:47 -07006587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006588 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006589 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006590 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006591
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006592 W(ViewRootImpl viewAncestor) {
6593 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006594 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006595 }
6596
Igor Murashkina86ab6402013-08-30 12:58:36 -07006597 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006598 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006599 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Adrian Roosfa104232014-06-20 16:10:14 -07006600 Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006601 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006602 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006603 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006604 visibleInsets, stableInsets, outsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006605 }
6606 }
6607
Craig Mautner5702d4d2012-06-30 14:10:16 -07006608 @Override
6609 public void moved(int newX, int newY) {
6610 final ViewRootImpl viewAncestor = mViewAncestor.get();
6611 if (viewAncestor != null) {
6612 viewAncestor.dispatchMoved(newX, newY);
6613 }
6614 }
6615
Igor Murashkina86ab6402013-08-30 12:58:36 -07006616 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006617 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006618 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006619 if (viewAncestor != null) {
6620 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006621 }
6622 }
6623
Igor Murashkina86ab6402013-08-30 12:58:36 -07006624 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006625 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006626 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006627 if (viewAncestor != null) {
6628 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006629 }
6630 }
6631
Igor Murashkina86ab6402013-08-30 12:58:36 -07006632 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006633 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006634 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006635 if (viewAncestor != null) {
6636 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637 }
6638 }
6639
6640 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006641 try {
6642 return ActivityManagerNative.getDefault().checkPermission(
6643 permission, Binder.getCallingPid(), Binder.getCallingUid());
6644 } catch (RemoteException e) {
6645 return PackageManager.PERMISSION_DENIED;
6646 }
6647 }
6648
Igor Murashkina86ab6402013-08-30 12:58:36 -07006649 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006650 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006651 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006652 if (viewAncestor != null) {
6653 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006654 if (view != null) {
6655 if (checkCallingPermission(Manifest.permission.DUMP) !=
6656 PackageManager.PERMISSION_GRANTED) {
6657 throw new SecurityException("Insufficient permissions to invoke"
6658 + " executeCommand() from pid=" + Binder.getCallingPid()
6659 + ", uid=" + Binder.getCallingUid());
6660 }
6661
6662 OutputStream clientStream = null;
6663 try {
6664 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6665 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6666 } catch (IOException e) {
6667 e.printStackTrace();
6668 } finally {
6669 if (clientStream != null) {
6670 try {
6671 clientStream.close();
6672 } catch (IOException e) {
6673 e.printStackTrace();
6674 }
6675 }
6676 }
6677 }
6678 }
6679 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006680
6681 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006682 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006683 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006684 if (viewAncestor != null) {
6685 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006686 }
6687 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006688
6689 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006690 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6691 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006692 if (sync) {
6693 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006694 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006695 } catch (RemoteException e) {
6696 }
6697 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006698 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006699
Igor Murashkina86ab6402013-08-30 12:58:36 -07006700 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07006701 public void dispatchWallpaperCommand(String action, int x, int y,
6702 int z, Bundle extras, boolean sync) {
6703 if (sync) {
6704 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006705 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006706 } catch (RemoteException e) {
6707 }
6708 }
6709 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006710
6711 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006712 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07006713 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006714 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006715 if (viewAncestor != null) {
6716 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006717 }
6718 }
Joe Onorato664644d2011-01-23 17:53:23 -08006719
Igor Murashkina86ab6402013-08-30 12:58:36 -07006720 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006721 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6722 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006723 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006724 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006725 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6726 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006727 }
6728 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006729
Igor Murashkina86ab6402013-08-30 12:58:36 -07006730 @Override
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07006731 public void onAnimationStarted(int remainingFrameCount) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006732 final ViewRootImpl viewAncestor = mViewAncestor.get();
6733 if (viewAncestor != null) {
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07006734 viewAncestor.dispatchWindowAnimationStarted(remainingFrameCount);
6735 }
6736 }
6737
6738 @Override
6739 public void onAnimationStopped() {
6740 final ViewRootImpl viewAncestor = mViewAncestor.get();
6741 if (viewAncestor != null) {
6742 viewAncestor.dispatchWindowAnimationStopped();
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006743 }
6744 }
Craig Mautner9c795042014-10-28 19:59:59 -07006745
6746 @Override
6747 public void dispatchWindowShown() {
6748 final ViewRootImpl viewAncestor = mViewAncestor.get();
6749 if (viewAncestor != null) {
6750 viewAncestor.dispatchWindowShown();
6751 }
6752 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006753 }
6754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006755 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6756 public CalledFromWrongThreadException(String msg) {
6757 super(msg);
6758 }
6759 }
6760
Alan Viverettebea0c7da2015-09-01 16:00:20 -04006761 static HandlerActionQueue getRunQueue() {
6762 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006763 if (rq != null) {
6764 return rq;
6765 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04006766 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006767 sRunQueues.set(rq);
6768 return rq;
6769 }
Romain Guy8506ab42009-06-11 17:35:47 -07006770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006771 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006772 * Class for managing the accessibility interaction connection
6773 * based on the global accessibility state.
6774 */
6775 final class AccessibilityInteractionConnectionManager
6776 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07006777 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006778 public void onAccessibilityStateChanged(boolean enabled) {
6779 if (enabled) {
6780 ensureConnection();
Chris Craikcce47eb2014-07-16 15:12:15 -07006781 if (mAttachInfo.mHasWindowFocus) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006782 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6783 View focusedView = mView.findFocus();
6784 if (focusedView != null && focusedView != mView) {
6785 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6786 }
6787 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006788 } else {
6789 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006790 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006791 }
6792 }
6793
6794 public void ensureConnection() {
Chris Craikcce47eb2014-07-16 15:12:15 -07006795 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08006796 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07006797 if (!registered) {
6798 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006799 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6800 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006801 }
6802 }
6803
6804 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006805 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08006806 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006807 if (registered) {
Svetoslav8e3feb12014-02-24 13:46:47 -08006808 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006809 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6810 }
6811 }
6812 }
6813
Chris Craikcce47eb2014-07-16 15:12:15 -07006814 final class HighContrastTextManager implements HighTextContrastChangeListener {
6815 HighContrastTextManager() {
6816 mAttachInfo.mHighContrastText = mAccessibilityManager.isHighTextContrastEnabled();
6817 }
6818 @Override
6819 public void onHighTextContrastStateChanged(boolean enabled) {
6820 mAttachInfo.mHighContrastText = enabled;
6821
6822 // Destroy Displaylists so they can be recreated with high contrast recordings
6823 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07006824
6825 // Schedule redraw, which will rerecord + redraw all text
6826 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07006827 }
6828 }
6829
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006830 /**
6831 * This class is an interface this ViewAncestor provides to the
6832 * AccessibilityManagerService to the latter can interact with
6833 * the view hierarchy in this ViewAncestor.
6834 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006835 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006836 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006837 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006838
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006839 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6840 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006841 }
6842
Svetoslav Ganov42138042012-03-20 11:51:39 -07006843 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006844 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006845 Region interactiveRegion, int interactionId,
6846 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006847 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006848 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6849 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006850 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006851 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006852 interactiveRegion, interactionId, callback, flags, interrogatingPid,
6853 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006854 } else {
6855 // We cannot make the call and notify the caller so it does not wait.
6856 try {
6857 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6858 } catch (RemoteException re) {
6859 /* best effort - ignore */
6860 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006861 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006862 }
6863
Svetoslav Ganov42138042012-03-20 11:51:39 -07006864 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006865 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006866 Bundle arguments, int interactionId,
6867 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07006868 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006869 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6870 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006871 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006872 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07006873 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006874 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006875 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006876 try {
6877 callback.setPerformAccessibilityActionResult(false, interactionId);
6878 } catch (RemoteException re) {
6879 /* best effort - ignore */
6880 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006881 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006882 }
6883
Svetoslav Ganov42138042012-03-20 11:51:39 -07006884 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006885 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006886 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006887 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006888 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006889 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6890 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006891 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006892 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006893 viewId, interactiveRegion, interactionId, callback, flags,
6894 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006895 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006896 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006897 try {
6898 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6899 } catch (RemoteException re) {
6900 /* best effort - ignore */
6901 }
6902 }
6903 }
6904
Svetoslav Ganov42138042012-03-20 11:51:39 -07006905 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006906 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006907 Region interactiveRegion, int interactionId,
6908 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006909 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006910 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6911 if (viewRootImpl != null && viewRootImpl.mView != null) {
6912 viewRootImpl.getAccessibilityInteractionController()
6913 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006914 interactiveRegion, interactionId, callback, flags, interrogatingPid,
6915 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006916 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006917 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006918 try {
6919 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6920 } catch (RemoteException re) {
6921 /* best effort - ignore */
6922 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006923 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006924 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006925
Svetoslav Ganov42138042012-03-20 11:51:39 -07006926 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07006927 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
6928 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006929 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006930 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6931 if (viewRootImpl != null && viewRootImpl.mView != null) {
6932 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07006933 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
6934 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6935 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006936 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006937 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006938 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006939 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006940 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006941 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006942 }
6943 }
6944 }
6945
Svetoslav Ganov42138042012-03-20 11:51:39 -07006946 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07006947 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
6948 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006949 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006950 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6951 if (viewRootImpl != null && viewRootImpl.mView != null) {
6952 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07006953 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
6954 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6955 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006956 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006957 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006958 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006959 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006960 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006961 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006962 }
6963 }
6964 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006965 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006966
Svetoslav Ganova0156172011-06-26 17:55:44 -07006967 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07006968 private int mChangeTypes = 0;
6969
Svetoslav Ganov42138042012-03-20 11:51:39 -07006970 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07006971 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006972
Igor Murashkina86ab6402013-08-30 12:58:36 -07006973 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006974 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07006975 // The accessibility may be turned off while we were waiting so check again.
6976 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6977 mLastEventTimeMillis = SystemClock.uptimeMillis();
6978 AccessibilityEvent event = AccessibilityEvent.obtain();
6979 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07006980 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07006981 mSource.sendAccessibilityEventUnchecked(event);
6982 } else {
6983 mLastEventTimeMillis = 0;
6984 }
6985 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07006986 mSource.resetSubtreeAccessibilityStateChanged();
6987 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07006988 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07006989 }
6990
Alan Viverette77e9a282013-09-12 17:16:09 -07006991 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006992 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006993 // If there is no common predecessor, then mSource points to
6994 // a removed view, hence in this case always prefer the source.
6995 View predecessor = getCommonPredecessor(mSource, source);
6996 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006997 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006998 return;
6999 }
7000 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007001 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007002 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
7003 final long minEventIntevalMillis =
7004 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
7005 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007006 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07007007 run();
7008 } else {
7009 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007010 }
7011 }
7012 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013}