blob: ccb85a671fb505ee326bec4289e0f4c35b251712 [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;
Dianne Hackbornc68c9132011-07-29 01:25:18 -070024import android.content.ComponentCallbacks2;
Romain Guy6b7bd242010-10-06 19:49:23 -070025import android.content.Context;
26import android.content.pm.PackageManager;
27import android.content.res.CompatibilityInfo;
28import android.content.res.Configuration;
29import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.graphics.Canvas;
Alan Viverettefed3f722013-11-14 14:48:20 -080031import android.graphics.Matrix;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080032import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070034import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070035import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070036import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Rect;
38import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070039import android.graphics.drawable.Drawable;
Romain Guy6b7bd242010-10-06 19:49:23 -070040import android.media.AudioManager;
41import android.os.Binder;
42import android.os.Bundle;
43import android.os.Debug;
44import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070045import android.os.Looper;
46import android.os.Message;
47import android.os.ParcelFileDescriptor;
Romain Guy7e4e5612012-03-05 14:37:29 -080048import android.os.PowerManager;
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;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080058import android.util.TypedValue;
Jeff Browna175a5b2012-02-15 19:18:31 -080059import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070061import android.view.accessibility.AccessibilityEvent;
62import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070063import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
64import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganov02107852011-10-03 17:06:56 -070065import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070066import android.view.accessibility.IAccessibilityInteractionConnection;
67import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080068import android.view.animation.AccelerateDecelerateInterpolator;
69import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.view.inputmethod.InputConnection;
71import android.view.inputmethod.InputMethodManager;
Igor Murashkina86ab6402013-08-30 12:58:36 -070072import android.view.Surface.OutOfResourcesException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070074
Svetoslav Ganov42138042012-03-20 11:51:39 -070075import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070076import com.android.internal.os.SomeArgs;
Joe Onorato86f67862010-11-05 18:57:34 -070077import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070078import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070079import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
Jeff Brown5182c782013-10-15 20:31:52 -070081import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import java.io.IOException;
83import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070084import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070085import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070087import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089/**
90 * The top of a view hierarchy, implementing the needed protocol between View
91 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070092 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 *
94 * {@hide}
95 */
Romain Guy812ccbe2010-06-01 14:07:24 -070096@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -080097public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -080098 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -070099 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700101 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 /** @noinspection PointlessBooleanExpression*/
103 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
104 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800105 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
107 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
108 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
109 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700110 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700111 private static final boolean DEBUG_FPS = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Romain Guy59a12ca2011-06-09 17:48:21 -0700113 /**
114 * Set this system property to true to force the view hierarchy to render
115 * at 60 Hz. This can be used to measure the potential framerate.
116 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700117 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Dan Morrille4d9a012013-03-28 18:10:43 -0700118 private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
Michael Chan53071d62009-05-13 17:29:48 -0700119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 /**
121 * Maximum time we allow the user to roll the trackball enough to generate
122 * a key event, before resetting the counters.
123 */
124 static final int MAX_TRACKBALL_DELAY = 250;
125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
127
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800128 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
129 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700130
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800131 static final ArrayList<ComponentCallbacks> sConfigCallbacks
132 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700133
Jeff Brownf9e989d2013-04-04 23:04:03 -0700134 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700135 final IWindowSession mWindowSession;
136 final Display mDisplay;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800137 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700140
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800141 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 final Thread mThread;
144
145 final WindowLeaked mLocation;
146
147 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
148
149 final W mWindow;
150
Dianne Hackborn180c4842011-09-13 12:39:25 -0700151 final int mTargetSdkVersion;
152
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700153 int mSeq;
154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700156
157 View mAccessibilityFocusedHost;
158 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 int mViewVisibility;
161 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700162 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Dianne Hackbornce418e62011-03-01 14:31:38 -0800164 // Set to true if the owner of this window is in the stopped state,
165 // so the window should no longer be active.
166 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700167
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700168 boolean mLastInCompatMode = false;
169
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700170 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700171 BaseSurfaceHolder mSurfaceHolder;
172 boolean mIsCreating;
173 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 final Region mTransparentRegion;
176 final Region mPreviousTransparentRegion;
177
178 int mWidth;
179 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800180 Rect mDirty;
181 final Rect mCurrentDirty = new Rect();
Romain Guybb93d552009-03-24 21:04:15 -0700182 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700183
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700184 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
186 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700187 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700188 InputQueue.Callback mInputQueueCallback;
189 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700190 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800191 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 final Rect mTempRect; // used in the transaction to not thrash the heap.
194 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
196 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800197 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700199 /** Set to true while in performTraversals for detecting when die(true) is called from internal
200 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
201 boolean mIsInTraversal;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700202 boolean mFitSystemWindowsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 boolean mLayoutRequested;
204 boolean mFirst;
205 boolean mReportNextDraw;
206 boolean mFullRedrawNeeded;
207 boolean mNewSurfaceNeeded;
208 boolean mHasHadWindowFocus;
209 boolean mLastWasImTarget;
Dianne Hackborn12d3a942012-04-27 14:16:30 -0700210 boolean mWindowsAnimating;
Michael Jurkaf42d90102013-05-08 18:00:04 +0200211 boolean mDrawDuringWindowsAnimating;
Romain Guy1f59e5c2012-05-06 14:11:16 -0700212 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700213 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700214 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800215 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800216
217 // Pool of queued input events.
218 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
219 private QueuedInputEvent mQueuedInputEventPool;
220 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800221
Michael Wrightc8a7e542013-03-20 17:58:33 -0700222 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700223 * Pending input events are input events waiting to be delivered to the input stages
224 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700225 */
226 QueuedInputEvent mPendingInputEventHead;
227 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700228 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800229 boolean mProcessInputEventsScheduled;
Michael Wright95ae9422013-03-14 10:58:50 -0700230 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700231
232 InputStage mFirstInputStage;
233 InputStage mFirstPostImeInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234
Michael Wright4567e402013-08-16 15:08:35 -0700235 boolean mFlipControllerFallbackKeys;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700238 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700241 // Surface can never be reassigned or cleared (use Surface.clear()).
242 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
244 boolean mAdded;
245 boolean mAddedTouchMode;
246
Craig Mautner48d0d182013-06-11 07:53:06 -0700247 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // These are accessed by multiple threads.
250 final Rect mWinFrame; // frame given by window manager.
251
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800252 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 final Rect mPendingVisibleInsets = new Rect();
254 final Rect mPendingContentInsets = new Rect();
255 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
256 = new ViewTreeObserver.InternalInsetsInfo();
257
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700258 final Rect mFitSystemWindowsInsets = new Rect();
259
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700260 final Configuration mLastConfiguration = new Configuration();
261 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 boolean mScrollMayChange;
264 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800265 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 int mScrollY;
267 int mCurScrollY;
268 Scroller mScroller;
John Reckcec24ae2013-11-05 13:27:50 -0800269// HardwareLayer mResizeBuffer;
270// long mResizeBufferStartTime;
271// int mResizeBufferDuration;
272// static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700273 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700274
Romain Guy8506ab42009-06-11 17:35:47 -0700275 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276
Christopher Tatea53146c2010-09-07 11:57:52 -0700277 /* Drag/drop */
278 ClipDescription mDragDescription;
279 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800280 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700281 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700282 final PointF mLastTouchPoint = new PointF();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700283
284 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800285 private Choreographer.FrameCallback mRenderProfiler;
286 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700287
Dan Morrille4d9a012013-03-28 18:10:43 -0700288 private boolean mMediaDisabled;
289
Chet Haase2f2022a2011-10-11 06:41:59 -0700290 // Variables to track frames per second, enabled via DEBUG_FPS flag
291 private long mFpsStartTime = -1;
292 private long mFpsPrevTime = -1;
293 private int mFpsNumFrames;
294
Romain Guyfbb93fa2012-12-03 18:50:35 -0800295 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 /**
298 * see {@link #playSoundEffect(int)}
299 */
300 AudioManager mAudioManager;
301
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700302 final AccessibilityManager mAccessibilityManager;
303
Gilles Debunne5ac84422011-10-19 09:35:58 -0700304 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700305
306 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
307
Svetoslav Ganova0156172011-06-26 17:55:44 -0700308 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700309
Svetoslav Ganov42138042012-03-20 11:51:39 -0700310 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800311
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700312 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700313 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700314
Chet Haase97140572012-09-13 14:56:47 -0700315 private boolean mInLayout = false;
316 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
317 boolean mHandlingLayoutInLayoutRequest = false;
318
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700319 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700320
Craig Mautner8f303ad2013-06-14 11:32:22 -0700321 /** Set to true once doDie() has been called. */
322 private boolean mRemoved;
323
Jeff Brown21bc5c92011-02-28 18:27:14 -0800324 /**
325 * Consistency verifier for debugging purposes.
326 */
327 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
328 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
329 new InputEventConsistencyVerifier(this, 0) : null;
330
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700331 static final class SystemUiVisibilityInfo {
332 int seq;
333 int globalVisibility;
334 int localValue;
335 int localChanges;
336 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700337
Jeff Brown98365d72012-08-19 20:30:52 -0700338 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700339 mContext = context;
340 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700341 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800342 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700343
Craig Mautner48d0d182013-06-11 07:53:06 -0700344 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 mThread = Thread.currentThread();
347 mLocation = new WindowLeaked(null);
348 mLocation.fillInStackTrace();
349 mWidth = -1;
350 mHeight = -1;
351 mDirty = new Rect();
352 mTempRect = new Rect();
353 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700355 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700356 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 mViewVisibility = View.GONE;
358 mTransparentRegion = new Region();
359 mPreviousTransparentRegion = new Region();
360 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700362 mAccessibilityManager = AccessibilityManager.getInstance(context);
363 mAccessibilityInteractionConnectionManager =
364 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800365 mAccessibilityManager.addAccessibilityStateChangeListener(
366 mAccessibilityInteractionConnectionManager);
Jeff Brown98365d72012-08-19 20:30:52 -0700367 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700369 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700370 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700371 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800372 mChoreographer = Choreographer.getInstance();
Michael Wright4567e402013-08-16 15:08:35 -0700373 mFlipControllerFallbackKeys =
374 context.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
Romain Guy7e4e5612012-03-05 14:37:29 -0800375
376 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
377 mAttachInfo.mScreenOn = powerManager.isScreenOn();
Dianne Hackborna53de062012-05-08 18:53:51 -0700378 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800381 public static void addFirstDrawHandler(Runnable callback) {
382 synchronized (sFirstDrawHandlers) {
383 if (!sFirstDrawComplete) {
384 sFirstDrawHandlers.add(callback);
385 }
386 }
387 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700388
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800389 public static void addConfigCallback(ComponentCallbacks callback) {
390 synchronized (sConfigCallbacks) {
391 sConfigCallbacks.add(callback);
392 }
393 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 // FIXME for perf testing only
396 private boolean mProfile = false;
397
398 /**
399 * Call this to profile the next traversal call.
400 * FIXME for perf testing only. Remove eventually
401 */
402 public void profile() {
403 mProfile = true;
404 }
405
406 /**
407 * Indicates whether we are in touch mode. Calling this method triggers an IPC
408 * call and should be avoided whenever possible.
409 *
410 * @return True, if the device is in touch mode, false otherwise.
411 *
412 * @hide
413 */
414 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700415 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
416 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700418 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 } catch (RemoteException e) {
420 }
421 }
422 return false;
423 }
424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 /**
426 * We have one child
427 */
Romain Guye4d01122010-06-16 18:44:05 -0700428 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 synchronized (this) {
430 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700431 mView = view;
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700432 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700433 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700434 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800435 if (mWindowAttributes.packageName == null) {
436 mWindowAttributes.packageName = mBasePackageName;
437 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700438 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700439 // Keep track of the actual window flags supplied by the client.
440 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700441
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700442 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700443
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700444 if (view instanceof RootViewSurfaceTaker) {
445 mSurfaceHolderCallback =
446 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
447 if (mSurfaceHolderCallback != null) {
448 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700449 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700450 }
451 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800452
Craig Mautner48d0d182013-06-11 07:53:06 -0700453 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700454 mTranslator = compatibilityInfo.getTranslator();
Craig Mautner48d0d182013-06-11 07:53:06 -0700455 mDisplayAdjustments.setActivityToken(attrs.token);
Romain Guy856d4e12011-10-14 15:47:55 -0700456
Romain Guy1aec9a22011-01-05 09:37:12 -0800457 // If the application owns the surface, don't enable hardware acceleration
458 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700459 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800460 }
461
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700462 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700463 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700464 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700465 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700466 attrs.backup();
467 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700468 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700469 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
470
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700471 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700472 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700473 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700474 }
475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 mSoftInputMode = attrs.softInputMode;
477 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700478 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700480 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700481 mAttachInfo.mApplicationScale =
482 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 if (panelParentView != null) {
484 mAttachInfo.mPanelParentWindowToken
485 = panelParentView.getApplicationWindowToken();
486 }
487 mAdded = true;
488 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 // Schedule the first layout -before- adding to the window
491 // manager, to make sure we do the relayout before receiving
492 // any other events from the system.
493 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700494 if ((mWindowAttributes.inputFeatures
495 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
496 mInputChannel = new InputChannel();
497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700499 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700500 mAttachInfo.mRecomputeGlobalAttributes = true;
501 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700502 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
503 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700504 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 } catch (RemoteException e) {
506 mAdded = false;
507 mView = null;
508 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700509 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700510 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700512 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700514 } finally {
515 if (restore) {
516 attrs.restore();
517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700519
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700520 if (mTranslator != null) {
521 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700522 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800523 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 mPendingContentInsets.set(mAttachInfo.mContentInsets);
525 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800526 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700527 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 mAttachInfo.mRootView = null;
529 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700530 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700532 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700534 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
535 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
536 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 "Unable to add window -- token " + attrs.token
538 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700539 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
540 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 "Unable to add window -- token " + attrs.token
542 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700543 case WindowManagerGlobal.ADD_APP_EXITING:
544 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 "Unable to add window -- app for token " + attrs.token
546 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700547 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
548 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 "Unable to add window -- window " + mWindow
550 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700551 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 // Silently ignore -- we would have just removed it
553 // right away, anyway.
554 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700555 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
556 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 "Unable to add window " + mWindow +
558 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700559 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
560 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 "Unable to add window " + mWindow +
562 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700563 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
564 throw new WindowManager.InvalidDisplayException(
565 "Unable to add window " + mWindow +
566 " -- the specified display can not be found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568 throw new RuntimeException(
569 "Unable to add window -- unknown error code " + res);
570 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700571
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700572 if (view instanceof RootViewSurfaceTaker) {
573 mInputQueueCallback =
574 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
575 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700576 if (mInputChannel != null) {
577 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700578 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700579 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700580 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700581 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
582 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700583 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700586 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
587 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700588
589 if (mAccessibilityManager.isEnabled()) {
590 mAccessibilityInteractionConnectionManager.ensureConnection();
591 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700592
593 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
594 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
595 }
Michael Wright95ae9422013-03-14 10:58:50 -0700596
Jeff Brownf9e989d2013-04-04 23:04:03 -0700597 // Set up the input pipeline.
598 CharSequence counterSuffix = attrs.getTitle();
Michael Wright88d7f792013-08-27 15:45:42 -0700599 InputStage syntheticInputStage = new SyntheticInputStage();
600 InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700601 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
602 "aq:native-post-ime:" + counterSuffix);
603 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
604 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
605 "aq:ime:" + counterSuffix);
606 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
607 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
608 "aq:native-pre-ime:" + counterSuffix);
609
610 mFirstInputStage = nativePreImeStage;
611 mFirstPostImeInputStage = earlyPostImeStage;
612 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
614 }
615 }
616
keunyoung30f420f2013-08-02 14:23:10 -0700617 /** Whether the window is in local focus mode or not */
618 private boolean isInLocalFocusMode() {
619 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
620 }
621
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800622 void destroyHardwareResources() {
Romain Guy46bfc482013-08-16 18:38:29 -0700623 invalidateDisplayLists();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800624 if (mAttachInfo.mHardwareRenderer != null) {
625 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
626 mAttachInfo.mHardwareRenderer.destroy(false);
627 }
628 }
629
Romain Guy65b345f2011-07-27 18:51:50 -0700630 void destroyHardwareLayers() {
631 if (mThread != Thread.currentThread()) {
632 if (mAttachInfo.mHardwareRenderer != null &&
633 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700634 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700635 }
636 } else {
Romain Guy46bfc482013-08-16 18:38:29 -0700637 invalidateDisplayLists();
Romain Guy65b345f2011-07-27 18:51:50 -0700638 if (mAttachInfo.mHardwareRenderer != null &&
639 mAttachInfo.mHardwareRenderer.isEnabled()) {
640 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
641 }
642 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700643 }
644
Romain Guy11cb6422012-09-21 00:39:43 -0700645 void pushHardwareLayerUpdate(HardwareLayer layer) {
646 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
647 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
648 }
649 }
650
Romain Guy40543602013-06-12 15:31:28 -0700651 void flushHardwareLayerUpdates() {
652 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
653 mAttachInfo.mHardwareRenderer.validate()) {
654 mAttachInfo.mHardwareRenderer.flushLayerUpdates();
655 }
656 }
657
658 void dispatchFlushHardwareLayerUpdates() {
659 mHandler.removeMessages(MSG_FLUSH_LAYER_UPDATES);
660 mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
661 }
662
John Reck4f02bf42014-01-03 18:09:17 -0800663 public void attachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700664 //noinspection SimplifiableIfStatement
Romain Guyba6be8a2012-04-23 18:22:09 -0700665 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
John Reck4f02bf42014-01-03 18:09:17 -0800666 mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700667 }
668 }
669
670 public void detachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700671 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700672 mAttachInfo.mHardwareRenderer.detachFunctor(functor);
673 }
674 }
675
Romain Guy3b748a42013-04-17 18:54:38 -0700676 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800677 mAttachInfo.mHardwareAccelerated = false;
678 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800679
Romain Guy856d4e12011-10-14 15:47:55 -0700680 // Don't enable hardware acceleration when the application is in compatibility mode
681 if (mTranslator != null) return;
682
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800683 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700684 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800685 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
686
Romain Guy566c3312011-03-21 18:21:28 -0700687 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700688 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700689 return;
690 }
691
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700692 // Persistent processes (including the system) should not do
693 // accelerated rendering on low-end devices. In that case,
694 // sRendererDisabled will be set. In addition, the system process
695 // itself should never do accelerated rendering. In that case, both
696 // sRendererDisabled and sSystemRendererDisabled are set. When
697 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
698 // can be used by code on the system process to escape that and enable
699 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800700
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700701 final boolean fakeHwAccelerated = (attrs.privateFlags &
702 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
703 final boolean forceHwAccelerated = (attrs.privateFlags &
704 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800705
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700706 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
707 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800708 // Don't enable hardware acceleration when we're not on the main thread
Romain Guy211370f2012-02-01 16:10:55 -0800709 if (!HardwareRenderer.sSystemRendererDisabled &&
710 Looper.getMainLooper() != Looper.myLooper()) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700711 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800712 + "acceleration outside of the main thread, aborting");
713 return;
714 }
715
Romain Guyb051e892010-09-28 19:09:36 -0700716 if (mAttachInfo.mHardwareRenderer != null) {
717 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy211370f2012-02-01 16:10:55 -0800718 }
719
720 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
John Reck30835792013-11-07 14:21:24 -0800721 mAttachInfo.mHardwareRenderer = HardwareRenderer.create(translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700722 if (mAttachInfo.mHardwareRenderer != null) {
723 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
724 mAttachInfo.mHardwareAccelerated =
725 mAttachInfo.mHardwareAccelerationRequested = true;
726 }
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700727 } else if (fakeHwAccelerated) {
728 // The window had wanted to use hardware acceleration, but this
729 // is not allowed in its process. By setting this flag, it can
730 // still render as if it was accelerated. This is basically for
731 // the preview windows the window manager shows for launching
732 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700733 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700734 }
735 }
736 }
737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 public View getView() {
739 return mView;
740 }
741
742 final WindowLeaked getLocation() {
743 return mLocation;
744 }
745
746 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
747 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700748 int oldSoftInputMode = mWindowAttributes.softInputMode;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700749 // Keep track of the actual window flags supplied by the client.
750 mClientWindowLayoutFlags = attrs.flags;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700751 // preserve compatible window flag if exists.
Adam Lesinski95c42972013-10-02 10:13:27 -0700752 int compatibleWindowFlag = mWindowAttributes.privateFlags
753 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Craig Mautner3fe38c02012-05-03 17:28:09 -0700754 // transfer over system UI visibility values as they carry current state.
755 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
756 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Romain Guyf21c9b02011-09-06 16:56:54 -0700757 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400758 if ((mWindowAttributesChangesFlag
759 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
760 // Recompute system ui visibility.
761 mAttachInfo.mRecomputeGlobalAttributes = true;
762 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800763 if (mWindowAttributes.packageName == null) {
764 mWindowAttributes.packageName = mBasePackageName;
765 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700766 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700767
768 applyKeepScreenOnFlag(mWindowAttributes);
769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 if (newView) {
771 mSoftInputMode = attrs.softInputMode;
772 requestLayout();
773 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700774 // Don't lose the mode we last auto-computed.
775 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
776 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
777 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
778 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
779 | (oldSoftInputMode
780 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
781 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 mWindowAttributesChanged = true;
783 scheduleTraversals();
784 }
785 }
786
787 void handleAppVisibility(boolean visible) {
788 if (mAppVisible != visible) {
789 mAppVisible = visible;
790 scheduleTraversals();
791 }
792 }
793
794 void handleGetNewSurface() {
795 mNewSurfaceNeeded = true;
796 mFullRedrawNeeded = true;
797 scheduleTraversals();
798 }
799
Romain Guybb9908b2012-03-08 11:14:07 -0800800 void handleScreenStateChange(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -0800801 if (on != mAttachInfo.mScreenOn) {
802 mAttachInfo.mScreenOn = on;
Romain Guybb9908b2012-03-08 11:14:07 -0800803 if (mView != null) {
804 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
805 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800806 if (on) {
807 mFullRedrawNeeded = true;
808 scheduleTraversals();
809 }
810 }
811 }
812
Craig Mautner6018aee2012-10-23 14:27:49 -0700813 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700814 public void requestFitSystemWindows() {
815 checkThread();
816 mFitSystemWindowsRequested = true;
817 scheduleTraversals();
818 }
819
Craig Mautner6018aee2012-10-23 14:27:49 -0700820 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800822 if (!mHandlingLayoutInLayoutRequest) {
823 checkThread();
824 mLayoutRequested = true;
825 scheduleTraversals();
826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
828
Craig Mautner6018aee2012-10-23 14:27:49 -0700829 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 public boolean isLayoutRequested() {
831 return mLayoutRequested;
832 }
833
Romain Guycfef1232012-02-23 13:50:37 -0800834 void invalidate() {
835 mDirty.set(0, 0, mWidth, mHeight);
836 scheduleTraversals();
837 }
838
Dianne Hackborna53de062012-05-08 18:53:51 -0700839 void invalidateWorld(View view) {
840 view.invalidate();
841 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700842 ViewGroup parent = (ViewGroup) view;
843 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700844 invalidateWorld(parent.getChildAt(i));
845 }
846 }
847 }
848
Craig Mautner6018aee2012-10-23 14:27:49 -0700849 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800851 invalidateChildInParent(null, dirty);
852 }
853
Craig Mautner8f303ad2013-06-14 11:32:22 -0700854 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800855 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700857 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800858
Chet Haase70d4ba12010-10-06 09:46:45 -0700859 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700860 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800861 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700862 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700863 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700864 }
Romain Guycfef1232012-02-23 13:50:37 -0800865
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700866 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700868 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700869 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800870 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700871 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700872 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700873 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700874 }
Romain Guy1e095972009-07-07 11:22:45 -0700875 if (mAttachInfo.mScalingRequired) {
876 dirty.inset(-1, -1);
877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 }
Romain Guycfef1232012-02-23 13:50:37 -0800879
880 final Rect localDirty = mDirty;
881 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700882 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800883 mAttachInfo.mIgnoreDirtyState = true;
884 }
Romain Guycfef1232012-02-23 13:50:37 -0800885
886 // Add the new dirty rect to the current one
887 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
888 // Intersect with the bounds of the window to skip
889 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700890 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700891 final boolean intersected = localDirty.intersect(0, 0,
892 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
893 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700894 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 }
Chet Haase3561d062012-10-23 12:54:51 -0700896 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
897 scheduleTraversals();
898 }
Romain Guycfef1232012-02-23 13:50:37 -0800899
900 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902
Dianne Hackbornce418e62011-03-01 14:31:38 -0800903 void setStopped(boolean stopped) {
904 if (mStopped != stopped) {
905 mStopped = stopped;
906 if (!stopped) {
907 scheduleTraversals();
908 }
909 }
910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911
Craig Mautner8f303ad2013-06-14 11:32:22 -0700912 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800913 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 return null;
915 }
916
Craig Mautner8f303ad2013-06-14 11:32:22 -0700917 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700918 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 if (child != mView) {
920 throw new RuntimeException("child is not mine, honest!");
921 }
922 // Note: don't apply scroll offset, because we want to know its
923 // visibility in the virtual canvas being given to the view hierarchy.
924 return r.intersect(0, 0, mWidth, mHeight);
925 }
926
Igor Murashkina86ab6402013-08-30 12:58:36 -0700927 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 public void bringChildToFront(View child) {
929 }
930
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 int getHostVisibility() {
932 return mAppVisible ? mView.getVisibility() : View.GONE;
933 }
Romain Guy8506ab42009-06-11 17:35:47 -0700934
John Reckcec24ae2013-11-05 13:27:50 -0800935// void disposeResizeBuffer() {
936// if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) {
937// mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
938// @Override
939// public void run() {
940// mResizeBuffer.destroy();
941// mResizeBuffer = null;
942// }
943// });
944// }
945// }
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800946
Chet Haasecca2c982011-05-20 14:34:18 -0700947 /**
948 * Add LayoutTransition to the list of transitions to be started in the next traversal.
949 * This list will be cleared after the transitions on the list are start()'ed. These
950 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
951 * happens during the layout phase of traversal, which we want to complete before any of the
952 * animations are started (because those animations may side-effect properties that layout
953 * depends upon, like the bounding rectangles of the affected views). So we add the transition
954 * to the list and it is started just prior to starting the drawing phase of traversal.
955 *
956 * @param transition The LayoutTransition to be started on the next traversal.
957 *
958 * @hide
959 */
960 public void requestTransitionStart(LayoutTransition transition) {
961 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
962 if (mPendingTransitions == null) {
963 mPendingTransitions = new ArrayList<LayoutTransition>();
964 }
965 mPendingTransitions.add(transition);
966 }
967 }
968
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700969 void scheduleTraversals() {
970 if (!mTraversalScheduled) {
971 mTraversalScheduled = true;
972 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
973 mChoreographer.postCallback(
974 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Jeff Brown330314c2012-04-27 02:20:22 -0700975 scheduleConsumeBatchedInput();
Jeff Brown96e942d2011-11-30 19:55:01 -0800976 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700977 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800978
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700979 void unscheduleTraversals() {
980 if (mTraversalScheduled) {
981 mTraversalScheduled = false;
982 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
983 mChoreographer.removeCallbacks(
984 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
985 }
986 }
987
988 void doTraversal() {
989 if (mTraversalScheduled) {
990 mTraversalScheduled = false;
991 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
992
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700993 if (mProfile) {
994 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -0800995 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800996
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700997 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
998 try {
999 performTraversals();
1000 } finally {
1001 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1002 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001003
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001004 if (mProfile) {
1005 Debug.stopMethodTracing();
1006 mProfile = false;
1007 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001008 }
1009 }
1010
Dianne Hackborn9d090892012-06-11 18:35:41 -07001011 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1012 // Update window's global keep screen on flag: if a view has requested
1013 // that the screen be kept on, then it is always set; otherwise, it is
1014 // set to whatever the client last requested for the global state.
1015 if (mAttachInfo.mKeepScreenOn) {
1016 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1017 } else {
1018 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1019 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1020 }
1021 }
1022
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001023 private boolean collectViewAttributes() {
1024 final View.AttachInfo attachInfo = mAttachInfo;
1025 if (attachInfo.mRecomputeGlobalAttributes) {
1026 //Log.i(TAG, "Computing view hierarchy attributes!");
1027 attachInfo.mRecomputeGlobalAttributes = false;
1028 boolean oldScreenOn = attachInfo.mKeepScreenOn;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001029 attachInfo.mKeepScreenOn = false;
1030 attachInfo.mSystemUiVisibility = 0;
1031 attachInfo.mHasSystemUiListeners = false;
1032 mView.dispatchCollectViewAttributes(attachInfo, 0);
Dianne Hackborn139e5aa2012-05-05 20:36:38 -07001033 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001034 WindowManager.LayoutParams params = mWindowAttributes;
John Spurlockbd957402013-10-03 11:38:39 -04001035 attachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001036 if (attachInfo.mKeepScreenOn != oldScreenOn
Craig Mautner7eac0f52012-09-13 13:14:14 -07001037 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1038 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001039 applyKeepScreenOnFlag(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001040 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1041 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1042 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1043 return true;
1044 }
1045 }
1046 return false;
1047 }
1048
John Spurlockbd957402013-10-03 11:38:39 -04001049 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1050 int vis = 0;
1051 // Translucent decor window flags imply stable system ui visibility.
1052 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1053 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1054 }
1055 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1056 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1057 }
1058 return vis;
1059 }
1060
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001061 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1062 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1063 int childWidthMeasureSpec;
1064 int childHeightMeasureSpec;
1065 boolean windowSizeMayChange = false;
1066
1067 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1068 "Measuring " + host + " in display " + desiredWindowWidth
1069 + "x" + desiredWindowHeight + "...");
1070
1071 boolean goodMeasure = false;
1072 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1073 // On large screens, we don't want to allow dialogs to just
1074 // stretch to fill the entire width of the screen to display
1075 // one line of text. First try doing the layout at a smaller
1076 // size to see if it will fit.
1077 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1078 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1079 int baseSize = 0;
1080 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1081 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1082 }
1083 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1084 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1085 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1086 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001087 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001088 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1089 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1090 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1091 goodMeasure = true;
1092 } else {
1093 // Didn't fit in that size... try expanding a bit.
1094 baseSize = (baseSize+desiredWindowWidth)/2;
1095 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1096 + baseSize);
1097 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001098 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001099 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1100 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1101 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1102 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1103 goodMeasure = true;
1104 }
1105 }
1106 }
1107 }
1108
1109 if (!goodMeasure) {
1110 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1111 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001112 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001113 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1114 windowSizeMayChange = true;
1115 }
1116 }
1117
1118 if (DBG) {
1119 System.out.println("======================================");
1120 System.out.println("performTraversals -- after measure");
1121 host.debug();
1122 }
1123
1124 return windowSizeMayChange;
1125 }
1126
Alan Viverettefed3f722013-11-14 14:48:20 -08001127 /**
1128 * Modifies the input matrix such that it maps view-local coordinates to
1129 * on-screen coordinates.
1130 *
1131 * @param m input matrix to modify
1132 */
1133 void transformMatrixToGlobal(Matrix m) {
1134 final View.AttachInfo attachInfo = mAttachInfo;
1135 m.postTranslate(attachInfo.mWindowLeft, attachInfo.mWindowTop);
1136 }
1137
1138 /**
1139 * Modifies the input matrix such that it maps on-screen coordinates to
1140 * view-local coordinates.
1141 *
1142 * @param m input matrix to modify
1143 */
1144 void transformMatrixToLocal(Matrix m) {
1145 final View.AttachInfo attachInfo = mAttachInfo;
1146 m.preTranslate(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
1147 }
1148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 private void performTraversals() {
1150 // cache mView since it is used so much below...
1151 final View host = mView;
1152
1153 if (DBG) {
1154 System.out.println("======================================");
1155 System.out.println("performTraversals");
1156 host.debug();
1157 }
1158
1159 if (host == null || !mAdded)
1160 return;
1161
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001162 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001164 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001166 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 WindowManager.LayoutParams lp = mWindowAttributes;
1168
1169 int desiredWindowWidth;
1170 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171
1172 final View.AttachInfo attachInfo = mAttachInfo;
1173
1174 final int viewVisibility = getHostVisibility();
1175 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1176 || mNewSurfaceNeeded;
1177
1178 WindowManager.LayoutParams params = null;
1179 if (mWindowAttributesChanged) {
1180 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001181 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 params = lp;
1183 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001184 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001185 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1186 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001187 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001188 mLayoutRequested = true;
1189 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001190 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001191 mLastInCompatMode = false;
1192 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001193 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001194 mLastInCompatMode = true;
1195 }
1196 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001197
Romain Guyf21c9b02011-09-06 16:56:54 -07001198 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001199
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001200 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001202 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 mLayoutRequested = true;
1204
John Spurlockf8508272013-10-14 21:06:52 -04001205 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1206 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001207 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001208 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001209 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001210 desiredWindowWidth = size.x;
1211 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001212 } else {
1213 DisplayMetrics packageMetrics =
1214 mView.getContext().getResources().getDisplayMetrics();
1215 desiredWindowWidth = packageMetrics.widthPixels;
1216 desiredWindowHeight = packageMetrics.heightPixels;
1217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218
Romain Guyc5d55862011-01-21 19:01:46 -08001219 // We used to use the following condition to choose 32 bits drawing caches:
1220 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1221 // However, windows are now always 32 bits by default, so choose 32 bits
1222 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 attachInfo.mHasWindowFocus = false;
1224 attachInfo.mWindowVisibility = viewVisibility;
1225 attachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001227 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001228 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001229 // Set the layout direction if it has not been set before (inherit is the default)
1230 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1231 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 host.dispatchAttachedToWindow(attachInfo, 0);
Dianne Hackborn961cae92013-03-20 14:59:43 -07001234 attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001235 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1236 host.fitSystemWindows(mFitSystemWindowsInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001240 desiredWindowWidth = frame.width();
1241 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001243 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001244 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001245 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001247 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249 }
1250
1251 if (viewVisibilityChanged) {
1252 attachInfo.mWindowVisibility = viewVisibility;
1253 host.dispatchWindowVisibilityChanged(viewVisibility);
1254 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001255 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 }
1257 if (viewVisibility == View.GONE) {
1258 // After making a window gone, we will count it as being
1259 // shown for the first time the next time it gets focus.
1260 mHasHadWindowFocus = false;
1261 }
1262 }
1263
Chet Haaseb78c2842012-04-19 13:39:50 -07001264 // Execute enqueued actions on every traversal in case a detached view enqueued an action
1265 getRunQueue().executeActions(attachInfo.mHandler);
1266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001268
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001269 boolean layoutRequested = mLayoutRequested && !mStopped;
1270 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001271
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001272 final Resources res = mView.getContext().getResources();
1273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 // make sure touch mode code executes by setting cached value
1276 // to opposite of the added touch mode.
1277 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001278 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001280 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1281 insetsChanged = true;
1282 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001283 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001286 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1288 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1289 + mAttachInfo.mVisibleInsets);
1290 }
1291 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1292 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001293 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294
John Spurlockf8508272013-10-14 21:06:52 -04001295 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1296 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001297 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001298 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001299 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001300 desiredWindowWidth = size.x;
1301 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001302 } else {
1303 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1304 desiredWindowWidth = packageMetrics.widthPixels;
1305 desiredWindowHeight = packageMetrics.heightPixels;
1306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 }
1308 }
1309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001311 windowSizeMayChange |= measureHierarchy(host, lp, res,
1312 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001315 if (collectViewAttributes()) {
1316 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001318 if (attachInfo.mForceReportNewAttributes) {
1319 attachInfo.mForceReportNewAttributes = false;
1320 params = lp;
1321 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322
1323 if (mFirst || attachInfo.mViewVisibilityChanged) {
1324 attachInfo.mViewVisibilityChanged = false;
1325 int resizeMode = mSoftInputMode &
1326 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1327 // If we are in auto resize mode, then we need to determine
1328 // what mode to use now.
1329 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1330 final int N = attachInfo.mScrollContainers.size();
1331 for (int i=0; i<N; i++) {
1332 if (attachInfo.mScrollContainers.get(i).isShown()) {
1333 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1334 }
1335 }
1336 if (resizeMode == 0) {
1337 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1338 }
1339 if ((lp.softInputMode &
1340 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1341 lp.softInputMode = (lp.softInputMode &
1342 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1343 resizeMode;
1344 params = lp;
1345 }
1346 }
1347 }
Romain Guy8506ab42009-06-11 17:35:47 -07001348
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001349 if (params != null) {
1350 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1351 if (!PixelFormat.formatHasAlpha(params.format)) {
1352 params.format = PixelFormat.TRANSLUCENT;
1353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001355 mAttachInfo.mOverscanRequested = (params.flags
1356 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 }
1358
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001359 if (mFitSystemWindowsRequested) {
1360 mFitSystemWindowsRequested = false;
1361 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001362 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001363 host.fitSystemWindows(mFitSystemWindowsInsets);
1364 if (mLayoutRequested) {
1365 // Short-circuit catching a new layout request here, so
1366 // we don't need to go through two layout passes when things
1367 // change due to fitting system windows, which can happen a lot.
1368 windowSizeMayChange |= measureHierarchy(host, lp,
1369 mView.getContext().getResources(),
1370 desiredWindowWidth, desiredWindowHeight);
1371 }
1372 }
1373
1374 if (layoutRequested) {
1375 // Clear this now, so that if anything requests a layout in the
1376 // rest of this function we will catch it and re-run a full
1377 // layout pass.
1378 mLayoutRequested = false;
1379 }
1380
1381 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001382 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001383 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1384 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1385 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1386 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387
Jeff Brown2e05ec32013-09-30 15:57:43 -07001388 // Determine whether to compute insets.
1389 // If there are no inset listeners remaining then we may still need to compute
1390 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 final boolean computesInternalInsets =
Jeff Brown2e05ec32013-09-30 15:57:43 -07001392 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1393 || attachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 boolean insetsPending = false;
1396 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001397
1398 if (mFirst || windowShouldResize || insetsChanged ||
1399 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400
1401 if (viewVisibility == View.VISIBLE) {
1402 // If this window is giving internal insets to the window
1403 // manager, and it is being added or changing its visibility,
1404 // then we want to first give the window manager "fake"
1405 // insets to cause it to effectively ignore the content of
1406 // the window during layout. This avoids it briefly causing
1407 // other windows to resize/move based on the raw frame of the
1408 // window, waiting until we can finish laying out this window
1409 // and get back to the window manager with the ultimately
1410 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001411 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 }
1413
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001414 if (mSurfaceHolder != null) {
1415 mSurfaceHolder.mSurfaceLock.lock();
1416 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001417 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001418
Romain Guyc361da82010-10-25 15:29:10 -07001419 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001421 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001424 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001425 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1426 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001427 }
Romain Guy2a83f002011-01-18 18:28:21 -08001428
1429 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001430 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
Dianne Hackborn021d2432013-10-13 15:20:09 -07001431 if (!mDrawDuringWindowsAnimating &&
1432 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
1433 mWindowsAnimating = true;
Michael Jurkaf42d90102013-05-08 18:00:04 +02001434 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001437 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 + " content=" + mPendingContentInsets.toShortString()
1439 + " visible=" + mPendingVisibleInsets.toShortString()
1440 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001441
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001442 if (mPendingConfiguration.seq != 0) {
1443 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1444 + mPendingConfiguration);
1445 updateConfiguration(mPendingConfiguration, !mFirst);
1446 mPendingConfiguration.seq = 0;
1447 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001448
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001449 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1450 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 contentInsetsChanged = !mPendingContentInsets.equals(
1452 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001453 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 mAttachInfo.mVisibleInsets);
1455 if (contentInsetsChanged) {
John Reckcec24ae2013-11-05 13:27:50 -08001456// TODO: Do something with this...
1457// if (mWidth > 0 && mHeight > 0 && lp != null &&
1458// ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1459// & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
1460// mSurface != null && mSurface.isValid() &&
1461// !mAttachInfo.mTurnOffWindowResizeAnim &&
1462// mAttachInfo.mHardwareRenderer != null &&
1463// mAttachInfo.mHardwareRenderer.isEnabled() &&
1464// mAttachInfo.mHardwareRenderer.validate() &&
1465// lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1466//
1467// disposeResizeBuffer();
1468//
1469// boolean completed = false;
1470// HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
1471// HardwareCanvas layerCanvas = null;
1472// try {
1473// if (mResizeBuffer == null) {
1474// mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1475// mWidth, mHeight, false);
1476// } else if (mResizeBuffer.getWidth() != mWidth ||
1477// mResizeBuffer.getHeight() != mHeight) {
1478// mResizeBuffer.resize(mWidth, mHeight);
1479// }
1480// // TODO: should handle create/resize failure
1481// layerCanvas = mResizeBuffer.start(hwRendererCanvas);
1482// final int restoreCount = layerCanvas.save();
1483//
1484// int yoff;
1485// final boolean scrolling = mScroller != null
1486// && mScroller.computeScrollOffset();
1487// if (scrolling) {
1488// yoff = mScroller.getCurrY();
1489// mScroller.abortAnimation();
1490// } else {
1491// yoff = mScrollY;
1492// }
1493//
1494// layerCanvas.translate(0, -yoff);
1495// if (mTranslator != null) {
1496// mTranslator.translateCanvas(layerCanvas);
1497// }
1498//
1499// DisplayList displayList = mView.mDisplayList;
1500// if (displayList != null && displayList.isValid()) {
1501// layerCanvas.drawDisplayList(displayList, null,
1502// DisplayList.FLAG_CLIP_CHILDREN);
1503// } else {
1504// mView.draw(layerCanvas);
1505// }
1506//
1507// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1508//
1509// mResizeBufferStartTime = SystemClock.uptimeMillis();
1510// mResizeBufferDuration = mView.getResources().getInteger(
1511// com.android.internal.R.integer.config_mediumAnimTime);
1512// completed = true;
1513//
1514// layerCanvas.restoreToCount(restoreCount);
1515// } catch (OutOfMemoryError e) {
1516// Log.w(TAG, "Not enough memory for content change anim buffer", e);
1517// } finally {
1518// if (mResizeBuffer != null) {
1519// mResizeBuffer.end(hwRendererCanvas);
1520// if (!completed) {
1521// disposeResizeBuffer();
1522// }
1523// }
1524// }
1525// }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1528 + mAttachInfo.mContentInsets);
1529 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001530 if (overscanInsetsChanged) {
1531 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1532 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1533 + mAttachInfo.mOverscanInsets);
1534 // Need to relayout with content insets.
1535 contentInsetsChanged = true;
1536 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001537 if (contentInsetsChanged || mLastSystemUiVisibility !=
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001538 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
1539 || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001540 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001541 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001542 mFitSystemWindowsRequested = false;
1543 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1544 host.fitSystemWindows(mFitSystemWindowsInsets);
1545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 if (visibleInsetsChanged) {
1547 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1548 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1549 + mAttachInfo.mVisibleInsets);
1550 }
1551
1552 if (!hadSurface) {
1553 if (mSurface.isValid()) {
1554 // If we are creating a new surface, then we need to
1555 // completely redraw it. Also, when we get to the
1556 // point of drawing it we will hold off and schedule
1557 // a new traversal instead. This is so we can tell the
1558 // window manager about all of the windows being displayed
1559 // before actually drawing them, so it can display then
1560 // all at once.
1561 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001562 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001563 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001564
Romain Guyb051e892010-09-28 19:09:36 -07001565 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001566 try {
Romain Guy786fc932012-07-24 16:24:56 -07001567 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08001568 mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001569 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001570 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001571 return;
1572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 }
1574 }
1575 } else if (!mSurface.isValid()) {
1576 // If the surface has been removed, then reset the scroll
1577 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001578 if (mLastScrolledFocus != null) {
1579 mLastScrolledFocus.clear();
1580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 mScrollY = mCurScrollY = 0;
1582 if (mScroller != null) {
1583 mScroller.abortAnimation();
1584 }
John Reckcec24ae2013-11-05 13:27:50 -08001585// disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001586 // Our surface is gone
1587 if (mAttachInfo.mHardwareRenderer != null &&
1588 mAttachInfo.mHardwareRenderer.isEnabled()) {
1589 mAttachInfo.mHardwareRenderer.destroy(true);
1590 }
Romain Guy2a83f002011-01-18 18:28:21 -08001591 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1592 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001593 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001594 try {
John Reck79d81e62013-11-05 13:26:57 -08001595 mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001596 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001597 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001598 return;
1599 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 }
1601 } catch (RemoteException e) {
1602 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001605 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606
1607 attachInfo.mWindowLeft = frame.left;
1608 attachInfo.mWindowTop = frame.top;
1609
1610 // !!FIXME!! This next section handles the case where we did not get the
1611 // window size we asked for. We should avoid this by getting a maximum size from
1612 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001613 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001614 mWidth = frame.width();
1615 mHeight = frame.height();
1616 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001618 if (mSurfaceHolder != null) {
1619 // The app owns the surface; tell it about what is going on.
1620 if (mSurface.isValid()) {
1621 // XXX .copyFrom() doesn't work!
1622 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1623 mSurfaceHolder.mSurface = mSurface;
1624 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001625 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001626 mSurfaceHolder.mSurfaceLock.unlock();
1627 if (mSurface.isValid()) {
1628 if (!hadSurface) {
1629 mSurfaceHolder.ungetCallbacks();
1630
1631 mIsCreating = true;
1632 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1633 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1634 if (callbacks != null) {
1635 for (SurfaceHolder.Callback c : callbacks) {
1636 c.surfaceCreated(mSurfaceHolder);
1637 }
1638 }
1639 surfaceChanged = true;
1640 }
1641 if (surfaceChanged) {
1642 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1643 lp.format, mWidth, mHeight);
1644 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1645 if (callbacks != null) {
1646 for (SurfaceHolder.Callback c : callbacks) {
1647 c.surfaceChanged(mSurfaceHolder, lp.format,
1648 mWidth, mHeight);
1649 }
1650 }
1651 }
1652 mIsCreating = false;
1653 } else if (hadSurface) {
1654 mSurfaceHolder.ungetCallbacks();
1655 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1656 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1657 if (callbacks != null) {
1658 for (SurfaceHolder.Callback c : callbacks) {
1659 c.surfaceDestroyed(mSurfaceHolder);
1660 }
1661 }
1662 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001663 try {
1664 mSurfaceHolder.mSurface = new Surface();
1665 } finally {
1666 mSurfaceHolder.mSurfaceLock.unlock();
1667 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001668 }
1669 }
Romain Guy53389bd2010-09-07 17:16:32 -07001670
Chet Haase40e03832011-10-06 08:34:13 -07001671 if (mAttachInfo.mHardwareRenderer != null &&
1672 mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guy370ab062013-05-21 12:15:07 -07001673 if (hwInitialized ||
Chet Haase40e03832011-10-06 08:34:13 -07001674 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1675 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1676 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1677 if (!hwInitialized) {
John Reck79d81e62013-11-05 13:26:57 -08001678 mAttachInfo.mHardwareRenderer.invalidate(mSurface);
Chet Haase391fef02012-09-27 15:26:36 -07001679 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001680 }
Romain Guy03985752011-07-11 15:33:51 -07001681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
1683
Dianne Hackbornce418e62011-03-01 14:31:38 -08001684 if (!mStopped) {
1685 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001686 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001687 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1688 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001689 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1690 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001691
Dianne Hackbornce418e62011-03-01 14:31:38 -08001692 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1693 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1694 + " mHeight=" + mHeight
1695 + " measuredHeight=" + host.getMeasuredHeight()
1696 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001697
Dianne Hackbornce418e62011-03-01 14:31:38 -08001698 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001699 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001700
Dianne Hackbornce418e62011-03-01 14:31:38 -08001701 // Implementation of weights from WindowManager.LayoutParams
1702 // We just grow the dimensions as needed and re-measure if
1703 // needs be
1704 int width = host.getMeasuredWidth();
1705 int height = host.getMeasuredHeight();
1706 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001707
Dianne Hackbornce418e62011-03-01 14:31:38 -08001708 if (lp.horizontalWeight > 0.0f) {
1709 width += (int) ((mWidth - width) * lp.horizontalWeight);
1710 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1711 MeasureSpec.EXACTLY);
1712 measureAgain = true;
1713 }
1714 if (lp.verticalWeight > 0.0f) {
1715 height += (int) ((mHeight - height) * lp.verticalWeight);
1716 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1717 MeasureSpec.EXACTLY);
1718 measureAgain = true;
1719 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001720
Dianne Hackbornce418e62011-03-01 14:31:38 -08001721 if (measureAgain) {
1722 if (DEBUG_LAYOUT) Log.v(TAG,
1723 "And hey let's measure once more: width=" + width
1724 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001725 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001726 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001727
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001728 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001731 } else {
1732 // Not the first pass and no window/insets/visibility change but the window
1733 // may have moved and we need check that and if so to update the left and right
1734 // in the attach info. We translate only the window frame since on window move
1735 // the window manager tells us only for the new frame but the insets are the
1736 // same and we do not want to translate them more than once.
1737
1738 // TODO: Well, we are checking whether the frame has changed similarly
1739 // to how this is done for the insets. This is however incorrect since
1740 // the insets and the frame are translated. For example, the old frame
1741 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1742 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1743 // true since we are comparing a not translated value to a translated one.
1744 // This scenario is rare but we may want to fix that.
1745
1746 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1747 || attachInfo.mWindowTop != frame.top);
1748 if (windowMoved) {
1749 if (mTranslator != null) {
1750 mTranslator.translateRectInScreenToAppWinFrame(frame);
1751 }
1752 attachInfo.mWindowLeft = frame.left;
1753 attachInfo.mWindowTop = frame.top;
1754 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001757 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 boolean triggerGlobalLayoutListener = didLayout
1759 || attachInfo.mRecomputeGlobalAttributes;
1760 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001761 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001763 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 // We can compute the transparent area
1765
Dianne Hackborn4702a852012-08-17 15:18:29 -07001766 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 // start out transparent
1768 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1769 host.getLocationInWindow(mTmpLocation);
1770 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1771 mTmpLocation[0] + host.mRight - host.mLeft,
1772 mTmpLocation[1] + host.mBottom - host.mTop);
1773
1774 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001775 if (mTranslator != null) {
1776 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1777 }
1778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1780 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001781 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 // reconfigure window manager
1783 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001784 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 } catch (RemoteException e) {
1786 }
1787 }
1788 }
1789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 if (DBG) {
1791 System.out.println("======================================");
1792 System.out.println("performTraversals -- after setFrame");
1793 host.debug();
1794 }
1795 }
1796
1797 if (triggerGlobalLayoutListener) {
1798 attachInfo.mRecomputeGlobalAttributes = false;
1799 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1800 }
1801
1802 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001803 // Clear the original insets.
1804 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1805 insets.reset();
1806
1807 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brown2e05ec32013-09-30 15:57:43 -07001809 attachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08001810
1811 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1813 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001814
1815 // Translate insets to screen coordinates if needed.
1816 final Rect contentInsets;
1817 final Rect visibleInsets;
1818 final Region touchableRegion;
1819 if (mTranslator != null) {
1820 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1821 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1822 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1823 } else {
1824 contentInsets = insets.contentInsets;
1825 visibleInsets = insets.visibleInsets;
1826 touchableRegion = insets.touchableRegion;
1827 }
1828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001830 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001831 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 } catch (RemoteException e) {
1833 }
1834 }
1835 }
Romain Guy8506ab42009-06-11 17:35:47 -07001836
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001837 boolean skipDraw = false;
1838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 if (mFirst) {
1840 // handle first focus request
1841 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1842 + mView.hasFocus());
1843 if (mView != null) {
1844 if (!mView.hasFocus()) {
1845 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001847 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001850 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 }
1852 }
Jeff Brown98365d72012-08-19 20:30:52 -07001853 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001854 // The first time we relayout the window, if the system is
1855 // doing window animations, we want to hold of on any future
1856 // draws until the animation is done.
1857 mWindowsAnimating = true;
1858 }
1859 } else if (mWindowsAnimating) {
1860 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 }
1862
1863 mFirst = false;
1864 mWillDrawSoon = false;
1865 mNewSurfaceNeeded = false;
1866 mViewVisibility = viewVisibility;
1867
keunyoung30f420f2013-08-02 14:23:10 -07001868 if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 final boolean imTarget = WindowManager.LayoutParams
1870 .mayUseInputMethod(mWindowAttributes.flags);
1871 if (imTarget != mLastWasImTarget) {
1872 mLastWasImTarget = imTarget;
1873 InputMethodManager imm = InputMethodManager.peekInstance();
1874 if (imm != null && imTarget) {
1875 imm.startGettingWindowFocus(mView);
1876 imm.onWindowFocus(mView, mView.findFocus(),
1877 mWindowAttributes.softInputMode,
1878 !mHasHadWindowFocus, mWindowAttributes.flags);
1879 }
1880 }
1881 }
Romain Guy8506ab42009-06-11 17:35:47 -07001882
Jeff Brown96e942d2011-11-30 19:55:01 -08001883 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001884 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001885 mReportNextDraw = true;
1886 }
1887
Romain Guyea835032011-07-28 19:24:37 -07001888 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1889 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890
Chet Haase61158c62011-09-06 22:19:45 -07001891 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001892 if (!skipDraw || mReportNextDraw) {
1893 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1894 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1895 mPendingTransitions.get(i).startChangingAnimations();
1896 }
1897 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001898 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001899
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001900 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001903 if (viewVisibility == View.VISIBLE) {
1904 // Try again
1905 scheduleTraversals();
1906 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001907 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1908 mPendingTransitions.get(i).endChangingAnimations();
1909 }
1910 mPendingTransitions.clear();
1911 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001913
1914 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 }
1916
Romain Guy3696779b2013-01-28 14:04:07 -08001917 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
1918 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1919 try {
1920 if (!mWindowSession.outOfMemory(mWindow) &&
1921 Process.myUid() != Process.SYSTEM_UID) {
1922 Slog.w(TAG, "No processes killed for memory; killing self");
1923 Process.killProcess(Process.myPid());
1924 }
1925 } catch (RemoteException ex) {
1926 }
1927 mLayoutRequested = true; // ask wm for a new surface next time.
1928 }
1929
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001930 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1931 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1932 try {
1933 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1934 } finally {
1935 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1936 }
1937 }
1938
Chet Haase97140572012-09-13 14:56:47 -07001939 /**
1940 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
1941 * is currently undergoing a layout pass.
1942 *
1943 * @return whether the view hierarchy is currently undergoing a layout pass
1944 */
1945 boolean isInLayout() {
1946 return mInLayout;
1947 }
1948
1949 /**
Chet Haasecc699b42012-12-13 09:06:55 -08001950 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
1951 * undergoing a layout pass. requestLayout() should not generally be called during layout,
1952 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
1953 * all children in that container hierarchy are measured and laid out at the end of the layout
1954 * pass for that container). If requestLayout() is called anyway, we handle it correctly
1955 * by registering all requesters during a frame as it proceeds. At the end of the frame,
1956 * we check all of those views to see if any still have pending layout requests, which
1957 * indicates that they were not correctly handled by their container hierarchy. If that is
1958 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
1959 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07001960 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08001961 * requests to the next frame to avoid possible infinite loops.
1962 *
1963 * <p>The return value from this method indicates whether the request should proceed
1964 * (if it is a request during the first layout pass) or should be skipped and posted to the
1965 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07001966 *
1967 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08001968 *
1969 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07001970 */
Chet Haasecc699b42012-12-13 09:06:55 -08001971 boolean requestLayoutDuringLayout(final View view) {
1972 if (view.mParent == null || view.mAttachInfo == null) {
1973 // Would not normally trigger another layout, so just let it pass through as usual
1974 return true;
1975 }
Chet Haase107a4822013-03-13 06:46:50 -07001976 if (!mLayoutRequesters.contains(view)) {
1977 mLayoutRequesters.add(view);
1978 }
Chet Haase97140572012-09-13 14:56:47 -07001979 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07001980 // Let the request proceed normally; it will be processed in a second layout pass
1981 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08001982 return true;
Chet Haase97140572012-09-13 14:56:47 -07001983 } else {
Chet Haase107a4822013-03-13 06:46:50 -07001984 // Don't let the request proceed during the second layout pass.
1985 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08001986 return false;
Chet Haase97140572012-09-13 14:56:47 -07001987 }
1988 }
1989
Chet Haase3efa7b52012-12-03 08:33:17 -08001990 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
1991 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001992 mLayoutRequested = false;
1993 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07001994 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001995
1996 final View host = mView;
1997 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1998 Log.v(TAG, "Laying out " + host + " to (" +
1999 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2000 }
2001
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002002 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2003 try {
2004 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002005
Chet Haased5a83522012-11-21 16:24:44 -08002006 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002007 int numViewsRequestingLayout = mLayoutRequesters.size();
2008 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002009 // requestLayout() was called during layout.
2010 // If no layout-request flags are set on the requesting views, there is no problem.
2011 // If some requests are still pending, then we need to clear those flags and do
2012 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002013 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2014 false);
2015 if (validLayoutRequesters != null) {
2016 // Set this flag to indicate that any further requests are happening during
2017 // the second pass, which may result in posting those requests to the next
2018 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002019 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002020
2021 // Process fresh layout requests, then measure and layout
2022 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002023 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002024 final View view = validLayoutRequesters.get(i);
2025 Log.w("View", "requestLayout() improperly called by " + view +
2026 " during layout: running second layout pass");
2027 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002028 }
2029 measureHierarchy(host, lp, mView.getContext().getResources(),
2030 desiredWindowWidth, desiredWindowHeight);
2031 mInLayout = true;
2032 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002033
Chet Haasecc699b42012-12-13 09:06:55 -08002034 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002035
2036 // Check the valid requests again, this time without checking/clearing the
2037 // layout flags, since requests happening during the second pass get noop'd
2038 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2039 if (validLayoutRequesters != null) {
2040 final ArrayList<View> finalRequesters = validLayoutRequesters;
2041 // Post second-pass requests to the next frame
2042 getRunQueue().post(new Runnable() {
2043 @Override
2044 public void run() {
2045 int numValidRequests = finalRequesters.size();
2046 for (int i = 0; i < numValidRequests; ++i) {
2047 final View view = finalRequesters.get(i);
2048 Log.w("View", "requestLayout() improperly called by " + view +
2049 " during second layout pass: posting in next frame");
2050 view.requestLayout();
2051 }
2052 }
2053 });
2054 }
Chet Haasecc699b42012-12-13 09:06:55 -08002055 }
Chet Haase107a4822013-03-13 06:46:50 -07002056
Chet Haase97140572012-09-13 14:56:47 -07002057 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002058 } finally {
2059 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2060 }
Chet Haase97140572012-09-13 14:56:47 -07002061 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002062 }
2063
Chet Haase107a4822013-03-13 06:46:50 -07002064 /**
2065 * This method is called during layout when there have been calls to requestLayout() during
2066 * layout. It walks through the list of views that requested layout to determine which ones
2067 * still need it, based on visibility in the hierarchy and whether they have already been
2068 * handled (as is usually the case with ListView children).
2069 *
2070 * @param layoutRequesters The list of views that requested layout during layout
2071 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2072 * If so, the FORCE_LAYOUT flag was not set on requesters.
2073 * @return A list of the actual views that still need to be laid out.
2074 */
2075 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2076 boolean secondLayoutRequests) {
2077
2078 int numViewsRequestingLayout = layoutRequesters.size();
2079 ArrayList<View> validLayoutRequesters = null;
2080 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2081 View view = layoutRequesters.get(i);
2082 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2083 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2084 View.PFLAG_FORCE_LAYOUT)) {
2085 boolean gone = false;
2086 View parent = view;
2087 // Only trigger new requests for views in a non-GONE hierarchy
2088 while (parent != null) {
2089 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2090 gone = true;
2091 break;
2092 }
2093 if (parent.mParent instanceof View) {
2094 parent = (View) parent.mParent;
2095 } else {
2096 parent = null;
2097 }
2098 }
2099 if (!gone) {
2100 if (validLayoutRequesters == null) {
2101 validLayoutRequesters = new ArrayList<View>();
2102 }
2103 validLayoutRequesters.add(view);
2104 }
2105 }
2106 }
2107 if (!secondLayoutRequests) {
2108 // If we're checking the layout flags, then we need to clean them up also
2109 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2110 View view = layoutRequesters.get(i);
2111 while (view != null &&
2112 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2113 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2114 if (view.mParent instanceof View) {
2115 view = (View) view.mParent;
2116 } else {
2117 view = null;
2118 }
2119 }
2120 }
2121 }
2122 layoutRequesters.clear();
2123 return validLayoutRequesters;
2124 }
2125
Igor Murashkina86ab6402013-08-30 12:58:36 -07002126 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 public void requestTransparentRegion(View child) {
2128 // the test below should not fail unless someone is messing with us
2129 checkThread();
2130 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002131 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 // Need to make sure we re-evaluate the window attributes next
2133 // time around, to ensure the window has the correct format.
2134 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002135 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002136 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 }
2138 }
2139
2140 /**
2141 * Figures out the measure spec for the root view in a window based on it's
2142 * layout params.
2143 *
2144 * @param windowSize
2145 * The available width or height of the window
2146 *
2147 * @param rootDimension
2148 * The layout params for one dimension (width or height) of the
2149 * window.
2150 *
2151 * @return The measure spec to use to measure the root view.
2152 */
Romain Guya998dff2012-03-23 18:58:36 -07002153 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 int measureSpec;
2155 switch (rootDimension) {
2156
Romain Guy980a9382010-01-08 15:06:28 -08002157 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 // Window can't resize. Force root view to be windowSize.
2159 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2160 break;
2161 case ViewGroup.LayoutParams.WRAP_CONTENT:
2162 // Window can resize. Set max size for root view.
2163 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2164 break;
2165 default:
2166 // Window wants to be an exact size. Force root view to be that size.
2167 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2168 break;
2169 }
2170 return measureSpec;
2171 }
2172
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002173 int mHardwareYOffset;
2174 int mResizeAlpha;
2175 final Paint mResizePaint = new Paint();
2176
Igor Murashkina86ab6402013-08-30 12:58:36 -07002177 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002178 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002179 canvas.translate(0, -mHardwareYOffset);
2180 }
2181
Igor Murashkina86ab6402013-08-30 12:58:36 -07002182 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002183 public void onHardwarePostDraw(HardwareCanvas canvas) {
John Reckcec24ae2013-11-05 13:27:50 -08002184// if (mResizeBuffer != null) {
2185// mResizePaint.setAlpha(mResizeAlpha);
2186// canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
2187// }
2188 // TODO: this
2189 if (!HardwareRenderer.sUseRenderThread) {
2190 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002191 }
2192 }
2193
Chet Haaseed30fd82011-04-22 16:18:45 -07002194 /**
2195 * @hide
2196 */
2197 void outputDisplayList(View view) {
John Reck63049192013-12-10 15:22:01 -08002198 DisplayList displayList = view.getDisplayList();
2199 if (displayList != null) {
2200 displayList.output();
2201 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002202 }
2203
2204 /**
2205 * @see #PROPERTY_PROFILE_RENDERING
2206 */
2207 private void profileRendering(boolean enabled) {
2208 if (mProfileRendering) {
2209 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002210
2211 if (mRenderProfiler != null) {
2212 mChoreographer.removeFrameCallback(mRenderProfiler);
2213 }
2214 if (mRenderProfilingEnabled) {
2215 if (mRenderProfiler == null) {
2216 mRenderProfiler = new Choreographer.FrameCallback() {
2217 @Override
2218 public void doFrame(long frameTimeNanos) {
2219 mDirty.set(0, 0, mWidth, mHeight);
2220 scheduleTraversals();
2221 if (mRenderProfilingEnabled) {
2222 mChoreographer.postFrameCallback(mRenderProfiler);
2223 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002224 }
Chris Craikae4f32042013-02-07 12:57:10 -08002225 };
2226 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002227 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002228 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002229 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002230 }
2231 }
2232 }
2233
Chet Haase2f2022a2011-10-11 06:41:59 -07002234 /**
2235 * Called from draw() when DEBUG_FPS is enabled
2236 */
2237 private void trackFPS() {
2238 // Tracks frames per second drawn. First value in a series of draws may be bogus
2239 // because it down not account for the intervening idle time
2240 long nowTime = System.currentTimeMillis();
2241 if (mFpsStartTime < 0) {
2242 mFpsStartTime = mFpsPrevTime = nowTime;
2243 mFpsNumFrames = 0;
2244 } else {
2245 ++mFpsNumFrames;
2246 String thisHash = Integer.toHexString(System.identityHashCode(this));
2247 long frameTime = nowTime - mFpsPrevTime;
2248 long totalTime = nowTime - mFpsStartTime;
2249 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2250 mFpsPrevTime = nowTime;
2251 if (totalTime > 1000) {
2252 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2253 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2254 mFpsStartTime = nowTime;
2255 mFpsNumFrames = 0;
2256 }
2257 }
2258 }
2259
Jeff Brown96e942d2011-11-30 19:55:01 -08002260 private void performDraw() {
Craig Mautner006f0e42012-03-21 11:00:32 -07002261 if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2262 return;
2263 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002264
Jeff Brown96e942d2011-11-30 19:55:01 -08002265 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2266 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002267
Romain Guy1f59e5c2012-05-06 14:11:16 -07002268 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002269 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2270 try {
2271 draw(fullRedrawNeeded);
2272 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002273 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002274 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2275 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002276
Jeff Brown96e942d2011-11-30 19:55:01 -08002277 if (mReportNextDraw) {
2278 mReportNextDraw = false;
2279
2280 if (LOCAL_LOGV) {
2281 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2282 }
2283 if (mSurfaceHolder != null && mSurface.isValid()) {
2284 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2285 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2286 if (callbacks != null) {
2287 for (SurfaceHolder.Callback c : callbacks) {
2288 if (c instanceof SurfaceHolder.Callback2) {
2289 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2290 mSurfaceHolder);
2291 }
2292 }
2293 }
2294 }
2295 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002296 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002297 } catch (RemoteException e) {
2298 }
2299 }
2300 }
2301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002302 private void draw(boolean fullRedrawNeeded) {
2303 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002304 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002305 return;
2306 }
2307
Chet Haase2f2022a2011-10-11 06:41:59 -07002308 if (DEBUG_FPS) {
2309 trackFPS();
2310 }
2311
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002312 if (!sFirstDrawComplete) {
2313 synchronized (sFirstDrawHandlers) {
2314 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002315 final int count = sFirstDrawHandlers.size();
2316 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002317 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002318 }
2319 }
2320 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 scrollToRectOrFocus(null, false);
2323
Romain Guy25eba5c2012-04-04 17:29:03 -07002324 final AttachInfo attachInfo = mAttachInfo;
2325 if (attachInfo.mViewScrollChanged) {
2326 attachInfo.mViewScrollChanged = false;
2327 attachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002328 }
Romain Guy8506ab42009-06-11 17:35:47 -07002329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002330 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002331 boolean animating = mScroller != null && mScroller.computeScrollOffset();
2332 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002333 yoff = mScroller.getCurrY();
2334 } else {
2335 yoff = mScrollY;
2336 }
2337 if (mCurScrollY != yoff) {
2338 mCurScrollY = yoff;
2339 fullRedrawNeeded = true;
2340 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002341
Romain Guy25eba5c2012-04-04 17:29:03 -07002342 final float appScale = attachInfo.mApplicationScale;
2343 final boolean scalingRequired = attachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002345 int resizeAlpha = 0;
John Reckcec24ae2013-11-05 13:27:50 -08002346// if (mResizeBuffer != null) {
2347// long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2348// if (deltaTime < mResizeBufferDuration) {
2349// float amt = deltaTime/(float) mResizeBufferDuration;
2350// amt = mResizeInterpolator.getInterpolation(amt);
2351// animating = true;
2352// resizeAlpha = 255 - (int)(amt*255);
2353// } else {
2354// disposeResizeBuffer();
2355// }
2356// }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002357
Jeff Brown96e942d2011-11-30 19:55:01 -08002358 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002359 if (mSurfaceHolder != null) {
2360 // The app owns the surface, we won't draw.
2361 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002362 if (animating) {
2363 if (mScroller != null) {
2364 mScroller.abortAnimation();
2365 }
John Reckcec24ae2013-11-05 13:27:50 -08002366// disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002367 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002368 return;
2369 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002370
2371 if (fullRedrawNeeded) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002372 attachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002373 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002374 }
Chet Haasead4f7032011-06-22 09:18:31 -07002375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002376 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002377 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002378 + mWindowAttributes.getTitle()
2379 + ": dirty={" + dirty.left + "," + dirty.top
2380 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002381 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2382 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 }
2384
Romain Guyfbb93fa2012-12-03 18:50:35 -08002385 invalidateDisplayLists();
2386
Romain Guy25eba5c2012-04-04 17:29:03 -07002387 attachInfo.mTreeObserver.dispatchOnDraw();
2388
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002389 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002390 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002391 // Draw with hardware renderer.
2392 mIsAnimating = false;
2393 mHardwareYOffset = yoff;
2394 mResizeAlpha = resizeAlpha;
Romain Guyfea12b82011-01-27 15:36:40 -08002395
Jeff Brown96e942d2011-11-30 19:55:01 -08002396 mCurrentDirty.set(dirty);
Jeff Brown96e942d2011-11-30 19:55:01 -08002397 dirty.setEmpty();
2398
Romain Guye55945e2013-04-04 15:26:04 -07002399 attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
2400 animating ? null : mCurrentDirty);
Romain Guy3696779b2013-01-28 14:04:07 -08002401 } else {
2402 // If we get here with a disabled & requested hardware renderer, something went
2403 // wrong (an invalidate posted right before we destroyed the hardware surface
2404 // for instance) so we should just bail out. Locking the surface with software
2405 // rendering at this point would lock it forever and prevent hardware renderer
2406 // from doing its job when it comes back.
2407 // Before we request a new frame we must however attempt to reinitiliaze the
2408 // hardware renderer if it's in requested state. This would happen after an
2409 // eglTerminate() for instance.
2410 if (attachInfo.mHardwareRenderer != null &&
2411 !attachInfo.mHardwareRenderer.isEnabled() &&
2412 attachInfo.mHardwareRenderer.isRequested()) {
2413
2414 try {
2415 attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
John Reck79d81e62013-11-05 13:26:57 -08002416 mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002417 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002418 handleOutOfResourcesException(e);
2419 return;
2420 }
2421
2422 mFullRedrawNeeded = true;
2423 scheduleTraversals();
2424 return;
2425 }
2426
2427 if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2428 return;
2429 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002431 }
Romain Guy8506ab42009-06-11 17:35:47 -07002432
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002433 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 mFullRedrawNeeded = true;
2435 scheduleTraversals();
2436 }
2437 }
2438
Romain Guy25eba5c2012-04-04 17:29:03 -07002439 /**
Romain Guyedbca122012-04-04 18:25:53 -07002440 * @return true if drawing was succesfull, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002441 */
2442 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2443 boolean scalingRequired, Rect dirty) {
2444
2445 // Draw with software renderer.
2446 Canvas canvas;
2447 try {
2448 int left = dirty.left;
2449 int top = dirty.top;
2450 int right = dirty.right;
2451 int bottom = dirty.bottom;
2452
Romain Guy25eba5c2012-04-04 17:29:03 -07002453 canvas = mSurface.lockCanvas(dirty);
2454
Romain Guye55945e2013-04-04 15:26:04 -07002455 // The dirty rectangle can be modified by Surface.lockCanvas()
2456 //noinspection ConstantConditions
Romain Guy25eba5c2012-04-04 17:29:03 -07002457 if (left != dirty.left || top != dirty.top || right != dirty.right ||
2458 bottom != dirty.bottom) {
2459 attachInfo.mIgnoreDirtyState = true;
2460 }
2461
2462 // TODO: Do this in native
2463 canvas.setDensity(mDensity);
2464 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002465 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002466 return false;
2467 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002468 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002469 // Don't assume this is due to out of memory, it could be
2470 // something else, and if it is something else then we could
2471 // kill stuff (or ourself) for no reason.
2472 mLayoutRequested = true; // ask wm for a new surface next time.
2473 return false;
2474 }
2475
2476 try {
2477 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2478 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2479 + canvas.getWidth() + ", h=" + canvas.getHeight());
2480 //canvas.drawARGB(255, 255, 0, 0);
2481 }
2482
Romain Guy25eba5c2012-04-04 17:29:03 -07002483 // If this bitmap's format includes an alpha channel, we
2484 // need to clear it before drawing so that the child will
2485 // properly re-composite its drawing on a transparent
2486 // background. This automatically respects the clip/dirty region
2487 // or
2488 // If we are applying an offset, we need to clear the area
2489 // where the offset doesn't appear to avoid having garbage
2490 // left in the blank areas.
2491 if (!canvas.isOpaque() || yoff != 0) {
2492 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2493 }
2494
2495 dirty.setEmpty();
2496 mIsAnimating = false;
2497 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002498 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002499
2500 if (DEBUG_DRAW) {
2501 Context cxt = mView.getContext();
2502 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2503 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2504 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2505 }
2506 try {
2507 canvas.translate(0, -yoff);
2508 if (mTranslator != null) {
2509 mTranslator.translateCanvas(canvas);
2510 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002511 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002512 attachInfo.mSetIgnoreDirtyState = false;
2513
Romain Guy25eba5c2012-04-04 17:29:03 -07002514 mView.draw(canvas);
2515
Svetoslav Ganov42138042012-03-20 11:51:39 -07002516 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002517 } finally {
2518 if (!attachInfo.mSetIgnoreDirtyState) {
2519 // Only clear the flag if it was not set during the mView.draw() call
2520 attachInfo.mIgnoreDirtyState = false;
2521 }
2522 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002523 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002524 try {
2525 surface.unlockCanvasAndPost(canvas);
2526 } catch (IllegalArgumentException e) {
2527 Log.e(TAG, "Could not unlock surface", e);
2528 mLayoutRequested = true; // ask wm for a new surface next time.
2529 //noinspection ReturnInsideFinallyBlock
2530 return false;
2531 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002532
Romain Guy25eba5c2012-04-04 17:29:03 -07002533 if (LOCAL_LOGV) {
2534 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2535 }
2536 }
2537 return true;
2538 }
2539
Svetoslav Ganov42138042012-03-20 11:51:39 -07002540 /**
2541 * We want to draw a highlight around the current accessibility focused.
2542 * Since adding a style for all possible view is not a viable option we
2543 * have this specialized drawing method.
2544 *
2545 * Note: We are doing this here to be able to draw the highlight for
2546 * virtual views in addition to real ones.
2547 *
2548 * @param canvas The canvas on which to draw.
2549 */
2550 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
Alan Viverette8232eb92013-09-26 15:15:08 -07002551 if (!mAttachInfo.mHasWindowFocus) {
2552 return;
2553 }
2554
2555 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
Svetoslav Ganov07b726c2012-04-30 12:24:57 -07002556 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002557 return;
2558 }
Alan Viverette8232eb92013-09-26 15:15:08 -07002559
2560 final View host = mAccessibilityFocusedHost;
2561 if (host == null || host.mAttachInfo == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002562 return;
2563 }
Alan Viverette8232eb92013-09-26 15:15:08 -07002564
2565 final Drawable drawable = getAccessibilityFocusedDrawable();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002566 if (drawable == null) {
2567 return;
2568 }
Alan Viverette8232eb92013-09-26 15:15:08 -07002569
2570 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
2571 final Rect bounds = mView.mAttachInfo.mTmpInvalRect;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002572 if (provider == null) {
Alan Viverette8232eb92013-09-26 15:15:08 -07002573 host.getBoundsOnScreen(bounds);
2574 } else if (mAccessibilityFocusedVirtualView != null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002575 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
Alan Viverette8232eb92013-09-26 15:15:08 -07002576 } else {
2577 return;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002578 }
Alan Viverette8232eb92013-09-26 15:15:08 -07002579
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002580 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Svetoslav Ganova94c3192012-10-31 18:28:49 -07002581 bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002582 drawable.setBounds(bounds);
2583 drawable.draw(canvas);
2584 }
2585
2586 private Drawable getAccessibilityFocusedDrawable() {
2587 if (mAttachInfo != null) {
2588 // Lazily load the accessibility focus drawable.
2589 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2590 TypedValue value = new TypedValue();
2591 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2592 R.attr.accessibilityFocusedDrawable, value, true);
2593 if (resolved) {
2594 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002595 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002596 }
2597 }
2598 return mAttachInfo.mAccessibilityFocusDrawable;
2599 }
2600 return null;
2601 }
2602
Romain Guy51e4d4d2012-03-15 18:30:47 -07002603 void invalidateDisplayLists() {
2604 final ArrayList<DisplayList> displayLists = mDisplayLists;
2605 final int count = displayLists.size();
2606
2607 for (int i = 0; i < count; i++) {
Romain Guy38c2ece2012-05-24 14:20:56 -07002608 final DisplayList displayList = displayLists.get(i);
Romain Guyfbb93fa2012-12-03 18:50:35 -08002609 if (displayList.isDirty()) {
Romain Guy46bfc482013-08-16 18:38:29 -07002610 displayList.reset();
Romain Guyfbb93fa2012-12-03 18:50:35 -08002611 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07002612 }
2613
2614 displayLists.clear();
2615 }
2616
Michael Jurkaf42d90102013-05-08 18:00:04 +02002617 /**
2618 * @hide
2619 */
2620 public void setDrawDuringWindowsAnimating(boolean value) {
2621 mDrawDuringWindowsAnimating = value;
2622 if (value) {
2623 handleDispatchDoneAnimating();
2624 }
2625 }
2626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002627 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2628 final View.AttachInfo attachInfo = mAttachInfo;
2629 final Rect ci = attachInfo.mContentInsets;
2630 final Rect vi = attachInfo.mVisibleInsets;
2631 int scrollY = 0;
2632 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002634 if (vi.left > ci.left || vi.top > ci.top
2635 || vi.right > ci.right || vi.bottom > ci.bottom) {
2636 // We'll assume that we aren't going to change the scroll
2637 // offset, since we want to avoid that unless it is actually
2638 // going to make the focus visible... otherwise we scroll
2639 // all over the place.
2640 scrollY = mScrollY;
2641 // We can be called for two different situations: during a draw,
2642 // to update the scroll position if the focus has changed (in which
2643 // case 'rectangle' is null), or in response to a
2644 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2645 // is non-null and we just want to scroll to whatever that
2646 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002647 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002648 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002649 return false;
2650 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002651 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002652 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002653 // If the focus has changed, then ignore any requests to scroll
2654 // to a rectangle; first we want to make sure the entire focus
2655 // view is visible.
2656 rectangle = null;
2657 }
2658 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2659 + " rectangle=" + rectangle + " ci=" + ci
2660 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002661 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 // Optimization: if the focus hasn't changed since last
2663 // time, and no layout has happened, then just leave things
2664 // as they are.
2665 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2666 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002667 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002668 // We need to determine if the currently focused view is
2669 // within the visible part of the window and, if not, apply
2670 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002671 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672 mScrollMayChange = false;
2673 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2674 // Try to find the rectangle from the focus view.
2675 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2676 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2677 + mView.getWidth() + " h=" + mView.getHeight()
2678 + " ci=" + ci.toShortString()
2679 + " vi=" + vi.toShortString());
2680 if (rectangle == null) {
2681 focus.getFocusedRect(mTempRect);
2682 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2683 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002684 if (mView instanceof ViewGroup) {
2685 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2686 focus, mTempRect);
2687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2689 "Focus in window: focusRect="
2690 + mTempRect.toShortString()
2691 + " visRect=" + mVisRect.toShortString());
2692 } else {
2693 mTempRect.set(rectangle);
2694 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2695 "Request scroll to rect: "
2696 + mTempRect.toShortString()
2697 + " visRect=" + mVisRect.toShortString());
2698 }
2699 if (mTempRect.intersect(mVisRect)) {
2700 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2701 "Focus window visible rect: "
2702 + mTempRect.toShortString());
2703 if (mTempRect.height() >
2704 (mView.getHeight()-vi.top-vi.bottom)) {
2705 // If the focus simply is not going to fit, then
2706 // best is probably just to leave things as-is.
2707 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2708 "Too tall; leaving scrollY=" + scrollY);
2709 } else if ((mTempRect.top-scrollY) < vi.top) {
2710 scrollY -= vi.top - (mTempRect.top-scrollY);
2711 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2712 "Top covered; scrollY=" + scrollY);
2713 } else if ((mTempRect.bottom-scrollY)
2714 > (mView.getHeight()-vi.bottom)) {
2715 scrollY += (mTempRect.bottom-scrollY)
2716 - (mView.getHeight()-vi.bottom);
2717 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2718 "Bottom covered; scrollY=" + scrollY);
2719 }
2720 handled = true;
2721 }
2722 }
2723 }
2724 }
Romain Guy8506ab42009-06-11 17:35:47 -07002725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 if (scrollY != mScrollY) {
2727 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2728 + mScrollY + " , new=" + scrollY);
John Reckcec24ae2013-11-05 13:27:50 -08002729 if (!immediate /*&& mResizeBuffer == null*/) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 if (mScroller == null) {
2731 mScroller = new Scroller(mView.getContext());
2732 }
2733 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2734 } else if (mScroller != null) {
2735 mScroller.abortAnimation();
2736 }
2737 mScrollY = scrollY;
2738 }
Romain Guy8506ab42009-06-11 17:35:47 -07002739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 return handled;
2741 }
Romain Guy8506ab42009-06-11 17:35:47 -07002742
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002743 /**
2744 * @hide
2745 */
2746 public View getAccessibilityFocusedHost() {
2747 return mAccessibilityFocusedHost;
2748 }
2749
2750 /**
2751 * @hide
2752 */
2753 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2754 return mAccessibilityFocusedVirtualView;
2755 }
2756
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002757 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002758 // If we have a virtual view with accessibility focus we need
2759 // to clear the focus and invalidate the virtual view bounds.
2760 if (mAccessibilityFocusedVirtualView != null) {
2761
2762 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2763 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002764
2765 // Wipe the state of the current accessibility focus since
2766 // the call into the provider to clear accessibility focus
2767 // will fire an accessibility event which will end up calling
2768 // this method and we want to have clean state when this
2769 // invocation happens.
2770 mAccessibilityFocusedHost = null;
2771 mAccessibilityFocusedVirtualView = null;
2772
Alan Viverette239a0c02013-05-07 17:17:35 -07002773 // Clear accessibility focus on the host after clearing state since
2774 // this method may be reentrant.
2775 focusHost.clearAccessibilityFocusNoCallbacks();
2776
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002777 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2778 if (provider != null) {
2779 // Invalidate the area of the cleared accessibility focus.
2780 focusNode.getBoundsInParent(mTempRect);
2781 focusHost.invalidate(mTempRect);
2782 // Clear accessibility focus in the virtual node.
2783 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2784 focusNode.getSourceNodeId());
2785 provider.performAction(virtualNodeId,
2786 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2787 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002788 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002789 }
2790 if (mAccessibilityFocusedHost != null) {
2791 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002792 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2793 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002794
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002795 // Set the new focus host and node.
2796 mAccessibilityFocusedHost = view;
2797 mAccessibilityFocusedVirtualView = node;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002798 }
2799
Igor Murashkina86ab6402013-08-30 12:58:36 -07002800 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002802 if (DEBUG_INPUT_RESIZE) {
2803 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002804 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002805 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002806 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002807 }
2808
Igor Murashkina86ab6402013-08-30 12:58:36 -07002809 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002810 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002811 if (DEBUG_INPUT_RESIZE) {
2812 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002813 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002814 checkThread();
2815 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002816 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002817
Svetoslav Ganov42138042012-03-20 11:51:39 -07002818 @Override
2819 public ViewParent getParentForAccessibility() {
2820 return null;
2821 }
2822
Igor Murashkina86ab6402013-08-30 12:58:36 -07002823 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 public void focusableViewAvailable(View v) {
2825 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002826 if (mView != null) {
2827 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002828 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002829 } else {
2830 // the one case where will transfer focus away from the current one
2831 // is if the current view is a view group that prefers to give focus
2832 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002833 View focused = mView.findFocus();
2834 if (focused instanceof ViewGroup) {
2835 ViewGroup group = (ViewGroup) focused;
2836 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2837 && isViewDescendantOf(v, focused)) {
2838 v.requestFocus();
2839 }
Romain Guy1c90f032011-05-24 14:59:50 -07002840 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002841 }
2842 }
2843 }
2844
Igor Murashkina86ab6402013-08-30 12:58:36 -07002845 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002846 public void recomputeViewAttributes(View child) {
2847 checkThread();
2848 if (mView == child) {
2849 mAttachInfo.mRecomputeGlobalAttributes = true;
2850 if (!mWillDrawSoon) {
2851 scheduleTraversals();
2852 }
2853 }
2854 }
2855
2856 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002857 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002858 if (mAttachInfo.mHardwareRenderer != null &&
2859 mAttachInfo.mHardwareRenderer.isEnabled()) {
2860 mAttachInfo.mHardwareRenderer.validate();
2861 }
Dianne Hackborn961cae92013-03-20 14:59:43 -07002862 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 mView.dispatchDetachedFromWindow();
2864 }
2865
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002866 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2867 mAccessibilityManager.removeAccessibilityStateChangeListener(
2868 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002869 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002870
Romain Guya998dff2012-03-23 18:58:36 -07002871 destroyHardwareRenderer();
2872
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002873 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002874
Craig Mautner8f303ad2013-06-14 11:32:22 -07002875 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 mView = null;
2877 mAttachInfo.mRootView = null;
2878
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002879 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880
Jeff Browncc4f7db2011-08-30 20:34:48 -07002881 if (mInputQueueCallback != null && mInputQueue != null) {
2882 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002883 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002884 mInputQueueCallback = null;
2885 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002886 }
2887 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002888 mInputEventReceiver.dispose();
2889 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002892 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002893 } catch (RemoteException e) {
2894 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07002895
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002896 // Dispose the input channel after removing the window so the Window Manager
2897 // doesn't interpret the input channel being closed as an abnormal termination.
2898 if (mInputChannel != null) {
2899 mInputChannel.dispose();
2900 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002901 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002902
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002903 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002904 }
Romain Guy8506ab42009-06-11 17:35:47 -07002905
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002906 void updateConfiguration(Configuration config, boolean force) {
2907 if (DEBUG_CONFIGURATION) Log.v(TAG,
2908 "Applying new config to window "
2909 + mWindowAttributes.getTitle()
2910 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002911
Craig Mautner48d0d182013-06-11 07:53:06 -07002912 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
2913 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002914 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002915 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002916 }
2917
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002918 synchronized (sConfigCallbacks) {
2919 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2920 sConfigCallbacks.get(i).onConfigurationChanged(config);
2921 }
2922 }
2923 if (mView != null) {
2924 // At this point the resources have been updated to
2925 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002926 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002927 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002928 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002929 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2930 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002931 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07002932 if (lastLayoutDirection != currentLayoutDirection &&
2933 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002934 mView.setLayoutDirection(currentLayoutDirection);
2935 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002936 mView.dispatchConfigurationChanged(config);
2937 }
2938 }
Michael Wright4567e402013-08-16 15:08:35 -07002939
2940 mFlipControllerFallbackKeys =
2941 mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002942 }
Michael Wright4567e402013-08-16 15:08:35 -07002943
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002944 /**
2945 * Return true if child is an ancestor of parent, (or equal to the parent).
2946 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002947 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 if (child == parent) {
2949 return true;
2950 }
2951
2952 final ViewParent theParent = child.getParent();
2953 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2954 }
2955
Romain Guycdb86672010-03-18 18:54:50 -07002956 private static void forceLayout(View view) {
2957 view.forceLayout();
2958 if (view instanceof ViewGroup) {
2959 ViewGroup group = (ViewGroup) view;
2960 final int count = group.getChildCount();
2961 for (int i = 0; i < count; i++) {
2962 forceLayout(group.getChildAt(i));
2963 }
2964 }
2965 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966
Jeff Browna175a5b2012-02-15 19:18:31 -08002967 private final static int MSG_INVALIDATE = 1;
2968 private final static int MSG_INVALIDATE_RECT = 2;
2969 private final static int MSG_DIE = 3;
2970 private final static int MSG_RESIZED = 4;
2971 private final static int MSG_RESIZED_REPORT = 5;
2972 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07002973 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08002974 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2975 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08002976 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2977 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2978 private final static int MSG_CHECK_FOCUS = 13;
2979 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2980 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2981 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2982 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2983 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002984 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2985 private final static int MSG_DISPATCH_SCREEN_STATE = 20;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002986 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
2987 private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
2988 private final static int MSG_INVALIDATE_WORLD = 23;
2989 private final static int MSG_WINDOW_MOVED = 24;
Romain Guy40543602013-06-12 15:31:28 -07002990 private final static int MSG_FLUSH_LAYER_UPDATES = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991
Jeff Browna175a5b2012-02-15 19:18:31 -08002992 final class ViewRootHandler extends Handler {
2993 @Override
2994 public String getMessageName(Message message) {
2995 switch (message.what) {
2996 case MSG_INVALIDATE:
2997 return "MSG_INVALIDATE";
2998 case MSG_INVALIDATE_RECT:
2999 return "MSG_INVALIDATE_RECT";
3000 case MSG_DIE:
3001 return "MSG_DIE";
3002 case MSG_RESIZED:
3003 return "MSG_RESIZED";
3004 case MSG_RESIZED_REPORT:
3005 return "MSG_RESIZED_REPORT";
3006 case MSG_WINDOW_FOCUS_CHANGED:
3007 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003008 case MSG_DISPATCH_INPUT_EVENT:
3009 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003010 case MSG_DISPATCH_APP_VISIBILITY:
3011 return "MSG_DISPATCH_APP_VISIBILITY";
3012 case MSG_DISPATCH_GET_NEW_SURFACE:
3013 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003014 case MSG_DISPATCH_KEY_FROM_IME:
3015 return "MSG_DISPATCH_KEY_FROM_IME";
3016 case MSG_FINISH_INPUT_CONNECTION:
3017 return "MSG_FINISH_INPUT_CONNECTION";
3018 case MSG_CHECK_FOCUS:
3019 return "MSG_CHECK_FOCUS";
3020 case MSG_CLOSE_SYSTEM_DIALOGS:
3021 return "MSG_CLOSE_SYSTEM_DIALOGS";
3022 case MSG_DISPATCH_DRAG_EVENT:
3023 return "MSG_DISPATCH_DRAG_EVENT";
3024 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3025 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3026 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3027 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3028 case MSG_UPDATE_CONFIGURATION:
3029 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003030 case MSG_PROCESS_INPUT_EVENTS:
3031 return "MSG_PROCESS_INPUT_EVENTS";
Romain Guy51e4d4d2012-03-15 18:30:47 -07003032 case MSG_DISPATCH_SCREEN_STATE:
3033 return "MSG_DISPATCH_SCREEN_STATE";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003034 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3035 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003036 case MSG_DISPATCH_DONE_ANIMATING:
3037 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003038 case MSG_WINDOW_MOVED:
3039 return "MSG_WINDOW_MOVED";
Romain Guy40543602013-06-12 15:31:28 -07003040 case MSG_FLUSH_LAYER_UPDATES:
3041 return "MSG_FLUSH_LAYER_UPDATES";
Jeff Browna175a5b2012-02-15 19:18:31 -08003042 }
3043 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003044 }
Romain Guyf9284692011-07-13 18:46:21 -07003045
Jeff Browna175a5b2012-02-15 19:18:31 -08003046 @Override
3047 public void handleMessage(Message msg) {
3048 switch (msg.what) {
3049 case MSG_INVALIDATE:
3050 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003052 case MSG_INVALIDATE_RECT:
3053 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3054 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003055 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003056 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003057 case MSG_PROCESS_INPUT_EVENTS:
3058 mProcessInputEventsScheduled = false;
3059 doProcessInputEvents();
3060 break;
3061 case MSG_DISPATCH_APP_VISIBILITY:
3062 handleAppVisibility(msg.arg1 != 0);
3063 break;
3064 case MSG_DISPATCH_GET_NEW_SURFACE:
3065 handleGetNewSurface();
3066 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003067 case MSG_RESIZED: {
3068 // Recycled in the fall through...
3069 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003070 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003071 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003072 && mPendingContentInsets.equals(args.arg2)
3073 && mPendingVisibleInsets.equals(args.arg3)
3074 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003075 break;
Romain Guycdb86672010-03-18 18:54:50 -07003076 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003077 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003078 case MSG_RESIZED_REPORT:
3079 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003080 SomeArgs args = (SomeArgs) msg.obj;
3081
3082 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003083 if (config != null) {
3084 updateConfiguration(config, false);
3085 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003086
3087 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003088 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003089 mPendingContentInsets.set((Rect) args.arg2);
3090 mPendingVisibleInsets.set((Rect) args.arg3);
3091
3092 args.recycle();
3093
Jeff Browna175a5b2012-02-15 19:18:31 -08003094 if (msg.what == MSG_RESIZED_REPORT) {
3095 mReportNextDraw = true;
3096 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003097
Jeff Browna175a5b2012-02-15 19:18:31 -08003098 if (mView != null) {
3099 forceLayout(mView);
3100 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003101
Jeff Browna175a5b2012-02-15 19:18:31 -08003102 requestLayout();
3103 }
3104 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003105 case MSG_WINDOW_MOVED:
3106 if (mAdded) {
3107 final int w = mWinFrame.width();
3108 final int h = mWinFrame.height();
3109 final int l = msg.arg1;
3110 final int t = msg.arg2;
3111 mWinFrame.left = l;
3112 mWinFrame.right = l + w;
3113 mWinFrame.top = t;
3114 mWinFrame.bottom = t + h;
3115
3116 if (mView != null) {
3117 forceLayout(mView);
3118 }
3119 requestLayout();
3120 }
3121 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003122 case MSG_WINDOW_FOCUS_CHANGED: {
3123 if (mAdded) {
3124 boolean hasWindowFocus = msg.arg1 != 0;
3125 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126
Jeff Browna175a5b2012-02-15 19:18:31 -08003127 profileRendering(hasWindowFocus);
3128
3129 if (hasWindowFocus) {
3130 boolean inTouchMode = msg.arg2 != 0;
3131 ensureTouchModeLocally(inTouchMode);
3132
Romain Guye55945e2013-04-04 15:26:04 -07003133 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003134 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003135 try {
Romain Guy3696779b2013-01-28 14:04:07 -08003136 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
John Reck79d81e62013-11-05 13:26:57 -08003137 mWidth, mHeight, mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003138 } catch (OutOfResourcesException e) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003139 Log.e(TAG, "OutOfResourcesException locking surface", e);
3140 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003141 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003142 Slog.w(TAG, "No processes killed for memory; killing self");
3143 Process.killProcess(Process.myPid());
3144 }
3145 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003146 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003147 // Retry in a bit.
3148 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3149 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003150 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003151 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 }
Romain Guy8506ab42009-06-11 17:35:47 -07003153
Jeff Browna175a5b2012-02-15 19:18:31 -08003154 mLastWasImTarget = WindowManager.LayoutParams
3155 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003156
Jeff Browna175a5b2012-02-15 19:18:31 -08003157 InputMethodManager imm = InputMethodManager.peekInstance();
3158 if (mView != null) {
keunyoung30f420f2013-08-02 14:23:10 -07003159 if (hasWindowFocus && imm != null && mLastWasImTarget &&
3160 !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003161 imm.startGettingWindowFocus(mView);
3162 }
3163 mAttachInfo.mKeyDispatchState.reset();
3164 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003165 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003167
Jeff Browna175a5b2012-02-15 19:18:31 -08003168 // Note: must be done after the focus change callbacks,
3169 // so all of the view state is set up correctly.
3170 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003171 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003172 imm.onWindowFocus(mView, mView.findFocus(),
3173 mWindowAttributes.softInputMode,
3174 !mHasHadWindowFocus, mWindowAttributes.flags);
3175 }
3176 // Clear the forward bit. We can just do this directly, since
3177 // the window manager doesn't care about it.
3178 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003180 ((WindowManager.LayoutParams)mView.getLayoutParams())
3181 .softInputMode &=
3182 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3183 mHasHadWindowFocus = true;
3184 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003185
Svetoslav Ganov42138042012-03-20 11:51:39 -07003186 if (mView != null && mAccessibilityManager.isEnabled()) {
3187 if (hasWindowFocus) {
3188 mView.sendAccessibilityEvent(
3189 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003190 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003191 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003192 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003193 } break;
3194 case MSG_DIE:
3195 doDie();
3196 break;
keunyoung30f420f2013-08-02 14:23:10 -07003197 case MSG_DISPATCH_INPUT_EVENT: {
3198 InputEvent event = (InputEvent)msg.obj;
Jeff Browna175a5b2012-02-15 19:18:31 -08003199 enqueueInputEvent(event, null, 0, true);
3200 } break;
3201 case MSG_DISPATCH_KEY_FROM_IME: {
3202 if (LOCAL_LOGV) Log.v(
3203 TAG, "Dispatching key "
3204 + msg.obj + " from IME to " + mView);
3205 KeyEvent event = (KeyEvent)msg.obj;
3206 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3207 // The IME is trying to say this event is from the
3208 // system! Bad bad bad!
3209 //noinspection UnusedAssignment
3210 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
3211 }
3212 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3213 } break;
3214 case MSG_FINISH_INPUT_CONNECTION: {
3215 InputMethodManager imm = InputMethodManager.peekInstance();
3216 if (imm != null) {
3217 imm.reportFinishInputConnection((InputConnection)msg.obj);
3218 }
3219 } break;
3220 case MSG_CHECK_FOCUS: {
3221 InputMethodManager imm = InputMethodManager.peekInstance();
3222 if (imm != null) {
3223 imm.checkFocus();
3224 }
3225 } break;
3226 case MSG_CLOSE_SYSTEM_DIALOGS: {
3227 if (mView != null) {
3228 mView.onCloseSystemDialogs((String)msg.obj);
3229 }
3230 } break;
3231 case MSG_DISPATCH_DRAG_EVENT:
3232 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3233 DragEvent event = (DragEvent)msg.obj;
3234 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3235 handleDragEvent(event);
3236 } break;
3237 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003238 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003239 } break;
3240 case MSG_UPDATE_CONFIGURATION: {
3241 Configuration config = (Configuration)msg.obj;
3242 if (config.isOtherSeqNewer(mLastConfiguration)) {
3243 config = mLastConfiguration;
3244 }
3245 updateConfiguration(config, false);
3246 } break;
Romain Guybb9908b2012-03-08 11:14:07 -08003247 case MSG_DISPATCH_SCREEN_STATE: {
Romain Guy7e4e5612012-03-05 14:37:29 -08003248 if (mView != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08003249 handleScreenStateChange(msg.arg1 == 1);
Romain Guy7e4e5612012-03-05 14:37:29 -08003250 }
3251 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003252 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003253 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003254 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003255 case MSG_DISPATCH_DONE_ANIMATING: {
3256 handleDispatchDoneAnimating();
3257 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003258 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003259 if (mView != null) {
3260 invalidateWorld(mView);
3261 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003262 } break;
Romain Guy40543602013-06-12 15:31:28 -07003263 case MSG_FLUSH_LAYER_UPDATES: {
3264 flushHardwareLayerUpdates();
3265 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
3268 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003269
Jeff Browna175a5b2012-02-15 19:18:31 -08003270 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 /**
3273 * Something in the current window tells us we need to change the touch mode. For
3274 * example, we are not in touch mode, and the user touches the screen.
3275 *
3276 * If the touch mode has changed, tell the window manager, and handle it locally.
3277 *
3278 * @param inTouchMode Whether we want to be in touch mode.
3279 * @return True if the touch mode changed and focus changed was changed as a result
3280 */
3281 boolean ensureTouchMode(boolean inTouchMode) {
3282 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3283 + "touch mode is " + mAttachInfo.mInTouchMode);
3284 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3285
3286 // tell the window manager
3287 try {
keunyoung30f420f2013-08-02 14:23:10 -07003288 if (!isInLocalFocusMode()) {
3289 mWindowSession.setInTouchMode(inTouchMode);
3290 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003291 } catch (RemoteException e) {
3292 throw new RuntimeException(e);
3293 }
3294
3295 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003296 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 }
3298
3299 /**
3300 * Ensure that the touch mode for this window is set, and if it is changing,
3301 * take the appropriate action.
3302 * @param inTouchMode Whether we want to be in touch mode.
3303 * @return True if the touch mode changed and focus changed was changed as a result
3304 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003305 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3307 + "touch mode is " + mAttachInfo.mInTouchMode);
3308
3309 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3310
3311 mAttachInfo.mInTouchMode = inTouchMode;
3312 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3313
Romain Guy2d4cff62010-04-09 15:39:00 -07003314 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 }
3316
3317 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003318 if (mView != null && mView.hasFocus()) {
3319 // note: not relying on mFocusedView here because this could
3320 // be when the window is first being added, and mFocused isn't
3321 // set yet.
3322 final View focused = mView.findFocus();
3323 if (focused != null && !focused.isFocusableInTouchMode()) {
3324 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3325 if (ancestorToTakeFocus != null) {
3326 // there is an ancestor that wants focus after its
3327 // descendants that is focusable in touch mode.. give it
3328 // focus
3329 return ancestorToTakeFocus.requestFocus();
3330 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003331 // There's nothing to focus. Clear and propagate through the
3332 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08003333 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003334 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
3336 }
3337 }
3338 return false;
3339 }
3340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 /**
3342 * Find an ancestor of focused that wants focus after its descendants and is
3343 * focusable in touch mode.
3344 * @param focused The currently focused view.
3345 * @return An appropriate view, or null if no such view exists.
3346 */
Romain Guya998dff2012-03-23 18:58:36 -07003347 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003348 ViewParent parent = focused.getParent();
3349 while (parent instanceof ViewGroup) {
3350 final ViewGroup vgParent = (ViewGroup) parent;
3351 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3352 && vgParent.isFocusableInTouchMode()) {
3353 return vgParent;
3354 }
3355 if (vgParent.isRootNamespace()) {
3356 return null;
3357 } else {
3358 parent = vgParent.getParent();
3359 }
3360 }
3361 return null;
3362 }
3363
3364 private boolean leaveTouchMode() {
3365 if (mView != null) {
3366 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003367 View focusedView = mView.findFocus();
3368 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003370 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003371 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3373 // some view group has focus, and doesn't prefer its children
3374 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003375 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 }
3377 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003378
3379 // find the best view to give focus to in this brave new non-touch-mode
3380 // world
3381 final View focused = focusSearch(null, View.FOCUS_DOWN);
3382 if (focused != null) {
3383 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003384 }
3385 }
3386 return false;
3387 }
3388
Jeff Brownf9e989d2013-04-04 23:04:03 -07003389 /**
3390 * Base class for implementing a stage in the chain of responsibility
3391 * for processing input events.
3392 * <p>
3393 * Events are delivered to the stage by the {@link #deliver} method. The stage
3394 * then has the choice of finishing the event or forwarding it to the next stage.
3395 * </p>
3396 */
3397 abstract class InputStage {
3398 private final InputStage mNext;
3399
3400 protected static final int FORWARD = 0;
3401 protected static final int FINISH_HANDLED = 1;
3402 protected static final int FINISH_NOT_HANDLED = 2;
3403
3404 /**
3405 * Creates an input stage.
3406 * @param next The next stage to which events should be forwarded.
3407 */
3408 public InputStage(InputStage next) {
3409 mNext = next;
3410 }
3411
3412 /**
3413 * Delivers an event to be processed.
3414 */
3415 public final void deliver(QueuedInputEvent q) {
3416 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3417 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003418 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003419 finish(q, false);
3420 } else {
3421 apply(q, onProcess(q));
3422 }
3423 }
3424
3425 /**
3426 * Marks the the input event as finished then forwards it to the next stage.
3427 */
3428 protected void finish(QueuedInputEvent q, boolean handled) {
3429 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3430 if (handled) {
3431 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3432 }
3433 forward(q);
3434 }
3435
3436 /**
3437 * Forwards the event to the next stage.
3438 */
3439 protected void forward(QueuedInputEvent q) {
3440 onDeliverToNext(q);
3441 }
3442
3443 /**
3444 * Applies a result code from {@link #onProcess} to the specified event.
3445 */
3446 protected void apply(QueuedInputEvent q, int result) {
3447 if (result == FORWARD) {
3448 forward(q);
3449 } else if (result == FINISH_HANDLED) {
3450 finish(q, true);
3451 } else if (result == FINISH_NOT_HANDLED) {
3452 finish(q, false);
3453 } else {
3454 throw new IllegalArgumentException("Invalid result: " + result);
3455 }
3456 }
3457
3458 /**
3459 * Called when an event is ready to be processed.
3460 * @return A result code indicating how the event was handled.
3461 */
3462 protected int onProcess(QueuedInputEvent q) {
3463 return FORWARD;
3464 }
3465
3466 /**
3467 * Called when an event is being delivered to the next stage.
3468 */
3469 protected void onDeliverToNext(QueuedInputEvent q) {
3470 if (mNext != null) {
3471 mNext.deliver(q);
3472 } else {
3473 finishInputEvent(q);
3474 }
3475 }
Jeff Brown5182c782013-10-15 20:31:52 -07003476
Michael Wright17d28ca2013-10-31 17:47:45 -07003477 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3478 if (mView == null || !mAdded) {
3479 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3480 return true;
3481 } else if (!mAttachInfo.mHasWindowFocus &&
3482 !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
3483 !isTerminalInputEvent(q.mEvent)) {
3484 // If this is a focused event and the window doesn't currently have input focus,
3485 // then drop this event. This could be an event that came back from the previous
3486 // stage but the window has lost focus in the meantime.
3487 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
3488 return true;
3489 }
3490 return false;
3491 }
3492
Jeff Brown5182c782013-10-15 20:31:52 -07003493 void dump(String prefix, PrintWriter writer) {
3494 if (mNext != null) {
3495 mNext.dump(prefix, writer);
3496 }
3497 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003498 }
3499
3500 /**
3501 * Base class for implementing an input pipeline stage that supports
3502 * asynchronous and out-of-order processing of input events.
3503 * <p>
3504 * In addition to what a normal input stage can do, an asynchronous
3505 * input stage may also defer an input event that has been delivered to it
3506 * and finish or forward it later.
3507 * </p>
3508 */
3509 abstract class AsyncInputStage extends InputStage {
3510 private final String mTraceCounter;
3511
3512 private QueuedInputEvent mQueueHead;
3513 private QueuedInputEvent mQueueTail;
3514 private int mQueueLength;
3515
3516 protected static final int DEFER = 3;
3517
3518 /**
3519 * Creates an asynchronous input stage.
3520 * @param next The next stage to which events should be forwarded.
3521 * @param traceCounter The name of a counter to record the size of
3522 * the queue of pending events.
3523 */
3524 public AsyncInputStage(InputStage next, String traceCounter) {
3525 super(next);
3526 mTraceCounter = traceCounter;
3527 }
3528
3529 /**
3530 * Marks the event as deferred, which is to say that it will be handled
3531 * asynchronously. The caller is responsible for calling {@link #forward}
3532 * or {@link #finish} later when it is done handling the event.
3533 */
3534 protected void defer(QueuedInputEvent q) {
3535 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3536 enqueue(q);
3537 }
3538
3539 @Override
3540 protected void forward(QueuedInputEvent q) {
3541 // Clear the deferred flag.
3542 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3543
3544 // Fast path if the queue is empty.
3545 QueuedInputEvent curr = mQueueHead;
3546 if (curr == null) {
3547 super.forward(q);
3548 return;
3549 }
3550
3551 // Determine whether the event must be serialized behind any others
3552 // before it can be delivered to the next stage. This is done because
3553 // deferred events might be handled out of order by the stage.
3554 final int deviceId = q.mEvent.getDeviceId();
3555 QueuedInputEvent prev = null;
3556 boolean blocked = false;
3557 while (curr != null && curr != q) {
3558 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3559 blocked = true;
3560 }
3561 prev = curr;
3562 curr = curr.mNext;
3563 }
3564
3565 // If the event is blocked, then leave it in the queue to be delivered later.
3566 // Note that the event might not yet be in the queue if it was not previously
3567 // deferred so we will enqueue it if needed.
3568 if (blocked) {
3569 if (curr == null) {
3570 enqueue(q);
3571 }
3572 return;
3573 }
3574
3575 // The event is not blocked. Deliver it immediately.
3576 if (curr != null) {
3577 curr = curr.mNext;
3578 dequeue(q, prev);
3579 }
3580 super.forward(q);
3581
3582 // Dequeuing this event may have unblocked successors. Deliver them.
3583 while (curr != null) {
3584 if (deviceId == curr.mEvent.getDeviceId()) {
3585 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3586 break;
3587 }
3588 QueuedInputEvent next = curr.mNext;
3589 dequeue(curr, prev);
3590 super.forward(curr);
3591 curr = next;
3592 } else {
3593 prev = curr;
3594 curr = curr.mNext;
3595 }
3596 }
3597 }
3598
3599 @Override
3600 protected void apply(QueuedInputEvent q, int result) {
3601 if (result == DEFER) {
3602 defer(q);
3603 } else {
3604 super.apply(q, result);
3605 }
3606 }
3607
3608 private void enqueue(QueuedInputEvent q) {
3609 if (mQueueTail == null) {
3610 mQueueHead = q;
3611 mQueueTail = q;
3612 } else {
3613 mQueueTail.mNext = q;
3614 mQueueTail = q;
3615 }
3616
3617 mQueueLength += 1;
3618 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3619 }
3620
3621 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3622 if (prev == null) {
3623 mQueueHead = q.mNext;
3624 } else {
3625 prev.mNext = q.mNext;
3626 }
3627 if (mQueueTail == q) {
3628 mQueueTail = prev;
3629 }
3630 q.mNext = null;
3631
3632 mQueueLength -= 1;
3633 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3634 }
Jeff Brown5182c782013-10-15 20:31:52 -07003635
3636 @Override
3637 void dump(String prefix, PrintWriter writer) {
3638 writer.print(prefix);
3639 writer.print(getClass().getName());
3640 writer.print(": mQueueLength=");
3641 writer.println(mQueueLength);
3642
3643 super.dump(prefix, writer);
3644 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003645 }
3646
3647 /**
3648 * Delivers pre-ime input events to a native activity.
3649 * Does not support pointer events.
3650 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003651 final class NativePreImeInputStage extends AsyncInputStage
3652 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003653 public NativePreImeInputStage(InputStage next, String traceCounter) {
3654 super(next, traceCounter);
3655 }
3656
3657 @Override
3658 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003659 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3660 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3661 return DEFER;
3662 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003663 return FORWARD;
3664 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003665
3666 @Override
3667 public void onFinishedInputEvent(Object token, boolean handled) {
3668 QueuedInputEvent q = (QueuedInputEvent)token;
3669 if (handled) {
3670 finish(q, true);
3671 return;
3672 }
3673 forward(q);
3674 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003675 }
3676
3677 /**
3678 * Delivers pre-ime input events to the view hierarchy.
3679 * Does not support pointer events.
3680 */
3681 final class ViewPreImeInputStage extends InputStage {
3682 public ViewPreImeInputStage(InputStage next) {
3683 super(next);
3684 }
3685
3686 @Override
3687 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003688 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003689 return processKeyEvent(q);
3690 }
3691 return FORWARD;
3692 }
3693
3694 private int processKeyEvent(QueuedInputEvent q) {
3695 final KeyEvent event = (KeyEvent)q.mEvent;
3696 if (mView.dispatchKeyEventPreIme(event)) {
3697 return FINISH_HANDLED;
3698 }
3699 return FORWARD;
3700 }
3701 }
3702
3703 /**
3704 * Delivers input events to the ime.
3705 * Does not support pointer events.
3706 */
3707 final class ImeInputStage extends AsyncInputStage
3708 implements InputMethodManager.FinishedInputEventCallback {
3709 public ImeInputStage(InputStage next, String traceCounter) {
3710 super(next, traceCounter);
3711 }
3712
3713 @Override
3714 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07003715 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003716 InputMethodManager imm = InputMethodManager.peekInstance();
3717 if (imm != null) {
3718 final InputEvent event = q.mEvent;
3719 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3720 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3721 if (result == InputMethodManager.DISPATCH_HANDLED) {
3722 return FINISH_HANDLED;
3723 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
3724 return FINISH_NOT_HANDLED;
3725 } else {
3726 return DEFER; // callback will be invoked later
3727 }
3728 }
3729 }
3730 return FORWARD;
3731 }
3732
3733 @Override
3734 public void onFinishedInputEvent(Object token, boolean handled) {
3735 QueuedInputEvent q = (QueuedInputEvent)token;
3736 if (handled) {
3737 finish(q, true);
3738 return;
3739 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003740 forward(q);
3741 }
3742 }
3743
3744 /**
3745 * Performs early processing of post-ime input events.
3746 */
3747 final class EarlyPostImeInputStage extends InputStage {
3748 public EarlyPostImeInputStage(InputStage next) {
3749 super(next);
3750 }
3751
3752 @Override
3753 protected int onProcess(QueuedInputEvent q) {
3754 if (q.mEvent instanceof KeyEvent) {
3755 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003756 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003757 final int source = q.mEvent.getSource();
3758 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003759 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003760 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003761 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003762 return FORWARD;
3763 }
3764
3765 private int processKeyEvent(QueuedInputEvent q) {
3766 final KeyEvent event = (KeyEvent)q.mEvent;
3767
3768 // If the key's purpose is to exit touch mode then we consume it
3769 // and consider it handled.
3770 if (checkForLeavingTouchModeAndConsume(event)) {
3771 return FINISH_HANDLED;
3772 }
3773
3774 // Make sure the fallback event policy sees all keys that will be
3775 // delivered to the view hierarchy.
3776 mFallbackEventHandler.preDispatchKeyEvent(event);
3777 return FORWARD;
3778 }
3779
3780 private int processPointerEvent(QueuedInputEvent q) {
3781 final MotionEvent event = (MotionEvent)q.mEvent;
3782
3783 // Translate the pointer event for compatibility, if needed.
3784 if (mTranslator != null) {
3785 mTranslator.translateEventInScreenToAppWindow(event);
3786 }
3787
3788 // Enter touch mode on down or scroll.
3789 final int action = event.getAction();
3790 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3791 ensureTouchMode(true);
3792 }
3793
3794 // Offset the scroll position.
3795 if (mCurScrollY != 0) {
3796 event.offsetLocation(0, mCurScrollY);
3797 }
3798
3799 // Remember the touch position for possible drag-initiation.
3800 if (event.isTouchEvent()) {
3801 mLastTouchPoint.x = event.getRawX();
3802 mLastTouchPoint.y = event.getRawY();
3803 }
3804 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003805 }
3806 }
3807
Jeff Brownf9e989d2013-04-04 23:04:03 -07003808 /**
3809 * Delivers post-ime input events to a native activity.
3810 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003811 final class NativePostImeInputStage extends AsyncInputStage
3812 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003813 public NativePostImeInputStage(InputStage next, String traceCounter) {
3814 super(next, traceCounter);
3815 }
3816
3817 @Override
3818 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003819 if (mInputQueue != null) {
3820 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3821 return DEFER;
3822 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003823 return FORWARD;
3824 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003825
3826 @Override
3827 public void onFinishedInputEvent(Object token, boolean handled) {
3828 QueuedInputEvent q = (QueuedInputEvent)token;
3829 if (handled) {
3830 finish(q, true);
3831 return;
3832 }
3833 forward(q);
3834 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003835 }
3836
3837 /**
3838 * Delivers post-ime input events to the view hierarchy.
3839 */
3840 final class ViewPostImeInputStage extends InputStage {
3841 public ViewPostImeInputStage(InputStage next) {
3842 super(next);
3843 }
3844
3845 @Override
3846 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003847 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003848 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003849 } else {
Dianne Hackborn021d2432013-10-13 15:20:09 -07003850 // If delivering a new non-key event, make sure the window is
3851 // now allowed to start updating.
3852 handleDispatchDoneAnimating();
Jeff Brown29c0ed22013-01-14 13:50:37 -08003853 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003854 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3855 return processPointerEvent(q);
3856 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3857 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003858 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003859 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003860 }
3861 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003862 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003863
Jeff Brownf9e989d2013-04-04 23:04:03 -07003864 private int processKeyEvent(QueuedInputEvent q) {
3865 final KeyEvent event = (KeyEvent)q.mEvent;
3866
Dianne Hackborn021d2432013-10-13 15:20:09 -07003867 if (event.getAction() != KeyEvent.ACTION_UP) {
3868 // If delivering a new key event, make sure the window is
3869 // now allowed to start updating.
3870 handleDispatchDoneAnimating();
3871 }
3872
Jeff Brownf9e989d2013-04-04 23:04:03 -07003873 // Deliver the key to the view hierarchy.
3874 if (mView.dispatchKeyEvent(event)) {
3875 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003876 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003877
Michael Wright17d28ca2013-10-31 17:47:45 -07003878 if (shouldDropInputEvent(q)) {
3879 return FINISH_NOT_HANDLED;
3880 }
3881
Jeff Brownf9e989d2013-04-04 23:04:03 -07003882 // If the Control modifier is held, try to interpret the key as a shortcut.
3883 if (event.getAction() == KeyEvent.ACTION_DOWN
3884 && event.isCtrlPressed()
3885 && event.getRepeatCount() == 0
3886 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3887 if (mView.dispatchKeyShortcutEvent(event)) {
3888 return FINISH_HANDLED;
3889 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003890 if (shouldDropInputEvent(q)) {
3891 return FINISH_NOT_HANDLED;
3892 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003893 }
3894
3895 // Apply the fallback event policy.
3896 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3897 return FINISH_HANDLED;
3898 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003899 if (shouldDropInputEvent(q)) {
3900 return FINISH_NOT_HANDLED;
3901 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003902
3903 // Handle automatic focus changes.
3904 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3905 int direction = 0;
3906 switch (event.getKeyCode()) {
3907 case KeyEvent.KEYCODE_DPAD_LEFT:
3908 if (event.hasNoModifiers()) {
3909 direction = View.FOCUS_LEFT;
3910 }
3911 break;
3912 case KeyEvent.KEYCODE_DPAD_RIGHT:
3913 if (event.hasNoModifiers()) {
3914 direction = View.FOCUS_RIGHT;
3915 }
3916 break;
3917 case KeyEvent.KEYCODE_DPAD_UP:
3918 if (event.hasNoModifiers()) {
3919 direction = View.FOCUS_UP;
3920 }
3921 break;
3922 case KeyEvent.KEYCODE_DPAD_DOWN:
3923 if (event.hasNoModifiers()) {
3924 direction = View.FOCUS_DOWN;
3925 }
3926 break;
3927 case KeyEvent.KEYCODE_TAB:
3928 if (event.hasNoModifiers()) {
3929 direction = View.FOCUS_FORWARD;
3930 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3931 direction = View.FOCUS_BACKWARD;
3932 }
3933 break;
3934 }
3935 if (direction != 0) {
3936 View focused = mView.findFocus();
3937 if (focused != null) {
3938 View v = focused.focusSearch(direction);
3939 if (v != null && v != focused) {
3940 // do the math the get the interesting rect
3941 // of previous focused into the coord system of
3942 // newly focused view
3943 focused.getFocusedRect(mTempRect);
3944 if (mView instanceof ViewGroup) {
3945 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3946 focused, mTempRect);
3947 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3948 v, mTempRect);
3949 }
3950 if (v.requestFocus(direction, mTempRect)) {
3951 playSoundEffect(SoundEffectConstants
3952 .getContantForFocusDirection(direction));
3953 return FINISH_HANDLED;
3954 }
3955 }
3956
3957 // Give the focused view a last chance to handle the dpad key.
3958 if (mView.dispatchUnhandledMove(focused, direction)) {
3959 return FINISH_HANDLED;
3960 }
3961 } else {
3962 // find the best view to give focus to in this non-touch-mode with no-focus
3963 View v = focusSearch(null, direction);
3964 if (v != null && v.requestFocus(direction)) {
3965 return FINISH_HANDLED;
3966 }
3967 }
3968 }
3969 }
3970 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003971 }
3972
Jeff Brownf9e989d2013-04-04 23:04:03 -07003973 private int processPointerEvent(QueuedInputEvent q) {
3974 final MotionEvent event = (MotionEvent)q.mEvent;
3975
3976 if (mView.dispatchPointerEvent(event)) {
3977 return FINISH_HANDLED;
3978 }
3979 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003980 }
3981
Jeff Brownf9e989d2013-04-04 23:04:03 -07003982 private int processTrackballEvent(QueuedInputEvent q) {
3983 final MotionEvent event = (MotionEvent)q.mEvent;
3984
3985 if (mView.dispatchTrackballEvent(event)) {
3986 return FINISH_HANDLED;
3987 }
3988 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003989 }
3990
Jeff Brownf9e989d2013-04-04 23:04:03 -07003991 private int processGenericMotionEvent(QueuedInputEvent q) {
3992 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003993
Jeff Brownf9e989d2013-04-04 23:04:03 -07003994 // Deliver the event to the view.
3995 if (mView.dispatchGenericMotionEvent(event)) {
3996 return FINISH_HANDLED;
3997 }
3998 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003999 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004000 }
4001
Jeff Brownf9e989d2013-04-04 23:04:03 -07004002 /**
Jeff Brown678a1252013-04-09 17:46:25 -07004003 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004004 */
4005 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07004006 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
4007 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
4008 private final SyntheticTouchNavigationHandler mTouchNavigation =
4009 new SyntheticTouchNavigationHandler();
Michael Wright4567e402013-08-16 15:08:35 -07004010 private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004011
4012 public SyntheticInputStage() {
4013 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08004014 }
4015
Jeff Brownf9e989d2013-04-04 23:04:03 -07004016 @Override
4017 protected int onProcess(QueuedInputEvent q) {
4018 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
4019 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004020 final MotionEvent event = (MotionEvent)q.mEvent;
4021 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004022 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004023 mTrackball.process(event);
4024 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004025 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004026 mJoystick.process(event);
4027 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004028 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4029 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004030 mTouchNavigation.process(event);
4031 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004032 }
Michael Wright4567e402013-08-16 15:08:35 -07004033 } else if (q.mEvent instanceof KeyEvent) {
4034 if (mKeys.process((KeyEvent) q.mEvent)) {
4035 return FINISH_HANDLED;
4036 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004037 }
Michael Wright4567e402013-08-16 15:08:35 -07004038
Jeff Brownf9e989d2013-04-04 23:04:03 -07004039 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004040 }
4041
Jeff Brownf9e989d2013-04-04 23:04:03 -07004042 @Override
4043 protected void onDeliverToNext(QueuedInputEvent q) {
4044 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4045 // Cancel related synthetic events if any prior stage has handled the event.
4046 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004047 final MotionEvent event = (MotionEvent)q.mEvent;
4048 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004049 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004050 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004051 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004052 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004053 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4054 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004055 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004056 }
4057 }
4058 }
4059 super.onDeliverToNext(q);
4060 }
Jeff Brown678a1252013-04-09 17:46:25 -07004061 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004062
Jeff Brown678a1252013-04-09 17:46:25 -07004063 /**
4064 * Creates dpad events from unhandled trackball movements.
4065 */
4066 final class SyntheticTrackballHandler {
4067 private final TrackballAxis mX = new TrackballAxis();
4068 private final TrackballAxis mY = new TrackballAxis();
4069 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004070
Jeff Brown678a1252013-04-09 17:46:25 -07004071 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004072 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004073 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004074 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004075 // It has been too long since the last movement,
4076 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004077 mX.reset(0);
4078 mY.reset(0);
4079 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004080 }
4081
4082 final int action = event.getAction();
4083 final int metaState = event.getMetaState();
4084 switch (action) {
4085 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004086 mX.reset(2);
4087 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004088 enqueueInputEvent(new KeyEvent(curTime, curTime,
4089 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4090 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4091 InputDevice.SOURCE_KEYBOARD));
4092 break;
4093 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004094 mX.reset(2);
4095 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004096 enqueueInputEvent(new KeyEvent(curTime, curTime,
4097 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4098 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4099 InputDevice.SOURCE_KEYBOARD));
4100 break;
4101 }
4102
Jeff Brown678a1252013-04-09 17:46:25 -07004103 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4104 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004105 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004106 + " / Y=" + mY.position + " step="
4107 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004108 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004109 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4110 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004111
4112 // Generate DPAD events based on the trackball movement.
4113 // We pick the axis that has moved the most as the direction of
4114 // the DPAD. When we generate DPAD events for one axis, then the
4115 // other axis is reset -- we don't want to perform DPAD jumps due
4116 // to slight movements in the trackball when making major movements
4117 // along the other axis.
4118 int keycode = 0;
4119 int movement = 0;
4120 float accel = 1;
4121 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004122 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004123 if (movement != 0) {
4124 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4125 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004126 accel = mX.acceleration;
4127 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004128 }
4129 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004130 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004131 if (movement != 0) {
4132 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4133 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004134 accel = mY.acceleration;
4135 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004136 }
4137 }
4138
4139 if (keycode != 0) {
4140 if (movement < 0) movement = -movement;
4141 int accelMovement = (int)(movement * accel);
4142 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4143 + " accelMovement=" + accelMovement
4144 + " accel=" + accel);
4145 if (accelMovement > movement) {
4146 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4147 + keycode);
4148 movement--;
4149 int repeatCount = accelMovement - movement;
4150 enqueueInputEvent(new KeyEvent(curTime, curTime,
4151 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4152 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4153 InputDevice.SOURCE_KEYBOARD));
4154 }
4155 while (movement > 0) {
4156 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4157 + keycode);
4158 movement--;
4159 curTime = SystemClock.uptimeMillis();
4160 enqueueInputEvent(new KeyEvent(curTime, curTime,
4161 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4162 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4163 InputDevice.SOURCE_KEYBOARD));
4164 enqueueInputEvent(new KeyEvent(curTime, curTime,
4165 KeyEvent.ACTION_UP, keycode, 0, metaState,
4166 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4167 InputDevice.SOURCE_KEYBOARD));
4168 }
Jeff Brown678a1252013-04-09 17:46:25 -07004169 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004170 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004171 }
4172
Jeff Brown678a1252013-04-09 17:46:25 -07004173 public void cancel(MotionEvent event) {
4174 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004175
Jeff Brownf9e989d2013-04-04 23:04:03 -07004176 // If we reach this, we consumed a trackball event.
4177 // Because we will not translate the trackball event into a key event,
4178 // touch mode will not exit, so we exit touch mode here.
4179 if (mView != null && mAdded) {
4180 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004181 }
4182 }
Jeff Brown678a1252013-04-09 17:46:25 -07004183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004184
Jeff Brown678a1252013-04-09 17:46:25 -07004185 /**
4186 * Maintains state information for a single trackball axis, generating
4187 * discrete (DPAD) movements based on raw trackball motion.
4188 */
4189 static final class TrackballAxis {
4190 /**
4191 * The maximum amount of acceleration we will apply.
4192 */
4193 static final float MAX_ACCELERATION = 20;
4194
4195 /**
4196 * The maximum amount of time (in milliseconds) between events in order
4197 * for us to consider the user to be doing fast trackball movements,
4198 * and thus apply an acceleration.
4199 */
4200 static final long FAST_MOVE_TIME = 150;
4201
4202 /**
4203 * Scaling factor to the time (in milliseconds) between events to how
4204 * much to multiple/divide the current acceleration. When movement
4205 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4206 * FAST_MOVE_TIME it divides it.
4207 */
4208 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4209
4210 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4211 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4212 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4213
4214 float position;
4215 float acceleration = 1;
4216 long lastMoveTime = 0;
4217 int step;
4218 int dir;
4219 int nonAccelMovement;
4220
4221 void reset(int _step) {
4222 position = 0;
4223 acceleration = 1;
4224 lastMoveTime = 0;
4225 step = _step;
4226 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004227 }
4228
Jeff Brown678a1252013-04-09 17:46:25 -07004229 /**
4230 * Add trackball movement into the state. If the direction of movement
4231 * has been reversed, the state is reset before adding the
4232 * movement (so that you don't have to compensate for any previously
4233 * collected movement before see the result of the movement in the
4234 * new direction).
4235 *
4236 * @return Returns the absolute value of the amount of movement
4237 * collected so far.
4238 */
4239 float collect(float off, long time, String axis) {
4240 long normTime;
4241 if (off > 0) {
4242 normTime = (long)(off * FAST_MOVE_TIME);
4243 if (dir < 0) {
4244 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4245 position = 0;
4246 step = 0;
4247 acceleration = 1;
4248 lastMoveTime = 0;
4249 }
4250 dir = 1;
4251 } else if (off < 0) {
4252 normTime = (long)((-off) * FAST_MOVE_TIME);
4253 if (dir > 0) {
4254 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4255 position = 0;
4256 step = 0;
4257 acceleration = 1;
4258 lastMoveTime = 0;
4259 }
4260 dir = -1;
4261 } else {
4262 normTime = 0;
4263 }
4264
4265 // The number of milliseconds between each movement that is
4266 // considered "normal" and will not result in any acceleration
4267 // or deceleration, scaled by the offset we have here.
4268 if (normTime > 0) {
4269 long delta = time - lastMoveTime;
4270 lastMoveTime = time;
4271 float acc = acceleration;
4272 if (delta < normTime) {
4273 // The user is scrolling rapidly, so increase acceleration.
4274 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4275 if (scale > 1) acc *= scale;
4276 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4277 + off + " normTime=" + normTime + " delta=" + delta
4278 + " scale=" + scale + " acc=" + acc);
4279 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4280 } else {
4281 // The user is scrolling slowly, so decrease acceleration.
4282 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4283 if (scale > 1) acc /= scale;
4284 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4285 + off + " normTime=" + normTime + " delta=" + delta
4286 + " scale=" + scale + " acc=" + acc);
4287 acceleration = acc > 1 ? acc : 1;
4288 }
4289 }
4290 position += off;
4291 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004292 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004293
Jeff Brown678a1252013-04-09 17:46:25 -07004294 /**
4295 * Generate the number of discrete movement events appropriate for
4296 * the currently collected trackball movement.
4297 *
4298 * @return Returns the number of discrete movements, either positive
4299 * or negative, or 0 if there is not enough trackball movement yet
4300 * for a discrete movement.
4301 */
4302 int generate() {
4303 int movement = 0;
4304 nonAccelMovement = 0;
4305 do {
4306 final int dir = position >= 0 ? 1 : -1;
4307 switch (step) {
4308 // If we are going to execute the first step, then we want
4309 // to do this as soon as possible instead of waiting for
4310 // a full movement, in order to make things look responsive.
4311 case 0:
4312 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4313 return movement;
4314 }
4315 movement += dir;
4316 nonAccelMovement += dir;
4317 step = 1;
4318 break;
4319 // If we have generated the first movement, then we need
4320 // to wait for the second complete trackball motion before
4321 // generating the second discrete movement.
4322 case 1:
4323 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4324 return movement;
4325 }
4326 movement += dir;
4327 nonAccelMovement += dir;
4328 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4329 step = 2;
4330 break;
4331 // After the first two, we generate discrete movements
4332 // consistently with the trackball, applying an acceleration
4333 // if the trackball is moving quickly. This is a simple
4334 // acceleration on top of what we already compute based
4335 // on how quickly the wheel is being turned, to apply
4336 // a longer increasing acceleration to continuous movement
4337 // in one direction.
4338 default:
4339 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4340 return movement;
4341 }
4342 movement += dir;
4343 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4344 float acc = acceleration;
4345 acc *= 1.1f;
4346 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4347 break;
4348 }
4349 } while (true);
4350 }
4351 }
4352
4353 /**
4354 * Creates dpad events from unhandled joystick movements.
4355 */
4356 final class SyntheticJoystickHandler extends Handler {
4357 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4358 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4359
4360 private int mLastXDirection;
4361 private int mLastYDirection;
4362 private int mLastXKeyCode;
4363 private int mLastYKeyCode;
4364
4365 public SyntheticJoystickHandler() {
4366 super(true);
4367 }
4368
4369 @Override
4370 public void handleMessage(Message msg) {
4371 switch (msg.what) {
4372 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4373 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4374 KeyEvent oldEvent = (KeyEvent)msg.obj;
4375 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4376 SystemClock.uptimeMillis(),
4377 oldEvent.getRepeatCount() + 1);
4378 if (mAttachInfo.mHasWindowFocus) {
4379 enqueueInputEvent(e);
4380 Message m = obtainMessage(msg.what, e);
4381 m.setAsynchronous(true);
4382 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4383 }
4384 } break;
4385 }
4386 }
4387
4388 public void process(MotionEvent event) {
4389 update(event, true);
4390 }
4391
4392 public void cancel(MotionEvent event) {
4393 update(event, false);
4394 }
4395
4396 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004397 final long time = event.getEventTime();
4398 final int metaState = event.getMetaState();
4399 final int deviceId = event.getDeviceId();
4400 final int source = event.getSource();
4401
4402 int xDirection = joystickAxisValueToDirection(
4403 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4404 if (xDirection == 0) {
4405 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004406 }
4407
Jeff Brownf9e989d2013-04-04 23:04:03 -07004408 int yDirection = joystickAxisValueToDirection(
4409 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4410 if (yDirection == 0) {
4411 yDirection = joystickAxisValueToDirection(event.getY());
4412 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004413
Jeff Brown678a1252013-04-09 17:46:25 -07004414 if (xDirection != mLastXDirection) {
4415 if (mLastXKeyCode != 0) {
4416 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004417 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004418 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004419 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004420 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004421 }
4422
Jeff Brown678a1252013-04-09 17:46:25 -07004423 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004424
4425 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004426 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004427 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4428 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004429 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004430 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4431 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004432 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004433 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004434 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004435 }
4436 }
4437
Jeff Brown678a1252013-04-09 17:46:25 -07004438 if (yDirection != mLastYDirection) {
4439 if (mLastYKeyCode != 0) {
4440 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004441 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004442 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004443 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004444 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004445 }
4446
Jeff Brown678a1252013-04-09 17:46:25 -07004447 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004448
4449 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004450 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004451 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4452 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004453 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004454 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4455 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004456 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004457 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004458 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004459 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004460 }
4461 }
4462
Jeff Brownf9e989d2013-04-04 23:04:03 -07004463 private int joystickAxisValueToDirection(float value) {
4464 if (value >= 0.5f) {
4465 return 1;
4466 } else if (value <= -0.5f) {
4467 return -1;
4468 } else {
4469 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004470 }
4471 }
Jeff Brown678a1252013-04-09 17:46:25 -07004472 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004473
Jeff Brown678a1252013-04-09 17:46:25 -07004474 /**
4475 * Creates dpad events from unhandled touch navigation movements.
4476 */
4477 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004478 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4479 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004480
Jeff Brown4dac9012013-04-10 01:03:19 -07004481 // Assumed nominal width and height in millimeters of a touch navigation pad,
4482 // if no resolution information is available from the input system.
4483 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4484 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004485
Jeff Brown4dac9012013-04-10 01:03:19 -07004486 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004487
Jeff Brown4dac9012013-04-10 01:03:19 -07004488 // The nominal distance traveled to move by one unit.
4489 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4490
4491 // Minimum and maximum fling velocity in ticks per second.
4492 // The minimum velocity should be set such that we perform enough ticks per
4493 // second that the fling appears to be fluid. For example, if we set the minimum
4494 // to 2 ticks per second, then there may be up to half a second delay between the next
4495 // to last and last ticks which is noticeably discrete and jerky. This value should
4496 // probably not be set to anything less than about 4.
4497 // If fling accuracy is a problem then consider tuning the tick distance instead.
4498 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4499 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4500
4501 // Fling velocity decay factor applied after each new key is emitted.
4502 // This parameter controls the deceleration and overall duration of the fling.
4503 // The fling stops automatically when its velocity drops below the minimum
4504 // fling velocity defined above.
4505 private static final float FLING_TICK_DECAY = 0.8f;
4506
4507 /* The input device that we are tracking. */
4508
4509 private int mCurrentDeviceId = -1;
4510 private int mCurrentSource;
4511 private boolean mCurrentDeviceSupported;
4512
4513 /* Configuration for the current input device. */
4514
Jeff Brown4dac9012013-04-10 01:03:19 -07004515 // The scaled tick distance. A movement of this amount should generally translate
4516 // into a single dpad event in a given direction.
4517 private float mConfigTickDistance;
4518
4519 // The minimum and maximum scaled fling velocity.
4520 private float mConfigMinFlingVelocity;
4521 private float mConfigMaxFlingVelocity;
4522
4523 /* Tracking state. */
4524
4525 // The velocity tracker for detecting flings.
4526 private VelocityTracker mVelocityTracker;
4527
4528 // The active pointer id, or -1 if none.
4529 private int mActivePointerId = -1;
4530
John Reck79d81e62013-11-05 13:26:57 -08004531 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07004532 private float mStartX;
4533 private float mStartY;
4534
4535 // Most recently observed position.
4536 private float mLastX;
4537 private float mLastY;
4538
4539 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004540 private float mAccumulatedX;
4541 private float mAccumulatedY;
4542
Jeff Brown4dac9012013-04-10 01:03:19 -07004543 // Set to true if any movement was delivered to the app.
4544 // Implies that tap slop was exceeded.
4545 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004546
Jeff Brown4dac9012013-04-10 01:03:19 -07004547 // The most recently sent key down event.
4548 // The keycode remains set until the direction changes or a fling ends
4549 // so that repeated key events may be generated as required.
4550 private long mPendingKeyDownTime;
4551 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4552 private int mPendingKeyRepeatCount;
4553 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004554
Jeff Brown4dac9012013-04-10 01:03:19 -07004555 // The current fling velocity while a fling is in progress.
4556 private boolean mFlinging;
4557 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004558
4559 public SyntheticTouchNavigationHandler() {
4560 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004561 }
4562
4563 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004564 // Update the current device information.
4565 final long time = event.getEventTime();
4566 final int deviceId = event.getDeviceId();
4567 final int source = event.getSource();
4568 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4569 finishKeys(time);
4570 finishTracking(time);
4571 mCurrentDeviceId = deviceId;
4572 mCurrentSource = source;
4573 mCurrentDeviceSupported = false;
4574 InputDevice device = event.getDevice();
4575 if (device != null) {
4576 // In order to support an input device, we must know certain
4577 // characteristics about it, such as its size and resolution.
4578 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4579 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4580 if (xRange != null && yRange != null) {
4581 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004582
Jeff Brown4dac9012013-04-10 01:03:19 -07004583 // Infer the resolution if it not actually known.
4584 float xRes = xRange.getResolution();
4585 if (xRes <= 0) {
4586 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4587 }
4588 float yRes = yRange.getResolution();
4589 if (yRes <= 0) {
4590 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4591 }
4592 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004593
Jeff Brown4dac9012013-04-10 01:03:19 -07004594 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07004595 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4596 mConfigMinFlingVelocity =
4597 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4598 mConfigMaxFlingVelocity =
4599 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4600
4601 if (LOCAL_DEBUG) {
4602 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4603 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07004604 + ", mConfigTickDistance=" + mConfigTickDistance
4605 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4606 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4607 }
4608 }
4609 }
Jeff Brown678a1252013-04-09 17:46:25 -07004610 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004611 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004612 return;
4613 }
4614
Jeff Brown4dac9012013-04-10 01:03:19 -07004615 // Handle the event.
4616 final int action = event.getActionMasked();
4617 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004618 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004619 boolean caughtFling = mFlinging;
4620 finishKeys(time);
4621 finishTracking(time);
4622 mActivePointerId = event.getPointerId(0);
4623 mVelocityTracker = VelocityTracker.obtain();
4624 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07004625 mStartX = event.getX();
4626 mStartY = event.getY();
4627 mLastX = mStartX;
4628 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004629 mAccumulatedX = 0;
4630 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004631
4632 // If we caught a fling, then pretend that the tap slop has already
4633 // been exceeded to suppress taps whose only purpose is to stop the fling.
4634 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004635 break;
4636 }
4637
Jeff Brown4dac9012013-04-10 01:03:19 -07004638 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004639 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004640 if (mActivePointerId < 0) {
4641 break;
4642 }
4643 final int index = event.findPointerIndex(mActivePointerId);
4644 if (index < 0) {
4645 finishKeys(time);
4646 finishTracking(time);
4647 break;
4648 }
Jeff Brown678a1252013-04-09 17:46:25 -07004649
Jeff Brown4dac9012013-04-10 01:03:19 -07004650 mVelocityTracker.addMovement(event);
4651 final float x = event.getX(index);
4652 final float y = event.getY(index);
4653 mAccumulatedX += x - mLastX;
4654 mAccumulatedY += y - mLastY;
4655 mLastX = x;
4656 mLastY = y;
4657
4658 // Consume any accumulated movement so far.
4659 final int metaState = event.getMetaState();
4660 consumeAccumulatedMovement(time, metaState);
4661
4662 // Detect taps and flings.
4663 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07004664 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004665 // It might be a fling.
4666 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4667 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4668 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4669 if (!startFling(time, vx, vy)) {
4670 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004671 }
4672 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004673 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004674 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004675 break;
4676 }
4677
4678 case MotionEvent.ACTION_CANCEL: {
4679 finishKeys(time);
4680 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004681 break;
4682 }
4683 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004684 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004685
4686 public void cancel(MotionEvent event) {
4687 if (mCurrentDeviceId == event.getDeviceId()
4688 && mCurrentSource == event.getSource()) {
4689 final long time = event.getEventTime();
4690 finishKeys(time);
4691 finishTracking(time);
4692 }
4693 }
4694
4695 private void finishKeys(long time) {
4696 cancelFling();
4697 sendKeyUp(time);
4698 }
4699
4700 private void finishTracking(long time) {
4701 if (mActivePointerId >= 0) {
4702 mActivePointerId = -1;
4703 mVelocityTracker.recycle();
4704 mVelocityTracker = null;
4705 }
4706 }
4707
4708 private void consumeAccumulatedMovement(long time, int metaState) {
4709 final float absX = Math.abs(mAccumulatedX);
4710 final float absY = Math.abs(mAccumulatedY);
4711 if (absX >= absY) {
4712 if (absX >= mConfigTickDistance) {
4713 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4714 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4715 mAccumulatedY = 0;
4716 mConsumedMovement = true;
4717 }
4718 } else {
4719 if (absY >= mConfigTickDistance) {
4720 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4721 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4722 mAccumulatedX = 0;
4723 mConsumedMovement = true;
4724 }
4725 }
4726 }
4727
4728 private float consumeAccumulatedMovement(long time, int metaState,
4729 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4730 while (accumulator <= -mConfigTickDistance) {
4731 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4732 accumulator += mConfigTickDistance;
4733 }
4734 while (accumulator >= mConfigTickDistance) {
4735 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4736 accumulator -= mConfigTickDistance;
4737 }
4738 return accumulator;
4739 }
4740
4741 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4742 if (mPendingKeyCode != keyCode) {
4743 sendKeyUp(time);
4744 mPendingKeyDownTime = time;
4745 mPendingKeyCode = keyCode;
4746 mPendingKeyRepeatCount = 0;
4747 } else {
4748 mPendingKeyRepeatCount += 1;
4749 }
4750 mPendingKeyMetaState = metaState;
4751
4752 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4753 // but it doesn't quite make sense when simulating the events in this way.
4754 if (LOCAL_DEBUG) {
4755 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4756 + ", repeatCount=" + mPendingKeyRepeatCount
4757 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4758 }
4759 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4760 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4761 mPendingKeyMetaState, mCurrentDeviceId,
4762 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4763 }
4764
4765 private void sendKeyUp(long time) {
4766 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4767 if (LOCAL_DEBUG) {
4768 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4769 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4770 }
4771 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4772 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4773 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4774 mCurrentSource));
4775 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4776 }
4777 }
4778
4779 private boolean startFling(long time, float vx, float vy) {
4780 if (LOCAL_DEBUG) {
4781 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4782 + ", min=" + mConfigMinFlingVelocity);
4783 }
4784
4785 // Flings must be oriented in the same direction as the preceding movements.
4786 switch (mPendingKeyCode) {
4787 case KeyEvent.KEYCODE_DPAD_LEFT:
4788 if (-vx >= mConfigMinFlingVelocity
4789 && Math.abs(vy) < mConfigMinFlingVelocity) {
4790 mFlingVelocity = -vx;
4791 break;
4792 }
4793 return false;
4794
4795 case KeyEvent.KEYCODE_DPAD_RIGHT:
4796 if (vx >= mConfigMinFlingVelocity
4797 && Math.abs(vy) < mConfigMinFlingVelocity) {
4798 mFlingVelocity = vx;
4799 break;
4800 }
4801 return false;
4802
4803 case KeyEvent.KEYCODE_DPAD_UP:
4804 if (-vy >= mConfigMinFlingVelocity
4805 && Math.abs(vx) < mConfigMinFlingVelocity) {
4806 mFlingVelocity = -vy;
4807 break;
4808 }
4809 return false;
4810
4811 case KeyEvent.KEYCODE_DPAD_DOWN:
4812 if (vy >= mConfigMinFlingVelocity
4813 && Math.abs(vx) < mConfigMinFlingVelocity) {
4814 mFlingVelocity = vy;
4815 break;
4816 }
4817 return false;
4818 }
4819
4820 // Post the first fling event.
4821 mFlinging = postFling(time);
4822 return mFlinging;
4823 }
4824
4825 private boolean postFling(long time) {
4826 // The idea here is to estimate the time when the pointer would have
4827 // traveled one tick distance unit given the current fling velocity.
4828 // This effect creates continuity of motion.
4829 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4830 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
4831 postAtTime(mFlingRunnable, time + delay);
4832 if (LOCAL_DEBUG) {
4833 Log.d(LOCAL_TAG, "Posted fling: velocity="
4834 + mFlingVelocity + ", delay=" + delay
4835 + ", keyCode=" + mPendingKeyCode);
4836 }
4837 return true;
4838 }
4839 return false;
4840 }
4841
4842 private void cancelFling() {
4843 if (mFlinging) {
4844 removeCallbacks(mFlingRunnable);
4845 mFlinging = false;
4846 }
4847 }
4848
4849 private final Runnable mFlingRunnable = new Runnable() {
4850 @Override
4851 public void run() {
4852 final long time = SystemClock.uptimeMillis();
4853 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
4854 mFlingVelocity *= FLING_TICK_DECAY;
4855 if (!postFling(time)) {
4856 mFlinging = false;
4857 finishKeys(time);
4858 }
4859 }
4860 };
Jeff Browncb1404e2011-01-15 18:14:15 -08004861 }
4862
Michael Wright916b6492013-12-03 16:53:03 -08004863 private KeyEvent getSyntheticFallbackKey(KeyEvent event) {
4864 // In some locales (like Japan) controllers use B for confirm and A for back, rather
4865 // than vice versa, so we need to special case this here since the input system itself
4866 // is not locale-aware.
4867 int keyCode;
4868 switch(event.getKeyCode()) {
4869 case KeyEvent.KEYCODE_BUTTON_A:
4870 case KeyEvent.KEYCODE_BUTTON_C:
4871 case KeyEvent.KEYCODE_BUTTON_X:
4872 case KeyEvent.KEYCODE_BUTTON_Z:
4873 keyCode = mFlipControllerFallbackKeys ?
4874 KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER;
4875 break;
4876 case KeyEvent.KEYCODE_BUTTON_B:
4877 case KeyEvent.KEYCODE_BUTTON_Y:
4878 keyCode = mFlipControllerFallbackKeys ?
4879 KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK;
4880 break;
4881 case KeyEvent.KEYCODE_BUTTON_THUMBL:
4882 case KeyEvent.KEYCODE_BUTTON_THUMBR:
4883 case KeyEvent.KEYCODE_BUTTON_START:
4884 case KeyEvent.KEYCODE_BUTTON_1:
4885 case KeyEvent.KEYCODE_BUTTON_2:
4886 case KeyEvent.KEYCODE_BUTTON_3:
4887 case KeyEvent.KEYCODE_BUTTON_4:
4888 case KeyEvent.KEYCODE_BUTTON_5:
4889 case KeyEvent.KEYCODE_BUTTON_6:
4890 case KeyEvent.KEYCODE_BUTTON_7:
4891 case KeyEvent.KEYCODE_BUTTON_8:
4892 case KeyEvent.KEYCODE_BUTTON_9:
4893 case KeyEvent.KEYCODE_BUTTON_10:
4894 case KeyEvent.KEYCODE_BUTTON_11:
4895 case KeyEvent.KEYCODE_BUTTON_12:
4896 case KeyEvent.KEYCODE_BUTTON_13:
4897 case KeyEvent.KEYCODE_BUTTON_14:
4898 case KeyEvent.KEYCODE_BUTTON_15:
4899 case KeyEvent.KEYCODE_BUTTON_16:
4900 keyCode = KeyEvent.KEYCODE_DPAD_CENTER;
4901 break;
4902 case KeyEvent.KEYCODE_BUTTON_SELECT:
4903 case KeyEvent.KEYCODE_BUTTON_MODE:
4904 keyCode = KeyEvent.KEYCODE_MENU;
4905 default:
4906 return null;
4907 }
4908 return KeyEvent.obtain(event.getDownTime(), event.getEventTime(),
4909 event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(),
4910 event.getDeviceId(), event.getScanCode(),
4911 event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource(), null);
4912 }
4913
4914
Michael Wright4567e402013-08-16 15:08:35 -07004915 final class SyntheticKeyHandler {
4916
4917 public boolean process(KeyEvent event) {
Michael Wright916b6492013-12-03 16:53:03 -08004918 KeyEvent syntheticKey = getSyntheticFallbackKey(event);
4919 if (syntheticKey != null) {
4920 enqueueInputEvent(syntheticKey);
4921 return true;
Michael Wright4567e402013-08-16 15:08:35 -07004922 }
Michael Wright916b6492013-12-03 16:53:03 -08004923 return false;
Michael Wright4567e402013-08-16 15:08:35 -07004924 }
4925
4926 }
4927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004928 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004929 * Returns true if the key is used for keyboard navigation.
4930 * @param keyEvent The key event.
4931 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004932 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004933 private static boolean isNavigationKey(KeyEvent keyEvent) {
4934 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004935 case KeyEvent.KEYCODE_DPAD_LEFT:
4936 case KeyEvent.KEYCODE_DPAD_RIGHT:
4937 case KeyEvent.KEYCODE_DPAD_UP:
4938 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08004939 case KeyEvent.KEYCODE_DPAD_CENTER:
4940 case KeyEvent.KEYCODE_PAGE_UP:
4941 case KeyEvent.KEYCODE_PAGE_DOWN:
4942 case KeyEvent.KEYCODE_MOVE_HOME:
4943 case KeyEvent.KEYCODE_MOVE_END:
4944 case KeyEvent.KEYCODE_TAB:
4945 case KeyEvent.KEYCODE_SPACE:
4946 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004947 return true;
4948 }
4949 return false;
4950 }
4951
4952 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004953 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004954 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08004955 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004956 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004957 private static boolean isTypingKey(KeyEvent keyEvent) {
4958 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004959 }
4960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004961 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004962 * 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 -08004963 * @param event The key event.
4964 * @return Whether this key event should be consumed (meaning the act of
4965 * leaving touch mode alone is considered the event).
4966 */
4967 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004968 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004969 if (!mAttachInfo.mInTouchMode) {
4970 return false;
4971 }
4972
Jeff Brown4e6319b2010-12-13 10:36:51 -08004973 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
4974 final int action = event.getAction();
4975 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004976 return false;
4977 }
4978
Jeff Brown4e6319b2010-12-13 10:36:51 -08004979 // Don't leave touch mode if the IME told us not to.
4980 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
4981 return false;
4982 }
4983
4984 // If the key can be used for keyboard navigation then leave touch mode
4985 // and select a focused view if needed (in ensureTouchMode).
4986 // When a new focused view is selected, we consume the navigation key because
4987 // navigation doesn't make much sense unless a view already has focus so
4988 // the key's purpose is to set focus.
4989 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004990 return ensureTouchMode(false);
4991 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08004992
4993 // If the key can be used for typing then leave touch mode
4994 // and select a focused view if needed (in ensureTouchMode).
4995 // Always allow the view to process the typing key.
4996 if (isTypingKey(event)) {
4997 ensureTouchMode(false);
4998 return false;
4999 }
5000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005001 return false;
5002 }
5003
Christopher Tatea53146c2010-09-07 11:57:52 -07005004 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08005005 void setLocalDragState(Object obj) {
5006 mLocalDragState = obj;
5007 }
5008
Christopher Tatea53146c2010-09-07 11:57:52 -07005009 private void handleDragEvent(DragEvent event) {
5010 // From the root, only drag start/end/location are dispatched. entered/exited
5011 // are determined and dispatched by the viewgroup hierarchy, who then report
5012 // that back here for ultimate reporting back to the framework.
5013 if (mView != null && mAdded) {
5014 final int what = event.mAction;
5015
5016 if (what == DragEvent.ACTION_DRAG_EXITED) {
5017 // A direct EXITED event means that the window manager knows we've just crossed
5018 // a window boundary, so the current drag target within this one must have
5019 // just been exited. Send it the usual notifications and then we're done
5020 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07005021 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005022 } else {
5023 // Cache the drag description when the operation starts, then fill it in
5024 // on subsequent calls as a convenience
5025 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005026 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005027 mDragDescription = event.mClipDescription;
5028 } else {
5029 event.mClipDescription = mDragDescription;
5030 }
5031
5032 // For events with a [screen] location, translate into window coordinates
5033 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5034 mDragPoint.set(event.mX, event.mY);
5035 if (mTranslator != null) {
5036 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5037 }
5038
5039 if (mCurScrollY != 0) {
5040 mDragPoint.offset(0, mCurScrollY);
5041 }
5042
5043 event.mX = mDragPoint.x;
5044 event.mY = mDragPoint.y;
5045 }
5046
5047 // Remember who the current drag target is pre-dispatch
5048 final View prevDragView = mCurrentDragView;
5049
5050 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005051 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005052
5053 // If we changed apparent drag target, tell the OS about it
5054 if (prevDragView != mCurrentDragView) {
5055 try {
5056 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005057 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005058 }
5059 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005060 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005061 }
5062 } catch (RemoteException e) {
5063 Slog.e(TAG, "Unable to note drag target change");
5064 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005065 }
Chris Tated4533f12010-10-19 15:15:08 -07005066
Christopher Tate407b4e92010-11-30 17:14:08 -08005067 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005068 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005069 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005070 try {
5071 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005072 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005073 } catch (RemoteException e) {
5074 Log.e(TAG, "Unable to report drop result");
5075 }
5076 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005077
5078 // When the drag operation ends, release any local state object
5079 // that may have been in use
5080 if (what == DragEvent.ACTION_DRAG_ENDED) {
5081 setLocalDragState(null);
5082 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005083 }
5084 }
5085 event.recycle();
5086 }
5087
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005088 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5089 if (mSeq != args.seq) {
5090 // The sequence has changed, so we need to update our value and make
5091 // sure to do a traversal afterward so the window manager is given our
5092 // most recent data.
5093 mSeq = args.seq;
5094 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005095 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005096 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005097 if (mView == null) return;
5098 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005099 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005100 }
Dianne Hackborncf675782012-05-10 15:07:24 -07005101 if (mAttachInfo != null) {
5102 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5103 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5104 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5105 mView.dispatchSystemUiVisibilityChanged(visibility);
5106 }
5107 }
Joe Onorato664644d2011-01-23 17:53:23 -08005108 }
5109
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005110 public void handleDispatchDoneAnimating() {
5111 if (mWindowsAnimating) {
5112 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07005113 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005114 scheduleTraversals();
5115 }
5116 }
5117 }
5118
Christopher Tate2c095f32010-10-04 14:13:40 -07005119 public void getLastTouchPoint(Point outLocation) {
5120 outLocation.x = (int) mLastTouchPoint.x;
5121 outLocation.y = (int) mLastTouchPoint.y;
5122 }
5123
Chris Tate9d1ab882010-11-02 15:55:39 -07005124 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005125 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005126 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005127 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005128 }
5129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005130 private AudioManager getAudioManager() {
5131 if (mView == null) {
5132 throw new IllegalStateException("getAudioManager called when there is no mView");
5133 }
5134 if (mAudioManager == null) {
5135 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5136 }
5137 return mAudioManager;
5138 }
5139
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005140 public AccessibilityInteractionController getAccessibilityInteractionController() {
5141 if (mView == null) {
5142 throw new IllegalStateException("getAccessibilityInteractionController"
5143 + " called when there is no mView");
5144 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005145 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005146 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005147 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005148 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005149 }
5150
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005151 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5152 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005153
5154 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005155 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005156 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005157 restore = true;
5158 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005159 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005160 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005161 if (params != null) {
5162 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005163 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005164 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005165 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005166 if (params != null && mOrigWindowType != params.type) {
5167 // For compatibility with old apps, don't crash here.
5168 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
5169 Slog.w(TAG, "Window type can not be changed after "
5170 + "the window is added; ignoring change of " + mView);
5171 params.type = mOrigWindowType;
5172 }
5173 }
Jeff Brown98365d72012-08-19 20:30:52 -07005174 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005175 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005176 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5177 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005178 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005179 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005180 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005181 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005182 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005183 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005184 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005185
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005186 if (mTranslator != null) {
5187 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005188 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005189 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5190 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005191 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005192 return relayoutResult;
5193 }
Romain Guy8506ab42009-06-11 17:35:47 -07005194
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005195 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005196 * {@inheritDoc}
5197 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005198 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 public void playSoundEffect(int effectId) {
5200 checkThread();
5201
Dan Morrille4d9a012013-03-28 18:10:43 -07005202 if (mMediaDisabled) {
5203 return;
5204 }
5205
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005206 try {
5207 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005209 switch (effectId) {
5210 case SoundEffectConstants.CLICK:
5211 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5212 return;
5213 case SoundEffectConstants.NAVIGATION_DOWN:
5214 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5215 return;
5216 case SoundEffectConstants.NAVIGATION_LEFT:
5217 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5218 return;
5219 case SoundEffectConstants.NAVIGATION_RIGHT:
5220 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5221 return;
5222 case SoundEffectConstants.NAVIGATION_UP:
5223 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5224 return;
5225 default:
5226 throw new IllegalArgumentException("unknown effect id " + effectId +
5227 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5228 }
5229 } catch (IllegalStateException e) {
5230 // Exception thrown by getAudioManager() when mView is null
5231 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5232 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 }
5234 }
5235
5236 /**
5237 * {@inheritDoc}
5238 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005239 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005240 public boolean performHapticFeedback(int effectId, boolean always) {
5241 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005242 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005243 } catch (RemoteException e) {
5244 return false;
5245 }
5246 }
5247
5248 /**
5249 * {@inheritDoc}
5250 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005251 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005252 public View focusSearch(View focused, int direction) {
5253 checkThread();
5254 if (!(mView instanceof ViewGroup)) {
5255 return null;
5256 }
5257 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5258 }
5259
5260 public void debug() {
5261 mView.debug();
5262 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005263
Jeff Brown5182c782013-10-15 20:31:52 -07005264 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5265 String innerPrefix = prefix + " ";
5266 writer.print(prefix); writer.println("ViewRoot:");
5267 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5268 writer.print(" mRemoved="); writer.println(mRemoved);
5269 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5270 writer.println(mConsumeBatchedInputScheduled);
5271 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5272 writer.println(mPendingInputEventCount);
5273 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5274 writer.println(mProcessInputEventsScheduled);
5275 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5276 writer.print(mTraversalScheduled);
5277 if (mTraversalScheduled) {
5278 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5279 } else {
5280 writer.println();
5281 }
5282 mFirstInputStage.dump(innerPrefix, writer);
5283
5284 mChoreographer.dump(prefix, writer);
5285
5286 writer.print(prefix); writer.println("View Hierarchy:");
5287 dumpViewHierarchy(innerPrefix, writer, mView);
5288 }
5289
5290 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5291 writer.print(prefix);
5292 if (view == null) {
5293 writer.println("null");
5294 return;
5295 }
5296 writer.println(view.toString());
5297 if (!(view instanceof ViewGroup)) {
5298 return;
5299 }
5300 ViewGroup grp = (ViewGroup)view;
5301 final int N = grp.getChildCount();
5302 if (N <= 0) {
5303 return;
5304 }
5305 prefix = prefix + " ";
5306 for (int i=0; i<N; i++) {
5307 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5308 }
5309 }
5310
Romain Guy211370f2012-02-01 16:10:55 -08005311 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005312 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005313 if (mView != null) {
5314 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005315 }
5316 }
5317
Romain Guya998dff2012-03-23 18:58:36 -07005318 private static void getGfxInfo(View view, int[] info) {
Romain Guy65b345f2011-07-27 18:51:50 -07005319 DisplayList displayList = view.mDisplayList;
5320 info[0]++;
5321 if (displayList != null) {
5322 info[1] += displayList.getSize();
5323 }
5324
5325 if (view instanceof ViewGroup) {
5326 ViewGroup group = (ViewGroup) view;
5327
5328 int count = group.getChildCount();
5329 for (int i = 0; i < count; i++) {
5330 getGfxInfo(group.getChildAt(i), info);
5331 }
5332 }
5333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005334
Craig Mautner8f303ad2013-06-14 11:32:22 -07005335 /**
5336 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5337 * @return True, request has been queued. False, request has been completed.
5338 */
5339 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005340 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5341 // done by dispatchDetachedFromWindow will cause havoc on return.
5342 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005343 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005344 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005345 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005346
5347 if (!mIsDrawing) {
5348 destroyHardwareRenderer();
5349 } else {
5350 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5351 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5352 }
5353 mHandler.sendEmptyMessage(MSG_DIE);
5354 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005355 }
5356
5357 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005358 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005359 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005361 if (mRemoved) {
5362 return;
5363 }
5364 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005365 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005366 dispatchDetachedFromWindow();
5367 }
5368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005369 if (mAdded && !mFirst) {
Romain Guyfbb93fa2012-12-03 18:50:35 -08005370 invalidateDisplayLists();
Romain Guy29d89972010-09-22 16:10:57 -07005371 destroyHardwareRenderer();
5372
Romain Guyedbca122012-04-04 18:25:53 -07005373 if (mView != null) {
5374 int viewVisibility = mView.getVisibility();
5375 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5376 if (mWindowAttributesChanged || viewVisibilityChanged) {
5377 // If layout params have been changed, first give them
5378 // to the window manager to make sure it has the correct
5379 // animation info.
5380 try {
5381 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005382 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5383 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005384 }
5385 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005387 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005388
Romain Guyedbca122012-04-04 18:25:53 -07005389 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005391 }
Romain Guyedbca122012-04-04 18:25:53 -07005392
5393 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005395 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005396 }
5397
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005398 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005399 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5400 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005401 }
5402
Dianne Hackborna53de062012-05-08 18:53:51 -07005403 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005404 mHandler.post(new Runnable() {
5405 @Override
5406 public void run() {
5407 // Profiling
5408 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5409 profileRendering(mAttachInfo.mHasWindowFocus);
5410
Dan Morrille4d9a012013-03-28 18:10:43 -07005411 // Media (used by sound effects)
5412 mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
5413
Romain Guy5bb3c732012-11-29 17:52:58 -08005414 // Hardware rendering
5415 if (mAttachInfo.mHardwareRenderer != null) {
John Reckcec24ae2013-11-05 13:27:50 -08005416 if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08005417 invalidate();
5418 }
5419 }
5420
5421 // Layout debugging
5422 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5423 if (layout != mAttachInfo.mDebugLayout) {
5424 mAttachInfo.mDebugLayout = layout;
5425 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5426 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5427 }
5428 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005429 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005430 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005431 }
5432
Romain Guy29d89972010-09-22 16:10:57 -07005433 private void destroyHardwareRenderer() {
Romain Guya998dff2012-03-23 18:58:36 -07005434 AttachInfo attachInfo = mAttachInfo;
5435 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
5436
5437 if (hardwareRenderer != null) {
5438 if (mView != null) {
5439 hardwareRenderer.destroyHardwareResources(mView);
5440 }
5441 hardwareRenderer.destroy(true);
5442 hardwareRenderer.setRequested(false);
5443
5444 attachInfo.mHardwareRenderer = null;
5445 attachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005446 }
5447 }
5448
Jeff Browna175a5b2012-02-15 19:18:31 -08005449 public void dispatchFinishInputConnection(InputConnection connection) {
5450 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5451 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005453
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005454 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08005455 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005456 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5457 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005458 + " visibleInsets=" + visibleInsets.toShortString()
5459 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005460 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005461 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005462 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005463 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005464 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005465 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005466 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005467 SomeArgs args = SomeArgs.obtain();
5468 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5469 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5470 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5471 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5472 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005473 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005474 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005475 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005476 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005477
Craig Mautner5702d4d2012-06-30 14:10:16 -07005478 public void dispatchMoved(int newX, int newY) {
5479 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5480 if (mTranslator != null) {
5481 PointF point = new PointF(newX, newY);
5482 mTranslator.translatePointInScreenToAppWindow(point);
5483 newX = (int) (point.x + 0.5);
5484 newY = (int) (point.y + 0.5);
5485 }
5486 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5487 mHandler.sendMessage(msg);
5488 }
5489
Jeff Brown4952dfd2011-11-30 19:23:22 -08005490 /**
5491 * Represents a pending input event that is waiting in a queue.
5492 *
5493 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005494 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005495 * one input event to the application at a time and waits for the application
5496 * to finish handling it before delivering the next one.
5497 *
5498 * However, because the application or IME can synthesize and inject multiple
5499 * key events at a time without going through the input dispatcher, we end up
5500 * needing a queue on the application's side.
5501 */
5502 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005503 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5504 public static final int FLAG_DEFERRED = 1 << 1;
5505 public static final int FLAG_FINISHED = 1 << 2;
5506 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5507 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005508
5509 public QueuedInputEvent mNext;
5510
5511 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005512 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005513 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005514
5515 public boolean shouldSkipIme() {
5516 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5517 return true;
5518 }
5519 return mEvent instanceof MotionEvent
5520 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5521 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005522 }
5523
5524 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005525 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005526 QueuedInputEvent q = mQueuedInputEventPool;
5527 if (q != null) {
5528 mQueuedInputEventPoolSize -= 1;
5529 mQueuedInputEventPool = q.mNext;
5530 q.mNext = null;
5531 } else {
5532 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005533 }
5534
Jeff Brown4952dfd2011-11-30 19:23:22 -08005535 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005536 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005537 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005538 return q;
5539 }
5540
5541 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5542 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005543 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005544
5545 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5546 mQueuedInputEventPoolSize += 1;
5547 q.mNext = mQueuedInputEventPool;
5548 mQueuedInputEventPool = q;
5549 }
5550 }
5551
Jeff Brownf9261d22012-02-03 13:49:15 -08005552 void enqueueInputEvent(InputEvent event) {
5553 enqueueInputEvent(event, null, 0, false);
5554 }
5555
Jeff Brown4952dfd2011-11-30 19:23:22 -08005556 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005557 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005558 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005559
Jeff Brown4952dfd2011-11-30 19:23:22 -08005560 // Always enqueue the input event in order, regardless of its time stamp.
5561 // We do this because the application or the IME may inject key events
5562 // in response to touch events and we want to ensure that the injected keys
5563 // are processed in the order they were received and we cannot trust that
5564 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005565 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005566 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005567 mPendingInputEventHead = q;
5568 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005569 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005570 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005571 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005572 }
Michael Wright95ae9422013-03-14 10:58:50 -07005573 mPendingInputEventCount += 1;
5574 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5575 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005576
Jeff Brownf9261d22012-02-03 13:49:15 -08005577 if (processImmediately) {
5578 doProcessInputEvents();
5579 } else {
5580 scheduleProcessInputEvents();
5581 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005582 }
5583
5584 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005585 if (!mProcessInputEventsScheduled) {
5586 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005587 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5588 msg.setAsynchronous(true);
5589 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005590 }
5591 }
5592
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005593 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005594 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005595 while (mPendingInputEventHead != null) {
5596 QueuedInputEvent q = mPendingInputEventHead;
5597 mPendingInputEventHead = q.mNext;
5598 if (mPendingInputEventHead == null) {
5599 mPendingInputEventTail = null;
5600 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005601 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005602
Michael Wright95ae9422013-03-14 10:58:50 -07005603 mPendingInputEventCount -= 1;
5604 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5605 mPendingInputEventCount);
5606
Jeff Brownf9e989d2013-04-04 23:04:03 -07005607 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005608 }
5609
5610 // We are done processing all input events that we can process right now
5611 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005612 if (mProcessInputEventsScheduled) {
5613 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005614 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005615 }
5616 }
5617
Jeff Brownf9e989d2013-04-04 23:04:03 -07005618 private void deliverInputEvent(QueuedInputEvent q) {
5619 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
5620 try {
5621 if (mInputEventConsistencyVerifier != null) {
5622 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5623 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005624
Jeff Brownf9e989d2013-04-04 23:04:03 -07005625 InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5626 if (stage != null) {
5627 stage.deliver(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005628 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005629 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005630 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005631 } finally {
5632 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Michael Wrightbf020962013-03-28 17:27:50 -07005633 }
Michael Wrightbf020962013-03-28 17:27:50 -07005634 }
5635
Jeff Brownf9e989d2013-04-04 23:04:03 -07005636 private void finishInputEvent(QueuedInputEvent q) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005637 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005638 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005639 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005640 } else {
5641 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005642 }
5643
5644 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005645 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005646
Jeff Brownf9e989d2013-04-04 23:04:03 -07005647 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005648 if (event instanceof KeyEvent) {
5649 final KeyEvent keyEvent = (KeyEvent)event;
5650 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5651 } else {
5652 final MotionEvent motionEvent = (MotionEvent)event;
5653 final int action = motionEvent.getAction();
5654 return action == MotionEvent.ACTION_UP
5655 || action == MotionEvent.ACTION_CANCEL
5656 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005657 }
5658 }
5659
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005660 void scheduleConsumeBatchedInput() {
5661 if (!mConsumeBatchedInputScheduled) {
5662 mConsumeBatchedInputScheduled = true;
5663 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5664 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005665 }
5666 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005667
5668 void unscheduleConsumeBatchedInput() {
5669 if (mConsumeBatchedInputScheduled) {
5670 mConsumeBatchedInputScheduled = false;
5671 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5672 mConsumedBatchedInputRunnable, null);
5673 }
5674 }
5675
Jeff Brown771526c2012-04-27 15:13:25 -07005676 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005677 if (mConsumeBatchedInputScheduled) {
5678 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005679 if (mInputEventReceiver != null) {
Michael Wright62ce65d2013-10-25 14:50:36 -07005680 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)) {
5681 // If we consumed a batch here, we want to go ahead and schedule the
5682 // consumption of batched input events on the next frame. Otherwise, we would
5683 // wait until we have more input events pending and might get starved by other
5684 // things occurring in the process.
5685 scheduleConsumeBatchedInput();
5686 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005687 }
Jeff Brown330314c2012-04-27 02:20:22 -07005688 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005689 }
5690 }
5691
5692 final class TraversalRunnable implements Runnable {
5693 @Override
5694 public void run() {
5695 doTraversal();
5696 }
5697 }
5698 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005699
Jeff Brown32cbc38552011-12-01 14:01:49 -08005700 final class WindowInputEventReceiver extends InputEventReceiver {
5701 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5702 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005703 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005704
5705 @Override
5706 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005707 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005708 }
Jeff Brown072ec962012-02-07 14:46:57 -08005709
5710 @Override
5711 public void onBatchedInputEventPending() {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005712 scheduleConsumeBatchedInput();
5713 }
5714
5715 @Override
5716 public void dispose() {
5717 unscheduleConsumeBatchedInput();
5718 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005719 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005720 }
5721 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005722
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005723 final class ConsumeBatchedInputRunnable implements Runnable {
5724 @Override
5725 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005726 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005727 }
5728 }
5729 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5730 new ConsumeBatchedInputRunnable();
5731 boolean mConsumeBatchedInputScheduled;
5732
Jeff Brown6cb7b462012-03-05 13:21:17 -08005733 final class InvalidateOnAnimationRunnable implements Runnable {
5734 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005735 private final ArrayList<View> mViews = new ArrayList<View>();
5736 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08005737 new ArrayList<AttachInfo.InvalidateInfo>();
5738 private View[] mTempViews;
5739 private AttachInfo.InvalidateInfo[] mTempViewRects;
5740
5741 public void addView(View view) {
5742 synchronized (this) {
5743 mViews.add(view);
5744 postIfNeededLocked();
5745 }
5746 }
5747
5748 public void addViewRect(AttachInfo.InvalidateInfo info) {
5749 synchronized (this) {
5750 mViewRects.add(info);
5751 postIfNeededLocked();
5752 }
5753 }
5754
5755 public void removeView(View view) {
5756 synchronized (this) {
5757 mViews.remove(view);
5758
5759 for (int i = mViewRects.size(); i-- > 0; ) {
5760 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5761 if (info.target == view) {
5762 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005763 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005764 }
5765 }
5766
5767 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005768 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005769 mPosted = false;
5770 }
5771 }
5772 }
5773
5774 @Override
5775 public void run() {
5776 final int viewCount;
5777 final int viewRectCount;
5778 synchronized (this) {
5779 mPosted = false;
5780
5781 viewCount = mViews.size();
5782 if (viewCount != 0) {
5783 mTempViews = mViews.toArray(mTempViews != null
5784 ? mTempViews : new View[viewCount]);
5785 mViews.clear();
5786 }
5787
5788 viewRectCount = mViewRects.size();
5789 if (viewRectCount != 0) {
5790 mTempViewRects = mViewRects.toArray(mTempViewRects != null
5791 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
5792 mViewRects.clear();
5793 }
5794 }
5795
5796 for (int i = 0; i < viewCount; i++) {
5797 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07005798 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08005799 }
5800
5801 for (int i = 0; i < viewRectCount; i++) {
5802 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
5803 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005804 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005805 }
5806 }
5807
5808 private void postIfNeededLocked() {
5809 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005810 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005811 mPosted = true;
5812 }
5813 }
5814 }
5815 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
5816 new InvalidateOnAnimationRunnable();
5817
Jeff Browna175a5b2012-02-15 19:18:31 -08005818 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
5819 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
5820 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5821 }
5822
Jeff Browna175a5b2012-02-15 19:18:31 -08005823 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
5824 long delayMilliseconds) {
5825 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
5826 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5827 }
5828
Jeff Brown6cb7b462012-03-05 13:21:17 -08005829 public void dispatchInvalidateOnAnimation(View view) {
5830 mInvalidateOnAnimationRunnable.addView(view);
5831 }
5832
5833 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
5834 mInvalidateOnAnimationRunnable.addViewRect(info);
5835 }
5836
Romain Guy2a0f2282012-05-08 14:43:12 -07005837 public void enqueueDisplayList(DisplayList displayList) {
Romain Guy51e4d4d2012-03-15 18:30:47 -07005838 mDisplayLists.add(displayList);
Romain Guy2a0f2282012-05-08 14:43:12 -07005839 }
5840
Jeff Brown6cb7b462012-03-05 13:21:17 -08005841 public void cancelInvalidate(View view) {
5842 mHandler.removeMessages(MSG_INVALIDATE, view);
5843 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
5844 // them to the pool
5845 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
5846 mInvalidateOnAnimationRunnable.removeView(view);
5847 }
5848
keunyoung30f420f2013-08-02 14:23:10 -07005849 public void dispatchInputEvent(InputEvent event) {
5850 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005851 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005852 mHandler.sendMessage(msg);
5853 }
5854
5855 public void dispatchKeyFromIme(KeyEvent event) {
5856 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005857 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005858 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08005859 }
5860
John Reckd6b10982012-04-19 18:01:35 -07005861 public void dispatchUnhandledKey(KeyEvent event) {
5862 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
Michael Wright916b6492013-12-03 16:53:03 -08005863 // Some fallback keys are decided by the ViewRoot as they might have special
5864 // properties (e.g. are locale aware). These take precedence over fallbacks defined by
5865 // the kcm.
5866 KeyEvent fallbackEvent = getSyntheticFallbackKey(event);
John Reckd6b10982012-04-19 18:01:35 -07005867
Michael Wright916b6492013-12-03 16:53:03 -08005868 if (fallbackEvent == null) {
5869 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5870 final int keyCode = event.getKeyCode();
5871 final int metaState = event.getMetaState();
Jeff Brownfd23e3e2012-05-09 13:34:28 -07005872
Michael Wright916b6492013-12-03 16:53:03 -08005873 // Check for fallback actions specified by the key character map.
5874 KeyCharacterMap.FallbackAction fallbackAction =
5875 kcm.getFallbackAction(keyCode, metaState);
5876 if (fallbackAction != null) {
5877 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5878 fallbackEvent = KeyEvent.obtain(
5879 event.getDownTime(), event.getEventTime(),
5880 event.getAction(), fallbackAction.keyCode,
5881 event.getRepeatCount(), fallbackAction.metaState,
5882 event.getDeviceId(), event.getScanCode(),
5883 flags, event.getSource(), null);
5884 fallbackAction.recycle();
5885
5886 }
5887 }
5888 if (fallbackEvent != null) {
keunyoung30f420f2013-08-02 14:23:10 -07005889 dispatchInputEvent(fallbackEvent);
John Reckd6b10982012-04-19 18:01:35 -07005890 }
5891 }
5892 }
5893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005894 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005895 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005896 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005897 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005898 }
5899
Romain Guybb9908b2012-03-08 11:14:07 -08005900 public void dispatchScreenStateChange(boolean on) {
5901 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
Romain Guy7e4e5612012-03-05 14:37:29 -08005902 msg.arg1 = on ? 1 : 0;
5903 mHandler.sendMessage(msg);
5904 }
5905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005906 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08005907 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
5908 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005909 }
5910
5911 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
5912 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005913 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005914 msg.arg1 = hasFocus ? 1 : 0;
5915 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005916 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005917 }
5918
Dianne Hackbornffa42482009-09-23 22:20:11 -07005919 public void dispatchCloseSystemDialogs(String reason) {
5920 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005921 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07005922 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08005923 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07005924 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005925
5926 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07005927 final int what;
5928 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005929 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
5930 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07005931 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08005932 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07005933 }
Jeff Browna175a5b2012-02-15 19:18:31 -08005934 Message msg = mHandler.obtainMessage(what, event);
5935 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07005936 }
5937
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005938 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
5939 int localValue, int localChanges) {
5940 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
5941 args.seq = seq;
5942 args.globalVisibility = globalVisibility;
5943 args.localValue = localValue;
5944 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08005945 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
5946 }
5947
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005948 public void dispatchDoneAnimating() {
5949 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
5950 }
5951
Jeff Browna175a5b2012-02-15 19:18:31 -08005952 public void dispatchCheckFocus() {
5953 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
5954 // This will result in a call to checkFocus() below.
5955 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
5956 }
Joe Onorato664644d2011-01-23 17:53:23 -08005957 }
5958
svetoslavganov75986cf2009-05-14 22:28:01 -07005959 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005960 * Post a callback to send a
5961 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07005962 * This event is send at most once every
5963 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005964 */
Alan Viverette77e9a282013-09-12 17:16:09 -07005965 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005966 if (mSendWindowContentChangedAccessibilityEvent == null) {
5967 mSendWindowContentChangedAccessibilityEvent =
5968 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005969 }
Alan Viverette77e9a282013-09-12 17:16:09 -07005970 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005971 }
5972
5973 /**
5974 * Remove a posted callback to send a
5975 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
5976 */
5977 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005978 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005979 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005980 }
5981 }
5982
Igor Murashkina86ab6402013-08-30 12:58:36 -07005983 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005984 public boolean showContextMenuForChild(View originalView) {
5985 return false;
5986 }
5987
Igor Murashkina86ab6402013-08-30 12:58:36 -07005988 @Override
Adam Powell6e346362010-07-23 10:18:23 -07005989 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
5990 return null;
5991 }
5992
Igor Murashkina86ab6402013-08-30 12:58:36 -07005993 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005994 public void createContextMenu(ContextMenu menu) {
5995 }
5996
Igor Murashkina86ab6402013-08-30 12:58:36 -07005997 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005998 public void childDrawableStateChanged(View child) {
5999 }
6000
Igor Murashkina86ab6402013-08-30 12:58:36 -07006001 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006002 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
6003 if (mView == null) {
6004 return false;
6005 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006006 // Intercept accessibility focus events fired by virtual nodes to keep
6007 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006008 final int eventType = event.getEventType();
6009 switch (eventType) {
6010 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006011 final long sourceNodeId = event.getSourceNodeId();
6012 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6013 sourceNodeId);
6014 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6015 if (source != null) {
6016 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6017 if (provider != null) {
6018 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
6019 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
6020 setAccessibilityFocus(source, node);
6021 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006022 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006023 } break;
6024 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006025 final long sourceNodeId = event.getSourceNodeId();
6026 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6027 sourceNodeId);
6028 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6029 if (source != null) {
6030 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6031 if (provider != null) {
6032 setAccessibilityFocus(null, null);
6033 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006034 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006035 } break;
6036 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006037 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006038 return true;
6039 }
6040
Svetoslav Ganov42138042012-03-20 11:51:39 -07006041 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006042 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6043 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006044 }
6045
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006046 @Override
6047 public boolean canResolveLayoutDirection() {
6048 return true;
6049 }
6050
6051 @Override
6052 public boolean isLayoutDirectionResolved() {
6053 return true;
6054 }
6055
6056 @Override
6057 public int getLayoutDirection() {
6058 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6059 }
6060
6061 @Override
6062 public boolean canResolveTextDirection() {
6063 return true;
6064 }
6065
6066 @Override
6067 public boolean isTextDirectionResolved() {
6068 return true;
6069 }
6070
6071 @Override
6072 public int getTextDirection() {
6073 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6074 }
6075
6076 @Override
6077 public boolean canResolveTextAlignment() {
6078 return true;
6079 }
6080
6081 @Override
6082 public boolean isTextAlignmentResolved() {
6083 return true;
6084 }
6085
6086 @Override
6087 public int getTextAlignment() {
6088 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6089 }
6090
Svetoslav Ganov42138042012-03-20 11:51:39 -07006091 private View getCommonPredecessor(View first, View second) {
6092 if (mAttachInfo != null) {
6093 if (mTempHashSet == null) {
6094 mTempHashSet = new HashSet<View>();
6095 }
6096 HashSet<View> seen = mTempHashSet;
6097 seen.clear();
6098 View firstCurrent = first;
6099 while (firstCurrent != null) {
6100 seen.add(firstCurrent);
6101 ViewParent firstCurrentParent = firstCurrent.mParent;
6102 if (firstCurrentParent instanceof View) {
6103 firstCurrent = (View) firstCurrentParent;
6104 } else {
6105 firstCurrent = null;
6106 }
6107 }
6108 View secondCurrent = second;
6109 while (secondCurrent != null) {
6110 if (seen.contains(secondCurrent)) {
6111 seen.clear();
6112 return secondCurrent;
6113 }
6114 ViewParent secondCurrentParent = secondCurrent.mParent;
6115 if (secondCurrentParent instanceof View) {
6116 secondCurrent = (View) secondCurrentParent;
6117 } else {
6118 secondCurrent = null;
6119 }
6120 }
6121 seen.clear();
6122 }
6123 return null;
6124 }
6125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006126 void checkThread() {
6127 if (mThread != Thread.currentThread()) {
6128 throw new CalledFromWrongThreadException(
6129 "Only the original thread that created a view hierarchy can touch its views.");
6130 }
6131 }
6132
Igor Murashkina86ab6402013-08-30 12:58:36 -07006133 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006134 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006135 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006136 }
6137
Igor Murashkina86ab6402013-08-30 12:58:36 -07006138 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006139 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
6140 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
6141 if (rectangle != null) {
6142 mTempRect.set(rectangle);
6143 mTempRect.offset(0, -mCurScrollY);
6144 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6145 try {
6146 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
6147 } catch (RemoteException re) {
6148 /* ignore */
6149 }
6150 }
6151 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006152 }
Romain Guy8506ab42009-06-11 17:35:47 -07006153
Igor Murashkina86ab6402013-08-30 12:58:36 -07006154 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006155 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6156 // Do nothing.
6157 }
6158
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006159 void changeCanvasOpacity(boolean opaque) {
6160 // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
6161 Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
6162 }
6163
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006164 class TakenSurfaceHolder extends BaseSurfaceHolder {
6165 @Override
6166 public boolean onAllowLockCanvas() {
6167 return mDrawingAllowed;
6168 }
6169
6170 @Override
6171 public void onRelayoutContainer() {
6172 // Not currently interesting -- from changing between fixed and layout size.
6173 }
6174
Igor Murashkina86ab6402013-08-30 12:58:36 -07006175 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006176 public void setFormat(int format) {
6177 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6178 }
6179
Igor Murashkina86ab6402013-08-30 12:58:36 -07006180 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006181 public void setType(int type) {
6182 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6183 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006184
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006185 @Override
6186 public void onUpdateSurface() {
6187 // We take care of format and type changes on our own.
6188 throw new IllegalStateException("Shouldn't be here");
6189 }
6190
Igor Murashkina86ab6402013-08-30 12:58:36 -07006191 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006192 public boolean isCreating() {
6193 return mIsCreating;
6194 }
6195
6196 @Override
6197 public void setFixedSize(int width, int height) {
6198 throw new UnsupportedOperationException(
6199 "Currently only support sizing from layout");
6200 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006201
6202 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006203 public void setKeepScreenOn(boolean screenOn) {
6204 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6205 }
6206 }
Romain Guy8506ab42009-06-11 17:35:47 -07006207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006208 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006209 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006210 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006211
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006212 W(ViewRootImpl viewAncestor) {
6213 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006214 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006215 }
6216
Igor Murashkina86ab6402013-08-30 12:58:36 -07006217 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006218 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -07006219 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006220 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006221 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006222 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07006223 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006224 }
6225 }
6226
Craig Mautner5702d4d2012-06-30 14:10:16 -07006227 @Override
6228 public void moved(int newX, int newY) {
6229 final ViewRootImpl viewAncestor = mViewAncestor.get();
6230 if (viewAncestor != null) {
6231 viewAncestor.dispatchMoved(newX, newY);
6232 }
6233 }
6234
Igor Murashkina86ab6402013-08-30 12:58:36 -07006235 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006236 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006237 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006238 if (viewAncestor != null) {
6239 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006240 }
6241 }
6242
Igor Murashkina86ab6402013-08-30 12:58:36 -07006243 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08006244 public void dispatchScreenState(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -08006245 final ViewRootImpl viewAncestor = mViewAncestor.get();
6246 if (viewAncestor != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08006247 viewAncestor.dispatchScreenStateChange(on);
Romain Guy7e4e5612012-03-05 14:37:29 -08006248 }
6249 }
Romain Guybb9908b2012-03-08 11:14:07 -08006250
Igor Murashkina86ab6402013-08-30 12:58:36 -07006251 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006252 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006253 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006254 if (viewAncestor != null) {
6255 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006256 }
6257 }
6258
Igor Murashkina86ab6402013-08-30 12:58:36 -07006259 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006260 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006261 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006262 if (viewAncestor != null) {
6263 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006264 }
6265 }
6266
6267 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006268 try {
6269 return ActivityManagerNative.getDefault().checkPermission(
6270 permission, Binder.getCallingPid(), Binder.getCallingUid());
6271 } catch (RemoteException e) {
6272 return PackageManager.PERMISSION_DENIED;
6273 }
6274 }
6275
Igor Murashkina86ab6402013-08-30 12:58:36 -07006276 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006277 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006278 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006279 if (viewAncestor != null) {
6280 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006281 if (view != null) {
6282 if (checkCallingPermission(Manifest.permission.DUMP) !=
6283 PackageManager.PERMISSION_GRANTED) {
6284 throw new SecurityException("Insufficient permissions to invoke"
6285 + " executeCommand() from pid=" + Binder.getCallingPid()
6286 + ", uid=" + Binder.getCallingUid());
6287 }
6288
6289 OutputStream clientStream = null;
6290 try {
6291 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6292 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6293 } catch (IOException e) {
6294 e.printStackTrace();
6295 } finally {
6296 if (clientStream != null) {
6297 try {
6298 clientStream.close();
6299 } catch (IOException e) {
6300 e.printStackTrace();
6301 }
6302 }
6303 }
6304 }
6305 }
6306 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006307
6308 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006309 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006310 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006311 if (viewAncestor != null) {
6312 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006313 }
6314 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006315
6316 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006317 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6318 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006319 if (sync) {
6320 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006321 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006322 } catch (RemoteException e) {
6323 }
6324 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006325 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006326
Igor Murashkina86ab6402013-08-30 12:58:36 -07006327 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07006328 public void dispatchWallpaperCommand(String action, int x, int y,
6329 int z, Bundle extras, boolean sync) {
6330 if (sync) {
6331 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006332 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006333 } catch (RemoteException e) {
6334 }
6335 }
6336 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006337
6338 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006339 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07006340 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006341 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006342 if (viewAncestor != null) {
6343 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006344 }
6345 }
Joe Onorato664644d2011-01-23 17:53:23 -08006346
Igor Murashkina86ab6402013-08-30 12:58:36 -07006347 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006348 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6349 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006350 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006351 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006352 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6353 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006354 }
6355 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006356
Igor Murashkina86ab6402013-08-30 12:58:36 -07006357 @Override
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006358 public void doneAnimating() {
6359 final ViewRootImpl viewAncestor = mViewAncestor.get();
6360 if (viewAncestor != null) {
6361 viewAncestor.dispatchDoneAnimating();
6362 }
6363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006364 }
6365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006366 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6367 public CalledFromWrongThreadException(String msg) {
6368 super(msg);
6369 }
6370 }
6371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006372 static RunQueue getRunQueue() {
6373 RunQueue rq = sRunQueues.get();
6374 if (rq != null) {
6375 return rq;
6376 }
6377 rq = new RunQueue();
6378 sRunQueues.set(rq);
6379 return rq;
6380 }
Romain Guy8506ab42009-06-11 17:35:47 -07006381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006382 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08006383 * The run queue is used to enqueue pending work from Views when no Handler is
6384 * attached. The work is executed during the next call to performTraversals on
6385 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006386 * @hide
6387 */
6388 static final class RunQueue {
6389 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
6390
6391 void post(Runnable action) {
6392 postDelayed(action, 0);
6393 }
6394
6395 void postDelayed(Runnable action, long delayMillis) {
6396 HandlerAction handlerAction = new HandlerAction();
6397 handlerAction.action = action;
6398 handlerAction.delay = delayMillis;
6399
6400 synchronized (mActions) {
6401 mActions.add(handlerAction);
6402 }
6403 }
6404
6405 void removeCallbacks(Runnable action) {
6406 final HandlerAction handlerAction = new HandlerAction();
6407 handlerAction.action = action;
6408
6409 synchronized (mActions) {
6410 final ArrayList<HandlerAction> actions = mActions;
6411
6412 while (actions.remove(handlerAction)) {
6413 // Keep going
6414 }
6415 }
6416 }
6417
6418 void executeActions(Handler handler) {
6419 synchronized (mActions) {
6420 final ArrayList<HandlerAction> actions = mActions;
6421 final int count = actions.size();
6422
6423 for (int i = 0; i < count; i++) {
6424 final HandlerAction handlerAction = actions.get(i);
6425 handler.postDelayed(handlerAction.action, handlerAction.delay);
6426 }
6427
Romain Guy15df6702009-08-17 20:17:30 -07006428 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006429 }
6430 }
6431
6432 private static class HandlerAction {
6433 Runnable action;
6434 long delay;
6435
6436 @Override
6437 public boolean equals(Object o) {
6438 if (this == o) return true;
6439 if (o == null || getClass() != o.getClass()) return false;
6440
6441 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006442 return !(action != null ? !action.equals(that.action) : that.action != null);
6443
6444 }
6445
6446 @Override
6447 public int hashCode() {
6448 int result = action != null ? action.hashCode() : 0;
6449 result = 31 * result + (int) (delay ^ (delay >>> 32));
6450 return result;
6451 }
6452 }
6453 }
6454
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006455 /**
6456 * Class for managing the accessibility interaction connection
6457 * based on the global accessibility state.
6458 */
6459 final class AccessibilityInteractionConnectionManager
6460 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07006461 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006462 public void onAccessibilityStateChanged(boolean enabled) {
6463 if (enabled) {
6464 ensureConnection();
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006465 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6466 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6467 View focusedView = mView.findFocus();
6468 if (focusedView != null && focusedView != mView) {
6469 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6470 }
6471 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006472 } else {
6473 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006474 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006475 }
6476 }
6477
6478 public void ensureConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006479 if (mAttachInfo != null) {
6480 final boolean registered =
6481 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
6482 if (!registered) {
6483 mAttachInfo.mAccessibilityWindowId =
6484 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6485 new AccessibilityInteractionConnection(ViewRootImpl.this));
6486 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006487 }
6488 }
6489
6490 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006491 final boolean registered =
6492 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006493 if (registered) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006494 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006495 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6496 }
6497 }
6498 }
6499
6500 /**
6501 * This class is an interface this ViewAncestor provides to the
6502 * AccessibilityManagerService to the latter can interact with
6503 * the view hierarchy in this ViewAncestor.
6504 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006505 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006506 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006507 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006508
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006509 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6510 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006511 }
6512
Svetoslav Ganov42138042012-03-20 11:51:39 -07006513 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006514 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006515 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006516 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006517 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6518 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006519 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006520 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006521 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6522 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006523 } else {
6524 // We cannot make the call and notify the caller so it does not wait.
6525 try {
6526 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6527 } catch (RemoteException re) {
6528 /* best effort - ignore */
6529 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006530 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006531 }
6532
Svetoslav Ganov42138042012-03-20 11:51:39 -07006533 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006534 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006535 Bundle arguments, int interactionId,
6536 IAccessibilityInteractionConnectionCallback callback, int flags,
6537 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006538 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6539 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006540 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006541 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006542 interactionId, callback, flags, interogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006543 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006544 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006545 try {
6546 callback.setPerformAccessibilityActionResult(false, interactionId);
6547 } catch (RemoteException re) {
6548 /* best effort - ignore */
6549 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006550 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006551 }
6552
Svetoslav Ganov42138042012-03-20 11:51:39 -07006553 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006554 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
6555 String viewId, int interactionId,
6556 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006557 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006558 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6559 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006560 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006561 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
6562 viewId, interactionId, callback, flags, interrogatingPid,
6563 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006564 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006565 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006566 try {
6567 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6568 } catch (RemoteException re) {
6569 /* best effort - ignore */
6570 }
6571 }
6572 }
6573
Svetoslav Ganov42138042012-03-20 11:51:39 -07006574 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006575 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006576 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006577 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006578 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6579 if (viewRootImpl != null && viewRootImpl.mView != null) {
6580 viewRootImpl.getAccessibilityInteractionController()
6581 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006582 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6583 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006584 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006585 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006586 try {
6587 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6588 } catch (RemoteException re) {
6589 /* best effort - ignore */
6590 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006591 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006592 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006593
Svetoslav Ganov42138042012-03-20 11:51:39 -07006594 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006595 public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
Svetoslav Ganov86783472012-06-06 21:12:20 -07006596 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006597 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006598 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6599 if (viewRootImpl != null && viewRootImpl.mView != null) {
6600 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006601 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006602 flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006603 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006604 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006605 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006606 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006607 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006608 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006609 }
6610 }
6611 }
6612
Svetoslav Ganov42138042012-03-20 11:51:39 -07006613 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006614 public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006615 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006616 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006617 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6618 if (viewRootImpl != null && viewRootImpl.mView != null) {
6619 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006620 .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006621 callback, flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006622 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006623 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006624 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006625 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006626 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006627 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006628 }
6629 }
6630 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006631 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006632
Svetoslav Ganova0156172011-06-26 17:55:44 -07006633 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07006634 private int mChangeTypes = 0;
6635
Svetoslav Ganov42138042012-03-20 11:51:39 -07006636 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07006637 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006638
Igor Murashkina86ab6402013-08-30 12:58:36 -07006639 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006640 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07006641 // The accessibility may be turned off while we were waiting so check again.
6642 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6643 mLastEventTimeMillis = SystemClock.uptimeMillis();
6644 AccessibilityEvent event = AccessibilityEvent.obtain();
6645 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07006646 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07006647 mSource.sendAccessibilityEventUnchecked(event);
6648 } else {
6649 mLastEventTimeMillis = 0;
6650 }
6651 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07006652 mSource.resetSubtreeAccessibilityStateChanged();
6653 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07006654 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07006655 }
6656
Alan Viverette77e9a282013-09-12 17:16:09 -07006657 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006658 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006659 // If there is no common predecessor, then mSource points to
6660 // a removed view, hence in this case always prefer the source.
6661 View predecessor = getCommonPredecessor(mSource, source);
6662 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006663 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006664 return;
6665 }
6666 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006667 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006668 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
6669 final long minEventIntevalMillis =
6670 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
6671 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006672 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07006673 run();
6674 } else {
6675 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006676 }
6677 }
6678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006679}