blob: d779628571bff09d455bb94a91b93971ff57e3d6 [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;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080031import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070033import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070034import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070035import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.graphics.Rect;
37import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070038import android.graphics.drawable.Drawable;
Romain Guy6b7bd242010-10-06 19:49:23 -070039import android.media.AudioManager;
40import android.os.Binder;
41import android.os.Bundle;
42import android.os.Debug;
43import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070044import android.os.Looper;
45import android.os.Message;
46import android.os.ParcelFileDescriptor;
Romain Guy7e4e5612012-03-05 14:37:29 -080047import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070049import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070050import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070051import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080052import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070054import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070055import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070056import android.util.Slog;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080057import android.util.TypedValue;
Jeff Browna175a5b2012-02-15 19:18:31 -080058import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070060import android.view.accessibility.AccessibilityEvent;
61import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070062import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
63import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganov02107852011-10-03 17:06:56 -070064import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070065import android.view.accessibility.IAccessibilityInteractionConnection;
66import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080067import android.view.animation.AccelerateDecelerateInterpolator;
68import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.view.inputmethod.InputConnection;
70import android.view.inputmethod.InputMethodManager;
Igor Murashkina86ab6402013-08-30 12:58:36 -070071import android.view.Surface.OutOfResourcesException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070073
Svetoslav Ganov42138042012-03-20 11:51:39 -070074import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070075import com.android.internal.os.SomeArgs;
Joe Onorato86f67862010-11-05 18:57:34 -070076import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070077import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070078import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Jeff Brown5182c782013-10-15 20:31:52 -070080import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import java.io.IOException;
82import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070083import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070084import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070086import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088/**
89 * The top of a view hierarchy, implementing the needed protocol between View
90 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070091 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 *
93 * {@hide}
94 */
Romain Guy812ccbe2010-06-01 14:07:24 -070095@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -080096public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -080097 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -070098 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700100 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 /** @noinspection PointlessBooleanExpression*/
102 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
103 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800104 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
106 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
107 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
108 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700109 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700110 private static final boolean DEBUG_FPS = false;
Michael Wrightc8a7e542013-03-20 17:58:33 -0700111 private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
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
235 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700236 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
238 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700239 // Surface can never be reassigned or cleared (use Surface.clear()).
240 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
242 boolean mAdded;
243 boolean mAddedTouchMode;
244
Craig Mautner48d0d182013-06-11 07:53:06 -0700245 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 // These are accessed by multiple threads.
248 final Rect mWinFrame; // frame given by window manager.
249
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800250 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 final Rect mPendingVisibleInsets = new Rect();
252 final Rect mPendingContentInsets = new Rect();
253 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
254 = new ViewTreeObserver.InternalInsetsInfo();
255
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700256 final Rect mFitSystemWindowsInsets = new Rect();
257
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700258 final Configuration mLastConfiguration = new Configuration();
259 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 boolean mScrollMayChange;
262 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800263 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 int mScrollY;
265 int mCurScrollY;
266 Scroller mScroller;
Romain Guy7d70fbf2011-05-24 17:40:25 -0700267 HardwareLayer mResizeBuffer;
268 long mResizeBufferStartTime;
269 int mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800270 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700271 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700272
Romain Guy8506ab42009-06-11 17:35:47 -0700273 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
Christopher Tatea53146c2010-09-07 11:57:52 -0700275 /* Drag/drop */
276 ClipDescription mDragDescription;
277 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800278 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700279 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700280 final PointF mLastTouchPoint = new PointF();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700281
282 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800283 private Choreographer.FrameCallback mRenderProfiler;
284 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700285
Dan Morrille4d9a012013-03-28 18:10:43 -0700286 private boolean mMediaDisabled;
287
Chet Haase2f2022a2011-10-11 06:41:59 -0700288 // Variables to track frames per second, enabled via DEBUG_FPS flag
289 private long mFpsStartTime = -1;
290 private long mFpsPrevTime = -1;
291 private int mFpsNumFrames;
292
Romain Guyfbb93fa2012-12-03 18:50:35 -0800293 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 /**
296 * see {@link #playSoundEffect(int)}
297 */
298 AudioManager mAudioManager;
299
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700300 final AccessibilityManager mAccessibilityManager;
301
Gilles Debunne5ac84422011-10-19 09:35:58 -0700302 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700303
304 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
305
Svetoslav Ganova0156172011-06-26 17:55:44 -0700306 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700307
Svetoslav Ganov42138042012-03-20 11:51:39 -0700308 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800309
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700310 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700311 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700312
Chet Haase97140572012-09-13 14:56:47 -0700313 private boolean mInLayout = false;
314 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
315 boolean mHandlingLayoutInLayoutRequest = false;
316
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700317 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700318
Craig Mautner8f303ad2013-06-14 11:32:22 -0700319 /** Set to true once doDie() has been called. */
320 private boolean mRemoved;
321
Jeff Brown21bc5c92011-02-28 18:27:14 -0800322 /**
323 * Consistency verifier for debugging purposes.
324 */
325 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
326 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
327 new InputEventConsistencyVerifier(this, 0) : null;
328
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700329 static final class SystemUiVisibilityInfo {
330 int seq;
331 int globalVisibility;
332 int localValue;
333 int localChanges;
334 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700335
Jeff Brown98365d72012-08-19 20:30:52 -0700336 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700337 mContext = context;
338 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700339 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800340 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700341
Craig Mautner48d0d182013-06-11 07:53:06 -0700342 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 mThread = Thread.currentThread();
345 mLocation = new WindowLeaked(null);
346 mLocation.fillInStackTrace();
347 mWidth = -1;
348 mHeight = -1;
349 mDirty = new Rect();
350 mTempRect = new Rect();
351 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700353 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700354 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 mViewVisibility = View.GONE;
356 mTransparentRegion = new Region();
357 mPreviousTransparentRegion = new Region();
358 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700360 mAccessibilityManager = AccessibilityManager.getInstance(context);
361 mAccessibilityInteractionConnectionManager =
362 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800363 mAccessibilityManager.addAccessibilityStateChangeListener(
364 mAccessibilityInteractionConnectionManager);
Jeff Brown98365d72012-08-19 20:30:52 -0700365 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700367 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700368 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700369 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800370 mChoreographer = Choreographer.getInstance();
Romain Guy7e4e5612012-03-05 14:37:29 -0800371
372 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
373 mAttachInfo.mScreenOn = powerManager.isScreenOn();
Dianne Hackborna53de062012-05-08 18:53:51 -0700374 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800377 public static void addFirstDrawHandler(Runnable callback) {
378 synchronized (sFirstDrawHandlers) {
379 if (!sFirstDrawComplete) {
380 sFirstDrawHandlers.add(callback);
381 }
382 }
383 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700384
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800385 public static void addConfigCallback(ComponentCallbacks callback) {
386 synchronized (sConfigCallbacks) {
387 sConfigCallbacks.add(callback);
388 }
389 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 // FIXME for perf testing only
392 private boolean mProfile = false;
393
394 /**
395 * Call this to profile the next traversal call.
396 * FIXME for perf testing only. Remove eventually
397 */
398 public void profile() {
399 mProfile = true;
400 }
401
402 /**
403 * Indicates whether we are in touch mode. Calling this method triggers an IPC
404 * call and should be avoided whenever possible.
405 *
406 * @return True, if the device is in touch mode, false otherwise.
407 *
408 * @hide
409 */
410 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700411 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
412 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700414 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 } catch (RemoteException e) {
416 }
417 }
418 return false;
419 }
420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 /**
422 * We have one child
423 */
Romain Guye4d01122010-06-16 18:44:05 -0700424 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 synchronized (this) {
426 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700427 mView = view;
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700428 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700429 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700430 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800431 if (mWindowAttributes.packageName == null) {
432 mWindowAttributes.packageName = mBasePackageName;
433 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700434 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700435 // Keep track of the actual window flags supplied by the client.
436 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700437
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700438 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700439
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700440 if (view instanceof RootViewSurfaceTaker) {
441 mSurfaceHolderCallback =
442 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
443 if (mSurfaceHolderCallback != null) {
444 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700445 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700446 }
447 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800448
Craig Mautner48d0d182013-06-11 07:53:06 -0700449 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700450 mTranslator = compatibilityInfo.getTranslator();
Craig Mautner48d0d182013-06-11 07:53:06 -0700451 mDisplayAdjustments.setActivityToken(attrs.token);
Romain Guy856d4e12011-10-14 15:47:55 -0700452
Romain Guy1aec9a22011-01-05 09:37:12 -0800453 // If the application owns the surface, don't enable hardware acceleration
454 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700455 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800456 }
457
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700458 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700459 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700460 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700461 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700462 attrs.backup();
463 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700464 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700465 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
466
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700467 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700468 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700469 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700470 }
471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 mSoftInputMode = attrs.softInputMode;
473 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700474 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700476 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700477 mAttachInfo.mApplicationScale =
478 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 if (panelParentView != null) {
480 mAttachInfo.mPanelParentWindowToken
481 = panelParentView.getApplicationWindowToken();
482 }
483 mAdded = true;
484 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 // Schedule the first layout -before- adding to the window
487 // manager, to make sure we do the relayout before receiving
488 // any other events from the system.
489 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700490 if ((mWindowAttributes.inputFeatures
491 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
492 mInputChannel = new InputChannel();
493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700495 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700496 mAttachInfo.mRecomputeGlobalAttributes = true;
497 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700498 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
499 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700500 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 } catch (RemoteException e) {
502 mAdded = false;
503 mView = null;
504 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700505 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700506 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700508 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700510 } finally {
511 if (restore) {
512 attrs.restore();
513 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700515
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700516 if (mTranslator != null) {
517 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700518 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800519 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 mPendingContentInsets.set(mAttachInfo.mContentInsets);
521 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800522 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700523 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 mAttachInfo.mRootView = null;
525 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700526 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700528 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700530 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
531 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
532 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 "Unable to add window -- token " + attrs.token
534 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700535 case WindowManagerGlobal.ADD_NOT_APP_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 for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700539 case WindowManagerGlobal.ADD_APP_EXITING:
540 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 "Unable to add window -- app for token " + attrs.token
542 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700543 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
544 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 "Unable to add window -- window " + mWindow
546 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700547 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 // Silently ignore -- we would have just removed it
549 // right away, anyway.
550 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700551 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
552 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 "Unable to add window " + mWindow +
554 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700555 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
556 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 "Unable to add window " + mWindow +
558 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700559 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
560 throw new WindowManager.InvalidDisplayException(
561 "Unable to add window " + mWindow +
562 " -- the specified display can not be found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 }
564 throw new RuntimeException(
565 "Unable to add window -- unknown error code " + res);
566 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700567
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700568 if (view instanceof RootViewSurfaceTaker) {
569 mInputQueueCallback =
570 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
571 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700572 if (mInputChannel != null) {
573 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700574 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700575 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700576 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700577 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
578 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700579 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700582 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
583 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700584
585 if (mAccessibilityManager.isEnabled()) {
586 mAccessibilityInteractionConnectionManager.ensureConnection();
587 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700588
589 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
590 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
591 }
Michael Wright95ae9422013-03-14 10:58:50 -0700592
Jeff Brownf9e989d2013-04-04 23:04:03 -0700593 // Set up the input pipeline.
594 CharSequence counterSuffix = attrs.getTitle();
Michael Wright88d7f792013-08-27 15:45:42 -0700595 InputStage syntheticInputStage = new SyntheticInputStage();
596 InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700597 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
598 "aq:native-post-ime:" + counterSuffix);
599 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
600 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
601 "aq:ime:" + counterSuffix);
602 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
603 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
604 "aq:native-pre-ime:" + counterSuffix);
605
606 mFirstInputStage = nativePreImeStage;
607 mFirstPostImeInputStage = earlyPostImeStage;
608 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
610 }
611 }
612
keunyoung30f420f2013-08-02 14:23:10 -0700613 /** Whether the window is in local focus mode or not */
614 private boolean isInLocalFocusMode() {
615 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
616 }
617
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800618 void destroyHardwareResources() {
Romain Guy46bfc482013-08-16 18:38:29 -0700619 invalidateDisplayLists();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800620 if (mAttachInfo.mHardwareRenderer != null) {
621 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
622 mAttachInfo.mHardwareRenderer.destroy(false);
623 }
624 }
625
Romain Guy65b345f2011-07-27 18:51:50 -0700626 void destroyHardwareLayers() {
627 if (mThread != Thread.currentThread()) {
628 if (mAttachInfo.mHardwareRenderer != null &&
629 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700630 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700631 }
632 } else {
Romain Guy46bfc482013-08-16 18:38:29 -0700633 invalidateDisplayLists();
Romain Guy65b345f2011-07-27 18:51:50 -0700634 if (mAttachInfo.mHardwareRenderer != null &&
635 mAttachInfo.mHardwareRenderer.isEnabled()) {
636 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
637 }
638 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700639 }
640
Romain Guy11cb6422012-09-21 00:39:43 -0700641 void pushHardwareLayerUpdate(HardwareLayer layer) {
642 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
643 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
644 }
645 }
646
Romain Guy40543602013-06-12 15:31:28 -0700647 void flushHardwareLayerUpdates() {
648 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
649 mAttachInfo.mHardwareRenderer.validate()) {
650 mAttachInfo.mHardwareRenderer.flushLayerUpdates();
651 }
652 }
653
654 void dispatchFlushHardwareLayerUpdates() {
655 mHandler.removeMessages(MSG_FLUSH_LAYER_UPDATES);
656 mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
657 }
658
Chris Craik41ee4652012-05-31 15:05:57 -0700659 public boolean attachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700660 //noinspection SimplifiableIfStatement
Romain Guyba6be8a2012-04-23 18:22:09 -0700661 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Chris Craik41ee4652012-05-31 15:05:57 -0700662 return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700663 }
Chris Craik41ee4652012-05-31 15:05:57 -0700664 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -0700665 }
666
667 public void detachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700668 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700669 mAttachInfo.mHardwareRenderer.detachFunctor(functor);
670 }
671 }
672
Romain Guy3b748a42013-04-17 18:54:38 -0700673 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800674 mAttachInfo.mHardwareAccelerated = false;
675 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800676
Romain Guy856d4e12011-10-14 15:47:55 -0700677 // Don't enable hardware acceleration when the application is in compatibility mode
678 if (mTranslator != null) return;
679
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800680 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700681 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800682 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
683
Romain Guy566c3312011-03-21 18:21:28 -0700684 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700685 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700686 return;
687 }
688
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700689 // Persistent processes (including the system) should not do
690 // accelerated rendering on low-end devices. In that case,
691 // sRendererDisabled will be set. In addition, the system process
692 // itself should never do accelerated rendering. In that case, both
693 // sRendererDisabled and sSystemRendererDisabled are set. When
694 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
695 // can be used by code on the system process to escape that and enable
696 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800697
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700698 final boolean fakeHwAccelerated = (attrs.privateFlags &
699 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
700 final boolean forceHwAccelerated = (attrs.privateFlags &
701 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800702
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700703 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
704 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800705 // Don't enable hardware acceleration when we're not on the main thread
Romain Guy211370f2012-02-01 16:10:55 -0800706 if (!HardwareRenderer.sSystemRendererDisabled &&
707 Looper.getMainLooper() != Looper.myLooper()) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700708 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800709 + "acceleration outside of the main thread, aborting");
710 return;
711 }
712
Romain Guyb051e892010-09-28 19:09:36 -0700713 if (mAttachInfo.mHardwareRenderer != null) {
714 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy211370f2012-02-01 16:10:55 -0800715 }
716
717 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700718 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700719 if (mAttachInfo.mHardwareRenderer != null) {
720 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
721 mAttachInfo.mHardwareAccelerated =
722 mAttachInfo.mHardwareAccelerationRequested = true;
723 }
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700724 } else if (fakeHwAccelerated) {
725 // The window had wanted to use hardware acceleration, but this
726 // is not allowed in its process. By setting this flag, it can
727 // still render as if it was accelerated. This is basically for
728 // the preview windows the window manager shows for launching
729 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700730 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700731 }
732 }
733 }
734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 public View getView() {
736 return mView;
737 }
738
739 final WindowLeaked getLocation() {
740 return mLocation;
741 }
742
743 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
744 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700745 int oldSoftInputMode = mWindowAttributes.softInputMode;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700746 // Keep track of the actual window flags supplied by the client.
747 mClientWindowLayoutFlags = attrs.flags;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700748 // preserve compatible window flag if exists.
Adam Lesinski95c42972013-10-02 10:13:27 -0700749 int compatibleWindowFlag = mWindowAttributes.privateFlags
750 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Craig Mautner3fe38c02012-05-03 17:28:09 -0700751 // transfer over system UI visibility values as they carry current state.
752 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
753 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Romain Guyf21c9b02011-09-06 16:56:54 -0700754 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400755 if ((mWindowAttributesChangesFlag
756 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
757 // Recompute system ui visibility.
758 mAttachInfo.mRecomputeGlobalAttributes = true;
759 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800760 if (mWindowAttributes.packageName == null) {
761 mWindowAttributes.packageName = mBasePackageName;
762 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700763 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700764
765 applyKeepScreenOnFlag(mWindowAttributes);
766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 if (newView) {
768 mSoftInputMode = attrs.softInputMode;
769 requestLayout();
770 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700771 // Don't lose the mode we last auto-computed.
772 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
773 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
774 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
775 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
776 | (oldSoftInputMode
777 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 mWindowAttributesChanged = true;
780 scheduleTraversals();
781 }
782 }
783
784 void handleAppVisibility(boolean visible) {
785 if (mAppVisible != visible) {
786 mAppVisible = visible;
787 scheduleTraversals();
788 }
789 }
790
791 void handleGetNewSurface() {
792 mNewSurfaceNeeded = true;
793 mFullRedrawNeeded = true;
794 scheduleTraversals();
795 }
796
Romain Guybb9908b2012-03-08 11:14:07 -0800797 void handleScreenStateChange(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -0800798 if (on != mAttachInfo.mScreenOn) {
799 mAttachInfo.mScreenOn = on;
Romain Guybb9908b2012-03-08 11:14:07 -0800800 if (mView != null) {
801 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
802 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800803 if (on) {
804 mFullRedrawNeeded = true;
805 scheduleTraversals();
806 }
807 }
808 }
809
Craig Mautner6018aee2012-10-23 14:27:49 -0700810 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700811 public void requestFitSystemWindows() {
812 checkThread();
813 mFitSystemWindowsRequested = true;
814 scheduleTraversals();
815 }
816
Craig Mautner6018aee2012-10-23 14:27:49 -0700817 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800819 if (!mHandlingLayoutInLayoutRequest) {
820 checkThread();
821 mLayoutRequested = true;
822 scheduleTraversals();
823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
825
Craig Mautner6018aee2012-10-23 14:27:49 -0700826 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 public boolean isLayoutRequested() {
828 return mLayoutRequested;
829 }
830
Romain Guycfef1232012-02-23 13:50:37 -0800831 void invalidate() {
832 mDirty.set(0, 0, mWidth, mHeight);
833 scheduleTraversals();
834 }
835
Dianne Hackborna53de062012-05-08 18:53:51 -0700836 void invalidateWorld(View view) {
837 view.invalidate();
838 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700839 ViewGroup parent = (ViewGroup) view;
840 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700841 invalidateWorld(parent.getChildAt(i));
842 }
843 }
844 }
845
Craig Mautner6018aee2012-10-23 14:27:49 -0700846 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800848 invalidateChildInParent(null, dirty);
849 }
850
Craig Mautner8f303ad2013-06-14 11:32:22 -0700851 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800852 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700854 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800855
Chet Haase70d4ba12010-10-06 09:46:45 -0700856 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700857 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800858 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700859 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700860 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700861 }
Romain Guycfef1232012-02-23 13:50:37 -0800862
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700863 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700865 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700866 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800867 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700868 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700869 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700870 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700871 }
Romain Guy1e095972009-07-07 11:22:45 -0700872 if (mAttachInfo.mScalingRequired) {
873 dirty.inset(-1, -1);
874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
Romain Guycfef1232012-02-23 13:50:37 -0800876
877 final Rect localDirty = mDirty;
878 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700879 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800880 mAttachInfo.mIgnoreDirtyState = true;
881 }
Romain Guycfef1232012-02-23 13:50:37 -0800882
883 // Add the new dirty rect to the current one
884 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
885 // Intersect with the bounds of the window to skip
886 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700887 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700888 final boolean intersected = localDirty.intersect(0, 0,
889 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
890 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700891 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
Chet Haase3561d062012-10-23 12:54:51 -0700893 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
894 scheduleTraversals();
895 }
Romain Guycfef1232012-02-23 13:50:37 -0800896
897 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899
Dianne Hackbornce418e62011-03-01 14:31:38 -0800900 void setStopped(boolean stopped) {
901 if (mStopped != stopped) {
902 mStopped = stopped;
903 if (!stopped) {
904 scheduleTraversals();
905 }
906 }
907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908
Craig Mautner8f303ad2013-06-14 11:32:22 -0700909 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800910 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 return null;
912 }
913
Craig Mautner8f303ad2013-06-14 11:32:22 -0700914 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700915 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 if (child != mView) {
917 throw new RuntimeException("child is not mine, honest!");
918 }
919 // Note: don't apply scroll offset, because we want to know its
920 // visibility in the virtual canvas being given to the view hierarchy.
921 return r.intersect(0, 0, mWidth, mHeight);
922 }
923
Igor Murashkina86ab6402013-08-30 12:58:36 -0700924 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 public void bringChildToFront(View child) {
926 }
927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 int getHostVisibility() {
929 return mAppVisible ? mView.getVisibility() : View.GONE;
930 }
Romain Guy8506ab42009-06-11 17:35:47 -0700931
Romain Guy7d70fbf2011-05-24 17:40:25 -0700932 void disposeResizeBuffer() {
Romain Guy27e0bf62013-06-21 14:07:07 -0700933 if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) {
934 mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
935 @Override
936 public void run() {
937 mResizeBuffer.destroy();
938 mResizeBuffer = null;
939 }
940 });
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800941 }
942 }
943
Chet Haasecca2c982011-05-20 14:34:18 -0700944 /**
945 * Add LayoutTransition to the list of transitions to be started in the next traversal.
946 * This list will be cleared after the transitions on the list are start()'ed. These
947 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
948 * happens during the layout phase of traversal, which we want to complete before any of the
949 * animations are started (because those animations may side-effect properties that layout
950 * depends upon, like the bounding rectangles of the affected views). So we add the transition
951 * to the list and it is started just prior to starting the drawing phase of traversal.
952 *
953 * @param transition The LayoutTransition to be started on the next traversal.
954 *
955 * @hide
956 */
957 public void requestTransitionStart(LayoutTransition transition) {
958 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
959 if (mPendingTransitions == null) {
960 mPendingTransitions = new ArrayList<LayoutTransition>();
961 }
962 mPendingTransitions.add(transition);
963 }
964 }
965
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700966 void scheduleTraversals() {
967 if (!mTraversalScheduled) {
968 mTraversalScheduled = true;
969 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
970 mChoreographer.postCallback(
971 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Jeff Brown330314c2012-04-27 02:20:22 -0700972 scheduleConsumeBatchedInput();
Jeff Brown96e942d2011-11-30 19:55:01 -0800973 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700974 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800975
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700976 void unscheduleTraversals() {
977 if (mTraversalScheduled) {
978 mTraversalScheduled = false;
979 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
980 mChoreographer.removeCallbacks(
981 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
982 }
983 }
984
985 void doTraversal() {
986 if (mTraversalScheduled) {
987 mTraversalScheduled = false;
988 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
989
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700990 if (mProfile) {
991 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -0800992 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800993
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700994 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
995 try {
996 performTraversals();
997 } finally {
998 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
999 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001000
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001001 if (mProfile) {
1002 Debug.stopMethodTracing();
1003 mProfile = false;
1004 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001005 }
1006 }
1007
Dianne Hackborn9d090892012-06-11 18:35:41 -07001008 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1009 // Update window's global keep screen on flag: if a view has requested
1010 // that the screen be kept on, then it is always set; otherwise, it is
1011 // set to whatever the client last requested for the global state.
1012 if (mAttachInfo.mKeepScreenOn) {
1013 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1014 } else {
1015 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1016 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1017 }
1018 }
1019
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001020 private boolean collectViewAttributes() {
1021 final View.AttachInfo attachInfo = mAttachInfo;
1022 if (attachInfo.mRecomputeGlobalAttributes) {
1023 //Log.i(TAG, "Computing view hierarchy attributes!");
1024 attachInfo.mRecomputeGlobalAttributes = false;
1025 boolean oldScreenOn = attachInfo.mKeepScreenOn;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001026 attachInfo.mKeepScreenOn = false;
1027 attachInfo.mSystemUiVisibility = 0;
1028 attachInfo.mHasSystemUiListeners = false;
1029 mView.dispatchCollectViewAttributes(attachInfo, 0);
Dianne Hackborn139e5aa2012-05-05 20:36:38 -07001030 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001031 WindowManager.LayoutParams params = mWindowAttributes;
John Spurlockbd957402013-10-03 11:38:39 -04001032 attachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001033 if (attachInfo.mKeepScreenOn != oldScreenOn
Craig Mautner7eac0f52012-09-13 13:14:14 -07001034 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1035 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001036 applyKeepScreenOnFlag(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001037 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1038 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1039 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1040 return true;
1041 }
1042 }
1043 return false;
1044 }
1045
John Spurlockbd957402013-10-03 11:38:39 -04001046 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1047 int vis = 0;
1048 // Translucent decor window flags imply stable system ui visibility.
1049 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1050 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1051 }
1052 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1053 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1054 }
1055 return vis;
1056 }
1057
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001058 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1059 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1060 int childWidthMeasureSpec;
1061 int childHeightMeasureSpec;
1062 boolean windowSizeMayChange = false;
1063
1064 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1065 "Measuring " + host + " in display " + desiredWindowWidth
1066 + "x" + desiredWindowHeight + "...");
1067
1068 boolean goodMeasure = false;
1069 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1070 // On large screens, we don't want to allow dialogs to just
1071 // stretch to fill the entire width of the screen to display
1072 // one line of text. First try doing the layout at a smaller
1073 // size to see if it will fit.
1074 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1075 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1076 int baseSize = 0;
1077 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1078 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1079 }
1080 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1081 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1082 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1083 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001084 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001085 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1086 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1087 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1088 goodMeasure = true;
1089 } else {
1090 // Didn't fit in that size... try expanding a bit.
1091 baseSize = (baseSize+desiredWindowWidth)/2;
1092 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1093 + baseSize);
1094 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001095 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001096 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1097 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1098 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1099 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1100 goodMeasure = true;
1101 }
1102 }
1103 }
1104 }
1105
1106 if (!goodMeasure) {
1107 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1108 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001109 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001110 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1111 windowSizeMayChange = true;
1112 }
1113 }
1114
1115 if (DBG) {
1116 System.out.println("======================================");
1117 System.out.println("performTraversals -- after measure");
1118 host.debug();
1119 }
1120
1121 return windowSizeMayChange;
1122 }
1123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 private void performTraversals() {
1125 // cache mView since it is used so much below...
1126 final View host = mView;
1127
1128 if (DBG) {
1129 System.out.println("======================================");
1130 System.out.println("performTraversals");
1131 host.debug();
1132 }
1133
1134 if (host == null || !mAdded)
1135 return;
1136
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001137 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001139 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001141 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 WindowManager.LayoutParams lp = mWindowAttributes;
1143
1144 int desiredWindowWidth;
1145 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146
1147 final View.AttachInfo attachInfo = mAttachInfo;
1148
1149 final int viewVisibility = getHostVisibility();
1150 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1151 || mNewSurfaceNeeded;
1152
1153 WindowManager.LayoutParams params = null;
1154 if (mWindowAttributesChanged) {
1155 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001156 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 params = lp;
1158 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001159 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001160 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1161 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001162 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001163 mLayoutRequested = true;
1164 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001165 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001166 mLastInCompatMode = false;
1167 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001168 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001169 mLastInCompatMode = true;
1170 }
1171 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001172
Romain Guyf21c9b02011-09-06 16:56:54 -07001173 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001174
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001175 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001177 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 mLayoutRequested = true;
1179
John Spurlockf8508272013-10-14 21:06:52 -04001180 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1181 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001182 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001183 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001184 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001185 desiredWindowWidth = size.x;
1186 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001187 } else {
1188 DisplayMetrics packageMetrics =
1189 mView.getContext().getResources().getDisplayMetrics();
1190 desiredWindowWidth = packageMetrics.widthPixels;
1191 desiredWindowHeight = packageMetrics.heightPixels;
1192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193
1194 // For the very first time, tell the view hierarchy that it
1195 // is attached to the window. Note that at this point the surface
1196 // object is not initialized to its backing store, but soon it
1197 // will be (assuming the window is visible).
1198 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -08001199 // We used to use the following condition to choose 32 bits drawing caches:
1200 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1201 // However, windows are now always 32 bits by default, so choose 32 bits
1202 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 attachInfo.mHasWindowFocus = false;
1204 attachInfo.mWindowVisibility = viewVisibility;
1205 attachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001207 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001208 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001209 // Set the layout direction if it has not been set before (inherit is the default)
1210 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1211 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 host.dispatchAttachedToWindow(attachInfo, 0);
Dianne Hackborn961cae92013-03-20 14:59:43 -07001214 attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001215 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1216 host.fitSystemWindows(mFitSystemWindowsInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001220 desiredWindowWidth = frame.width();
1221 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001223 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001224 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001225 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001227 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 }
1229 }
1230
1231 if (viewVisibilityChanged) {
1232 attachInfo.mWindowVisibility = viewVisibility;
1233 host.dispatchWindowVisibilityChanged(viewVisibility);
1234 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001235 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 }
1237 if (viewVisibility == View.GONE) {
1238 // After making a window gone, we will count it as being
1239 // shown for the first time the next time it gets focus.
1240 mHasHadWindowFocus = false;
1241 }
1242 }
1243
Chet Haaseb78c2842012-04-19 13:39:50 -07001244 // Execute enqueued actions on every traversal in case a detached view enqueued an action
1245 getRunQueue().executeActions(attachInfo.mHandler);
1246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001248
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001249 boolean layoutRequested = mLayoutRequested && !mStopped;
1250 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001251
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001252 final Resources res = mView.getContext().getResources();
1253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 // make sure touch mode code executes by setting cached value
1256 // to opposite of the added touch mode.
1257 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001258 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001260 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1261 insetsChanged = true;
1262 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001263 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001266 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1268 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1269 + mAttachInfo.mVisibleInsets);
1270 }
1271 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1272 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001273 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274
John Spurlockf8508272013-10-14 21:06:52 -04001275 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1276 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001277 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001278 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001279 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001280 desiredWindowWidth = size.x;
1281 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001282 } else {
1283 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1284 desiredWindowWidth = packageMetrics.widthPixels;
1285 desiredWindowHeight = packageMetrics.heightPixels;
1286 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 }
1288 }
1289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001291 windowSizeMayChange |= measureHierarchy(host, lp, res,
1292 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 }
1294
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001295 if (collectViewAttributes()) {
1296 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001298 if (attachInfo.mForceReportNewAttributes) {
1299 attachInfo.mForceReportNewAttributes = false;
1300 params = lp;
1301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302
1303 if (mFirst || attachInfo.mViewVisibilityChanged) {
1304 attachInfo.mViewVisibilityChanged = false;
1305 int resizeMode = mSoftInputMode &
1306 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1307 // If we are in auto resize mode, then we need to determine
1308 // what mode to use now.
1309 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1310 final int N = attachInfo.mScrollContainers.size();
1311 for (int i=0; i<N; i++) {
1312 if (attachInfo.mScrollContainers.get(i).isShown()) {
1313 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1314 }
1315 }
1316 if (resizeMode == 0) {
1317 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1318 }
1319 if ((lp.softInputMode &
1320 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1321 lp.softInputMode = (lp.softInputMode &
1322 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1323 resizeMode;
1324 params = lp;
1325 }
1326 }
1327 }
Romain Guy8506ab42009-06-11 17:35:47 -07001328
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001329 if (params != null) {
1330 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1331 if (!PixelFormat.formatHasAlpha(params.format)) {
1332 params.format = PixelFormat.TRANSLUCENT;
1333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001335 mAttachInfo.mOverscanRequested = (params.flags
1336 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 }
1338
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001339 if (mFitSystemWindowsRequested) {
1340 mFitSystemWindowsRequested = false;
1341 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001342 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001343 host.fitSystemWindows(mFitSystemWindowsInsets);
1344 if (mLayoutRequested) {
1345 // Short-circuit catching a new layout request here, so
1346 // we don't need to go through two layout passes when things
1347 // change due to fitting system windows, which can happen a lot.
1348 windowSizeMayChange |= measureHierarchy(host, lp,
1349 mView.getContext().getResources(),
1350 desiredWindowWidth, desiredWindowHeight);
1351 }
1352 }
1353
1354 if (layoutRequested) {
1355 // Clear this now, so that if anything requests a layout in the
1356 // rest of this function we will catch it and re-run a full
1357 // layout pass.
1358 mLayoutRequested = false;
1359 }
1360
1361 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001362 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001363 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1364 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1365 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1366 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367
Jeff Brown2e05ec32013-09-30 15:57:43 -07001368 // Determine whether to compute insets.
1369 // If there are no inset listeners remaining then we may still need to compute
1370 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 final boolean computesInternalInsets =
Jeff Brown2e05ec32013-09-30 15:57:43 -07001372 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1373 || attachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 boolean insetsPending = false;
1376 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001377
1378 if (mFirst || windowShouldResize || insetsChanged ||
1379 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380
1381 if (viewVisibility == View.VISIBLE) {
1382 // If this window is giving internal insets to the window
1383 // manager, and it is being added or changing its visibility,
1384 // then we want to first give the window manager "fake"
1385 // insets to cause it to effectively ignore the content of
1386 // the window during layout. This avoids it briefly causing
1387 // other windows to resize/move based on the raw frame of the
1388 // window, waiting until we can finish laying out this window
1389 // and get back to the window manager with the ultimately
1390 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001391 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 }
1393
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001394 if (mSurfaceHolder != null) {
1395 mSurfaceHolder.mSurfaceLock.lock();
1396 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001397 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001398
Romain Guyc361da82010-10-25 15:29:10 -07001399 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001401 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001404 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001405 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1406 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001407 }
Romain Guy2a83f002011-01-18 18:28:21 -08001408
1409 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001410 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
Dianne Hackborn021d2432013-10-13 15:20:09 -07001411 if (!mDrawDuringWindowsAnimating &&
1412 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
1413 mWindowsAnimating = true;
Michael Jurkaf42d90102013-05-08 18:00:04 +02001414 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001417 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 + " content=" + mPendingContentInsets.toShortString()
1419 + " visible=" + mPendingVisibleInsets.toShortString()
1420 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001421
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001422 if (mPendingConfiguration.seq != 0) {
1423 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1424 + mPendingConfiguration);
1425 updateConfiguration(mPendingConfiguration, !mFirst);
1426 mPendingConfiguration.seq = 0;
1427 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001428
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001429 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1430 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 contentInsetsChanged = !mPendingContentInsets.equals(
1432 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001433 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 mAttachInfo.mVisibleInsets);
1435 if (contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001436 if (mWidth > 0 && mHeight > 0 && lp != null &&
1437 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1438 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001439 mSurface != null && mSurface.isValid() &&
1440 !mAttachInfo.mTurnOffWindowResizeAnim &&
1441 mAttachInfo.mHardwareRenderer != null &&
1442 mAttachInfo.mHardwareRenderer.isEnabled() &&
1443 mAttachInfo.mHardwareRenderer.validate() &&
1444 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1445
1446 disposeResizeBuffer();
1447
1448 boolean completed = false;
Romain Guyc89b14b2012-08-08 14:53:48 -07001449 HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
Chet Haase08837c22011-11-28 11:53:21 -08001450 HardwareCanvas layerCanvas = null;
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001451 try {
1452 if (mResizeBuffer == null) {
1453 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1454 mWidth, mHeight, false);
1455 } else if (mResizeBuffer.getWidth() != mWidth ||
1456 mResizeBuffer.getHeight() != mHeight) {
1457 mResizeBuffer.resize(mWidth, mHeight);
1458 }
Chet Haase603f6de2012-09-14 15:31:25 -07001459 // TODO: should handle create/resize failure
Romain Guyc89b14b2012-08-08 14:53:48 -07001460 layerCanvas = mResizeBuffer.start(hwRendererCanvas);
Chet Haase08837c22011-11-28 11:53:21 -08001461 final int restoreCount = layerCanvas.save();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001462
1463 int yoff;
1464 final boolean scrolling = mScroller != null
1465 && mScroller.computeScrollOffset();
1466 if (scrolling) {
1467 yoff = mScroller.getCurrY();
1468 mScroller.abortAnimation();
1469 } else {
1470 yoff = mScrollY;
1471 }
1472
Chet Haase08837c22011-11-28 11:53:21 -08001473 layerCanvas.translate(0, -yoff);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001474 if (mTranslator != null) {
Chet Haase08837c22011-11-28 11:53:21 -08001475 mTranslator.translateCanvas(layerCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001476 }
1477
Romain Guy3a2d6aa2012-10-23 13:25:13 -07001478 DisplayList displayList = mView.mDisplayList;
Romain Guyf6664562013-09-04 14:14:07 -07001479 if (displayList != null && displayList.isValid()) {
Romain Guy3a2d6aa2012-10-23 13:25:13 -07001480 layerCanvas.drawDisplayList(displayList, null,
1481 DisplayList.FLAG_CLIP_CHILDREN);
1482 } else {
1483 mView.draw(layerCanvas);
1484 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001485
Svetoslav Ganov42138042012-03-20 11:51:39 -07001486 drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1487
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001488 mResizeBufferStartTime = SystemClock.uptimeMillis();
1489 mResizeBufferDuration = mView.getResources().getInteger(
1490 com.android.internal.R.integer.config_mediumAnimTime);
1491 completed = true;
1492
Chet Haase08837c22011-11-28 11:53:21 -08001493 layerCanvas.restoreToCount(restoreCount);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001494 } catch (OutOfMemoryError e) {
1495 Log.w(TAG, "Not enough memory for content change anim buffer", e);
1496 } finally {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001497 if (mResizeBuffer != null) {
Romain Guyc89b14b2012-08-08 14:53:48 -07001498 mResizeBuffer.end(hwRendererCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001499 if (!completed) {
Romain Guy27e0bf62013-06-21 14:07:07 -07001500 disposeResizeBuffer();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001501 }
1502 }
1503 }
1504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1507 + mAttachInfo.mContentInsets);
1508 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001509 if (overscanInsetsChanged) {
1510 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1511 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1512 + mAttachInfo.mOverscanInsets);
1513 // Need to relayout with content insets.
1514 contentInsetsChanged = true;
1515 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001516 if (contentInsetsChanged || mLastSystemUiVisibility !=
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001517 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
1518 || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001519 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001520 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001521 mFitSystemWindowsRequested = false;
1522 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1523 host.fitSystemWindows(mFitSystemWindowsInsets);
1524 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 if (visibleInsetsChanged) {
1526 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1527 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1528 + mAttachInfo.mVisibleInsets);
1529 }
1530
1531 if (!hadSurface) {
1532 if (mSurface.isValid()) {
1533 // If we are creating a new surface, then we need to
1534 // completely redraw it. Also, when we get to the
1535 // point of drawing it we will hold off and schedule
1536 // a new traversal instead. This is so we can tell the
1537 // window manager about all of the windows being displayed
1538 // before actually drawing them, so it can display then
1539 // all at once.
1540 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001541 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001542 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001543
Romain Guyb051e892010-09-28 19:09:36 -07001544 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001545 try {
Romain Guy786fc932012-07-24 16:24:56 -07001546 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
1547 mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07001548 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001549 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001550 return;
1551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 }
1553 }
1554 } else if (!mSurface.isValid()) {
1555 // If the surface has been removed, then reset the scroll
1556 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001557 if (mLastScrolledFocus != null) {
1558 mLastScrolledFocus.clear();
1559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 mScrollY = mCurScrollY = 0;
1561 if (mScroller != null) {
1562 mScroller.abortAnimation();
1563 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001564 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001565 // Our surface is gone
1566 if (mAttachInfo.mHardwareRenderer != null &&
1567 mAttachInfo.mHardwareRenderer.isEnabled()) {
1568 mAttachInfo.mHardwareRenderer.destroy(true);
1569 }
Romain Guy2a83f002011-01-18 18:28:21 -08001570 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1571 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001572 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001573 try {
Romain Guy786fc932012-07-24 16:24:56 -07001574 mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07001575 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001576 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001577 return;
1578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580 } catch (RemoteException e) {
1581 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001584 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585
1586 attachInfo.mWindowLeft = frame.left;
1587 attachInfo.mWindowTop = frame.top;
1588
1589 // !!FIXME!! This next section handles the case where we did not get the
1590 // window size we asked for. We should avoid this by getting a maximum size from
1591 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001592 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001593 mWidth = frame.width();
1594 mHeight = frame.height();
1595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001597 if (mSurfaceHolder != null) {
1598 // The app owns the surface; tell it about what is going on.
1599 if (mSurface.isValid()) {
1600 // XXX .copyFrom() doesn't work!
1601 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1602 mSurfaceHolder.mSurface = mSurface;
1603 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001604 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001605 mSurfaceHolder.mSurfaceLock.unlock();
1606 if (mSurface.isValid()) {
1607 if (!hadSurface) {
1608 mSurfaceHolder.ungetCallbacks();
1609
1610 mIsCreating = true;
1611 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1612 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1613 if (callbacks != null) {
1614 for (SurfaceHolder.Callback c : callbacks) {
1615 c.surfaceCreated(mSurfaceHolder);
1616 }
1617 }
1618 surfaceChanged = true;
1619 }
1620 if (surfaceChanged) {
1621 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1622 lp.format, mWidth, mHeight);
1623 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1624 if (callbacks != null) {
1625 for (SurfaceHolder.Callback c : callbacks) {
1626 c.surfaceChanged(mSurfaceHolder, lp.format,
1627 mWidth, mHeight);
1628 }
1629 }
1630 }
1631 mIsCreating = false;
1632 } else if (hadSurface) {
1633 mSurfaceHolder.ungetCallbacks();
1634 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1635 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1636 if (callbacks != null) {
1637 for (SurfaceHolder.Callback c : callbacks) {
1638 c.surfaceDestroyed(mSurfaceHolder);
1639 }
1640 }
1641 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001642 try {
1643 mSurfaceHolder.mSurface = new Surface();
1644 } finally {
1645 mSurfaceHolder.mSurfaceLock.unlock();
1646 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001647 }
1648 }
Romain Guy53389bd2010-09-07 17:16:32 -07001649
Chet Haase40e03832011-10-06 08:34:13 -07001650 if (mAttachInfo.mHardwareRenderer != null &&
1651 mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guy370ab062013-05-21 12:15:07 -07001652 if (hwInitialized ||
Chet Haase40e03832011-10-06 08:34:13 -07001653 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1654 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1655 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1656 if (!hwInitialized) {
Romain Guy786fc932012-07-24 16:24:56 -07001657 mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
Chet Haase391fef02012-09-27 15:26:36 -07001658 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001659 }
Romain Guy03985752011-07-11 15:33:51 -07001660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 }
1662
Dianne Hackbornce418e62011-03-01 14:31:38 -08001663 if (!mStopped) {
1664 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001665 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001666 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1667 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001668 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1669 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001670
Dianne Hackbornce418e62011-03-01 14:31:38 -08001671 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1672 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1673 + " mHeight=" + mHeight
1674 + " measuredHeight=" + host.getMeasuredHeight()
1675 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001676
Dianne Hackbornce418e62011-03-01 14:31:38 -08001677 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001678 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001679
Dianne Hackbornce418e62011-03-01 14:31:38 -08001680 // Implementation of weights from WindowManager.LayoutParams
1681 // We just grow the dimensions as needed and re-measure if
1682 // needs be
1683 int width = host.getMeasuredWidth();
1684 int height = host.getMeasuredHeight();
1685 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001686
Dianne Hackbornce418e62011-03-01 14:31:38 -08001687 if (lp.horizontalWeight > 0.0f) {
1688 width += (int) ((mWidth - width) * lp.horizontalWeight);
1689 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1690 MeasureSpec.EXACTLY);
1691 measureAgain = true;
1692 }
1693 if (lp.verticalWeight > 0.0f) {
1694 height += (int) ((mHeight - height) * lp.verticalWeight);
1695 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1696 MeasureSpec.EXACTLY);
1697 measureAgain = true;
1698 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001699
Dianne Hackbornce418e62011-03-01 14:31:38 -08001700 if (measureAgain) {
1701 if (DEBUG_LAYOUT) Log.v(TAG,
1702 "And hey let's measure once more: width=" + width
1703 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001704 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001705 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001706
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001707 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001710 } else {
1711 // Not the first pass and no window/insets/visibility change but the window
1712 // may have moved and we need check that and if so to update the left and right
1713 // in the attach info. We translate only the window frame since on window move
1714 // the window manager tells us only for the new frame but the insets are the
1715 // same and we do not want to translate them more than once.
1716
1717 // TODO: Well, we are checking whether the frame has changed similarly
1718 // to how this is done for the insets. This is however incorrect since
1719 // the insets and the frame are translated. For example, the old frame
1720 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1721 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1722 // true since we are comparing a not translated value to a translated one.
1723 // This scenario is rare but we may want to fix that.
1724
1725 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1726 || attachInfo.mWindowTop != frame.top);
1727 if (windowMoved) {
1728 if (mTranslator != null) {
1729 mTranslator.translateRectInScreenToAppWinFrame(frame);
1730 }
1731 attachInfo.mWindowLeft = frame.left;
1732 attachInfo.mWindowTop = frame.top;
1733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001736 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 boolean triggerGlobalLayoutListener = didLayout
1738 || attachInfo.mRecomputeGlobalAttributes;
1739 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001740 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001742 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 // We can compute the transparent area
1744
Dianne Hackborn4702a852012-08-17 15:18:29 -07001745 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 // start out transparent
1747 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1748 host.getLocationInWindow(mTmpLocation);
1749 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1750 mTmpLocation[0] + host.mRight - host.mLeft,
1751 mTmpLocation[1] + host.mBottom - host.mTop);
1752
1753 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001754 if (mTranslator != null) {
1755 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1756 }
1757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1759 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001760 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 // reconfigure window manager
1762 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001763 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 } catch (RemoteException e) {
1765 }
1766 }
1767 }
1768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 if (DBG) {
1770 System.out.println("======================================");
1771 System.out.println("performTraversals -- after setFrame");
1772 host.debug();
1773 }
1774 }
1775
1776 if (triggerGlobalLayoutListener) {
1777 attachInfo.mRecomputeGlobalAttributes = false;
1778 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1779 }
1780
1781 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001782 // Clear the original insets.
1783 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1784 insets.reset();
1785
1786 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brown2e05ec32013-09-30 15:57:43 -07001788 attachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08001789
1790 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1792 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001793
1794 // Translate insets to screen coordinates if needed.
1795 final Rect contentInsets;
1796 final Rect visibleInsets;
1797 final Region touchableRegion;
1798 if (mTranslator != null) {
1799 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1800 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1801 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1802 } else {
1803 contentInsets = insets.contentInsets;
1804 visibleInsets = insets.visibleInsets;
1805 touchableRegion = insets.touchableRegion;
1806 }
1807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001809 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001810 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 } catch (RemoteException e) {
1812 }
1813 }
1814 }
Romain Guy8506ab42009-06-11 17:35:47 -07001815
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001816 boolean skipDraw = false;
1817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 if (mFirst) {
1819 // handle first focus request
1820 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1821 + mView.hasFocus());
1822 if (mView != null) {
1823 if (!mView.hasFocus()) {
1824 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001826 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001829 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831 }
Jeff Brown98365d72012-08-19 20:30:52 -07001832 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001833 // The first time we relayout the window, if the system is
1834 // doing window animations, we want to hold of on any future
1835 // draws until the animation is done.
1836 mWindowsAnimating = true;
1837 }
1838 } else if (mWindowsAnimating) {
1839 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 }
1841
1842 mFirst = false;
1843 mWillDrawSoon = false;
1844 mNewSurfaceNeeded = false;
1845 mViewVisibility = viewVisibility;
1846
keunyoung30f420f2013-08-02 14:23:10 -07001847 if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 final boolean imTarget = WindowManager.LayoutParams
1849 .mayUseInputMethod(mWindowAttributes.flags);
1850 if (imTarget != mLastWasImTarget) {
1851 mLastWasImTarget = imTarget;
1852 InputMethodManager imm = InputMethodManager.peekInstance();
1853 if (imm != null && imTarget) {
1854 imm.startGettingWindowFocus(mView);
1855 imm.onWindowFocus(mView, mView.findFocus(),
1856 mWindowAttributes.softInputMode,
1857 !mHasHadWindowFocus, mWindowAttributes.flags);
1858 }
1859 }
1860 }
Romain Guy8506ab42009-06-11 17:35:47 -07001861
Jeff Brown96e942d2011-11-30 19:55:01 -08001862 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001863 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001864 mReportNextDraw = true;
1865 }
1866
Romain Guyea835032011-07-28 19:24:37 -07001867 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1868 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869
Chet Haase61158c62011-09-06 22:19:45 -07001870 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001871 if (!skipDraw || mReportNextDraw) {
1872 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1873 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1874 mPendingTransitions.get(i).startChangingAnimations();
1875 }
1876 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001877 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001878
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001879 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001882 if (viewVisibility == View.VISIBLE) {
1883 // Try again
1884 scheduleTraversals();
1885 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001886 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1887 mPendingTransitions.get(i).endChangingAnimations();
1888 }
1889 mPendingTransitions.clear();
1890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001892
1893 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 }
1895
Romain Guy3696779b2013-01-28 14:04:07 -08001896 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
1897 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1898 try {
1899 if (!mWindowSession.outOfMemory(mWindow) &&
1900 Process.myUid() != Process.SYSTEM_UID) {
1901 Slog.w(TAG, "No processes killed for memory; killing self");
1902 Process.killProcess(Process.myPid());
1903 }
1904 } catch (RemoteException ex) {
1905 }
1906 mLayoutRequested = true; // ask wm for a new surface next time.
1907 }
1908
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001909 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1910 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1911 try {
1912 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1913 } finally {
1914 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1915 }
1916 }
1917
Chet Haase97140572012-09-13 14:56:47 -07001918 /**
1919 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
1920 * is currently undergoing a layout pass.
1921 *
1922 * @return whether the view hierarchy is currently undergoing a layout pass
1923 */
1924 boolean isInLayout() {
1925 return mInLayout;
1926 }
1927
1928 /**
Chet Haasecc699b42012-12-13 09:06:55 -08001929 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
1930 * undergoing a layout pass. requestLayout() should not generally be called during layout,
1931 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
1932 * all children in that container hierarchy are measured and laid out at the end of the layout
1933 * pass for that container). If requestLayout() is called anyway, we handle it correctly
1934 * by registering all requesters during a frame as it proceeds. At the end of the frame,
1935 * we check all of those views to see if any still have pending layout requests, which
1936 * indicates that they were not correctly handled by their container hierarchy. If that is
1937 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
1938 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07001939 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08001940 * requests to the next frame to avoid possible infinite loops.
1941 *
1942 * <p>The return value from this method indicates whether the request should proceed
1943 * (if it is a request during the first layout pass) or should be skipped and posted to the
1944 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07001945 *
1946 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08001947 *
1948 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07001949 */
Chet Haasecc699b42012-12-13 09:06:55 -08001950 boolean requestLayoutDuringLayout(final View view) {
1951 if (view.mParent == null || view.mAttachInfo == null) {
1952 // Would not normally trigger another layout, so just let it pass through as usual
1953 return true;
1954 }
Chet Haase107a4822013-03-13 06:46:50 -07001955 if (!mLayoutRequesters.contains(view)) {
1956 mLayoutRequesters.add(view);
1957 }
Chet Haase97140572012-09-13 14:56:47 -07001958 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07001959 // Let the request proceed normally; it will be processed in a second layout pass
1960 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08001961 return true;
Chet Haase97140572012-09-13 14:56:47 -07001962 } else {
Chet Haase107a4822013-03-13 06:46:50 -07001963 // Don't let the request proceed during the second layout pass.
1964 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08001965 return false;
Chet Haase97140572012-09-13 14:56:47 -07001966 }
1967 }
1968
Chet Haase3efa7b52012-12-03 08:33:17 -08001969 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
1970 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001971 mLayoutRequested = false;
1972 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07001973 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001974
1975 final View host = mView;
1976 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1977 Log.v(TAG, "Laying out " + host + " to (" +
1978 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
1979 }
1980
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001981 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
1982 try {
1983 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08001984
Chet Haased5a83522012-11-21 16:24:44 -08001985 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07001986 int numViewsRequestingLayout = mLayoutRequesters.size();
1987 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08001988 // requestLayout() was called during layout.
1989 // If no layout-request flags are set on the requesting views, there is no problem.
1990 // If some requests are still pending, then we need to clear those flags and do
1991 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07001992 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
1993 false);
1994 if (validLayoutRequesters != null) {
1995 // Set this flag to indicate that any further requests are happening during
1996 // the second pass, which may result in posting those requests to the next
1997 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08001998 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07001999
2000 // Process fresh layout requests, then measure and layout
2001 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002002 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002003 final View view = validLayoutRequesters.get(i);
2004 Log.w("View", "requestLayout() improperly called by " + view +
2005 " during layout: running second layout pass");
2006 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002007 }
2008 measureHierarchy(host, lp, mView.getContext().getResources(),
2009 desiredWindowWidth, desiredWindowHeight);
2010 mInLayout = true;
2011 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002012
Chet Haasecc699b42012-12-13 09:06:55 -08002013 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002014
2015 // Check the valid requests again, this time without checking/clearing the
2016 // layout flags, since requests happening during the second pass get noop'd
2017 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2018 if (validLayoutRequesters != null) {
2019 final ArrayList<View> finalRequesters = validLayoutRequesters;
2020 // Post second-pass requests to the next frame
2021 getRunQueue().post(new Runnable() {
2022 @Override
2023 public void run() {
2024 int numValidRequests = finalRequesters.size();
2025 for (int i = 0; i < numValidRequests; ++i) {
2026 final View view = finalRequesters.get(i);
2027 Log.w("View", "requestLayout() improperly called by " + view +
2028 " during second layout pass: posting in next frame");
2029 view.requestLayout();
2030 }
2031 }
2032 });
2033 }
Chet Haasecc699b42012-12-13 09:06:55 -08002034 }
Chet Haase107a4822013-03-13 06:46:50 -07002035
Chet Haase97140572012-09-13 14:56:47 -07002036 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002037 } finally {
2038 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2039 }
Chet Haase97140572012-09-13 14:56:47 -07002040 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002041 }
2042
Chet Haase107a4822013-03-13 06:46:50 -07002043 /**
2044 * This method is called during layout when there have been calls to requestLayout() during
2045 * layout. It walks through the list of views that requested layout to determine which ones
2046 * still need it, based on visibility in the hierarchy and whether they have already been
2047 * handled (as is usually the case with ListView children).
2048 *
2049 * @param layoutRequesters The list of views that requested layout during layout
2050 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2051 * If so, the FORCE_LAYOUT flag was not set on requesters.
2052 * @return A list of the actual views that still need to be laid out.
2053 */
2054 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2055 boolean secondLayoutRequests) {
2056
2057 int numViewsRequestingLayout = layoutRequesters.size();
2058 ArrayList<View> validLayoutRequesters = null;
2059 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2060 View view = layoutRequesters.get(i);
2061 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2062 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2063 View.PFLAG_FORCE_LAYOUT)) {
2064 boolean gone = false;
2065 View parent = view;
2066 // Only trigger new requests for views in a non-GONE hierarchy
2067 while (parent != null) {
2068 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2069 gone = true;
2070 break;
2071 }
2072 if (parent.mParent instanceof View) {
2073 parent = (View) parent.mParent;
2074 } else {
2075 parent = null;
2076 }
2077 }
2078 if (!gone) {
2079 if (validLayoutRequesters == null) {
2080 validLayoutRequesters = new ArrayList<View>();
2081 }
2082 validLayoutRequesters.add(view);
2083 }
2084 }
2085 }
2086 if (!secondLayoutRequests) {
2087 // If we're checking the layout flags, then we need to clean them up also
2088 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2089 View view = layoutRequesters.get(i);
2090 while (view != null &&
2091 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2092 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2093 if (view.mParent instanceof View) {
2094 view = (View) view.mParent;
2095 } else {
2096 view = null;
2097 }
2098 }
2099 }
2100 }
2101 layoutRequesters.clear();
2102 return validLayoutRequesters;
2103 }
2104
Igor Murashkina86ab6402013-08-30 12:58:36 -07002105 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 public void requestTransparentRegion(View child) {
2107 // the test below should not fail unless someone is messing with us
2108 checkThread();
2109 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002110 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 // Need to make sure we re-evaluate the window attributes next
2112 // time around, to ensure the window has the correct format.
2113 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002114 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002115 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 }
2117 }
2118
2119 /**
2120 * Figures out the measure spec for the root view in a window based on it's
2121 * layout params.
2122 *
2123 * @param windowSize
2124 * The available width or height of the window
2125 *
2126 * @param rootDimension
2127 * The layout params for one dimension (width or height) of the
2128 * window.
2129 *
2130 * @return The measure spec to use to measure the root view.
2131 */
Romain Guya998dff2012-03-23 18:58:36 -07002132 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 int measureSpec;
2134 switch (rootDimension) {
2135
Romain Guy980a9382010-01-08 15:06:28 -08002136 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 // Window can't resize. Force root view to be windowSize.
2138 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2139 break;
2140 case ViewGroup.LayoutParams.WRAP_CONTENT:
2141 // Window can resize. Set max size for root view.
2142 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2143 break;
2144 default:
2145 // Window wants to be an exact size. Force root view to be that size.
2146 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2147 break;
2148 }
2149 return measureSpec;
2150 }
2151
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002152 int mHardwareYOffset;
2153 int mResizeAlpha;
2154 final Paint mResizePaint = new Paint();
2155
Igor Murashkina86ab6402013-08-30 12:58:36 -07002156 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002157 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002158 canvas.translate(0, -mHardwareYOffset);
2159 }
2160
Igor Murashkina86ab6402013-08-30 12:58:36 -07002161 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002162 public void onHardwarePostDraw(HardwareCanvas canvas) {
2163 if (mResizeBuffer != null) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002164 mResizePaint.setAlpha(mResizeAlpha);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002165 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002166 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002167 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002168 }
2169
Chet Haaseed30fd82011-04-22 16:18:45 -07002170 /**
2171 * @hide
2172 */
2173 void outputDisplayList(View view) {
2174 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
Chet Haaseed30fd82011-04-22 16:18:45 -07002175 DisplayList displayList = view.getDisplayList();
2176 if (displayList != null) {
Romain Guy59a12ca2011-06-09 17:48:21 -07002177 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
2178 }
2179 }
2180 }
2181
2182 /**
2183 * @see #PROPERTY_PROFILE_RENDERING
2184 */
2185 private void profileRendering(boolean enabled) {
2186 if (mProfileRendering) {
2187 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002188
2189 if (mRenderProfiler != null) {
2190 mChoreographer.removeFrameCallback(mRenderProfiler);
2191 }
2192 if (mRenderProfilingEnabled) {
2193 if (mRenderProfiler == null) {
2194 mRenderProfiler = new Choreographer.FrameCallback() {
2195 @Override
2196 public void doFrame(long frameTimeNanos) {
2197 mDirty.set(0, 0, mWidth, mHeight);
2198 scheduleTraversals();
2199 if (mRenderProfilingEnabled) {
2200 mChoreographer.postFrameCallback(mRenderProfiler);
2201 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002202 }
Chris Craikae4f32042013-02-07 12:57:10 -08002203 };
2204 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002205 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002206 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002207 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002208 }
2209 }
2210 }
2211
Chet Haase2f2022a2011-10-11 06:41:59 -07002212 /**
2213 * Called from draw() when DEBUG_FPS is enabled
2214 */
2215 private void trackFPS() {
2216 // Tracks frames per second drawn. First value in a series of draws may be bogus
2217 // because it down not account for the intervening idle time
2218 long nowTime = System.currentTimeMillis();
2219 if (mFpsStartTime < 0) {
2220 mFpsStartTime = mFpsPrevTime = nowTime;
2221 mFpsNumFrames = 0;
2222 } else {
2223 ++mFpsNumFrames;
2224 String thisHash = Integer.toHexString(System.identityHashCode(this));
2225 long frameTime = nowTime - mFpsPrevTime;
2226 long totalTime = nowTime - mFpsStartTime;
2227 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2228 mFpsPrevTime = nowTime;
2229 if (totalTime > 1000) {
2230 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2231 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2232 mFpsStartTime = nowTime;
2233 mFpsNumFrames = 0;
2234 }
2235 }
2236 }
2237
Jeff Brown96e942d2011-11-30 19:55:01 -08002238 private void performDraw() {
Craig Mautner006f0e42012-03-21 11:00:32 -07002239 if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2240 return;
2241 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002242
Jeff Brown96e942d2011-11-30 19:55:01 -08002243 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2244 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002245
Romain Guy1f59e5c2012-05-06 14:11:16 -07002246 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002247 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2248 try {
2249 draw(fullRedrawNeeded);
2250 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002251 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002252 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2253 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002254
Jeff Brown96e942d2011-11-30 19:55:01 -08002255 if (mReportNextDraw) {
2256 mReportNextDraw = false;
2257
2258 if (LOCAL_LOGV) {
2259 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2260 }
2261 if (mSurfaceHolder != null && mSurface.isValid()) {
2262 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2263 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2264 if (callbacks != null) {
2265 for (SurfaceHolder.Callback c : callbacks) {
2266 if (c instanceof SurfaceHolder.Callback2) {
2267 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2268 mSurfaceHolder);
2269 }
2270 }
2271 }
2272 }
2273 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002274 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002275 } catch (RemoteException e) {
2276 }
2277 }
2278 }
2279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 private void draw(boolean fullRedrawNeeded) {
2281 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002282 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 return;
2284 }
2285
Chet Haase2f2022a2011-10-11 06:41:59 -07002286 if (DEBUG_FPS) {
2287 trackFPS();
2288 }
2289
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002290 if (!sFirstDrawComplete) {
2291 synchronized (sFirstDrawHandlers) {
2292 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002293 final int count = sFirstDrawHandlers.size();
2294 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002295 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002296 }
2297 }
2298 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 scrollToRectOrFocus(null, false);
2301
Romain Guy25eba5c2012-04-04 17:29:03 -07002302 final AttachInfo attachInfo = mAttachInfo;
2303 if (attachInfo.mViewScrollChanged) {
2304 attachInfo.mViewScrollChanged = false;
2305 attachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 }
Romain Guy8506ab42009-06-11 17:35:47 -07002307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002309 boolean animating = mScroller != null && mScroller.computeScrollOffset();
2310 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 yoff = mScroller.getCurrY();
2312 } else {
2313 yoff = mScrollY;
2314 }
2315 if (mCurScrollY != yoff) {
2316 mCurScrollY = yoff;
2317 fullRedrawNeeded = true;
2318 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002319
Romain Guy25eba5c2012-04-04 17:29:03 -07002320 final float appScale = attachInfo.mApplicationScale;
2321 final boolean scalingRequired = attachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002323 int resizeAlpha = 0;
Romain Guy7d70fbf2011-05-24 17:40:25 -07002324 if (mResizeBuffer != null) {
2325 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2326 if (deltaTime < mResizeBufferDuration) {
2327 float amt = deltaTime/(float) mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002328 amt = mResizeInterpolator.getInterpolation(amt);
2329 animating = true;
2330 resizeAlpha = 255 - (int)(amt*255);
2331 } else {
Romain Guy7d70fbf2011-05-24 17:40:25 -07002332 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002333 }
2334 }
2335
Jeff Brown96e942d2011-11-30 19:55:01 -08002336 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002337 if (mSurfaceHolder != null) {
2338 // The app owns the surface, we won't draw.
2339 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002340 if (animating) {
2341 if (mScroller != null) {
2342 mScroller.abortAnimation();
2343 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07002344 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002345 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002346 return;
2347 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002348
2349 if (fullRedrawNeeded) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002350 attachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002351 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002352 }
Chet Haasead4f7032011-06-22 09:18:31 -07002353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002355 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 + mWindowAttributes.getTitle()
2357 + ": dirty={" + dirty.left + "," + dirty.top
2358 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002359 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2360 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 }
2362
Romain Guyfbb93fa2012-12-03 18:50:35 -08002363 invalidateDisplayLists();
2364
Romain Guy25eba5c2012-04-04 17:29:03 -07002365 attachInfo.mTreeObserver.dispatchOnDraw();
2366
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002367 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002368 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002369 // Draw with hardware renderer.
2370 mIsAnimating = false;
2371 mHardwareYOffset = yoff;
2372 mResizeAlpha = resizeAlpha;
Romain Guyfea12b82011-01-27 15:36:40 -08002373
Jeff Brown96e942d2011-11-30 19:55:01 -08002374 mCurrentDirty.set(dirty);
Jeff Brown96e942d2011-11-30 19:55:01 -08002375 dirty.setEmpty();
2376
Romain Guye55945e2013-04-04 15:26:04 -07002377 attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
2378 animating ? null : mCurrentDirty);
Romain Guy3696779b2013-01-28 14:04:07 -08002379 } else {
2380 // If we get here with a disabled & requested hardware renderer, something went
2381 // wrong (an invalidate posted right before we destroyed the hardware surface
2382 // for instance) so we should just bail out. Locking the surface with software
2383 // rendering at this point would lock it forever and prevent hardware renderer
2384 // from doing its job when it comes back.
2385 // Before we request a new frame we must however attempt to reinitiliaze the
2386 // hardware renderer if it's in requested state. This would happen after an
2387 // eglTerminate() for instance.
2388 if (attachInfo.mHardwareRenderer != null &&
2389 !attachInfo.mHardwareRenderer.isEnabled() &&
2390 attachInfo.mHardwareRenderer.isRequested()) {
2391
2392 try {
2393 attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
2394 mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07002395 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002396 handleOutOfResourcesException(e);
2397 return;
2398 }
2399
2400 mFullRedrawNeeded = true;
2401 scheduleTraversals();
2402 return;
2403 }
2404
2405 if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2406 return;
2407 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002409 }
Romain Guy8506ab42009-06-11 17:35:47 -07002410
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002411 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 mFullRedrawNeeded = true;
2413 scheduleTraversals();
2414 }
2415 }
2416
Romain Guy25eba5c2012-04-04 17:29:03 -07002417 /**
Romain Guyedbca122012-04-04 18:25:53 -07002418 * @return true if drawing was succesfull, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002419 */
2420 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2421 boolean scalingRequired, Rect dirty) {
2422
2423 // Draw with software renderer.
2424 Canvas canvas;
2425 try {
2426 int left = dirty.left;
2427 int top = dirty.top;
2428 int right = dirty.right;
2429 int bottom = dirty.bottom;
2430
Romain Guy25eba5c2012-04-04 17:29:03 -07002431 canvas = mSurface.lockCanvas(dirty);
2432
Romain Guye55945e2013-04-04 15:26:04 -07002433 // The dirty rectangle can be modified by Surface.lockCanvas()
2434 //noinspection ConstantConditions
Romain Guy25eba5c2012-04-04 17:29:03 -07002435 if (left != dirty.left || top != dirty.top || right != dirty.right ||
2436 bottom != dirty.bottom) {
2437 attachInfo.mIgnoreDirtyState = true;
2438 }
2439
2440 // TODO: Do this in native
2441 canvas.setDensity(mDensity);
2442 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002443 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002444 return false;
2445 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002446 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002447 // Don't assume this is due to out of memory, it could be
2448 // something else, and if it is something else then we could
2449 // kill stuff (or ourself) for no reason.
2450 mLayoutRequested = true; // ask wm for a new surface next time.
2451 return false;
2452 }
2453
2454 try {
2455 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2456 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2457 + canvas.getWidth() + ", h=" + canvas.getHeight());
2458 //canvas.drawARGB(255, 255, 0, 0);
2459 }
2460
Romain Guy25eba5c2012-04-04 17:29:03 -07002461 // If this bitmap's format includes an alpha channel, we
2462 // need to clear it before drawing so that the child will
2463 // properly re-composite its drawing on a transparent
2464 // background. This automatically respects the clip/dirty region
2465 // or
2466 // If we are applying an offset, we need to clear the area
2467 // where the offset doesn't appear to avoid having garbage
2468 // left in the blank areas.
2469 if (!canvas.isOpaque() || yoff != 0) {
2470 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2471 }
2472
2473 dirty.setEmpty();
2474 mIsAnimating = false;
2475 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002476 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002477
2478 if (DEBUG_DRAW) {
2479 Context cxt = mView.getContext();
2480 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2481 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2482 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2483 }
2484 try {
2485 canvas.translate(0, -yoff);
2486 if (mTranslator != null) {
2487 mTranslator.translateCanvas(canvas);
2488 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002489 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002490 attachInfo.mSetIgnoreDirtyState = false;
2491
Romain Guy25eba5c2012-04-04 17:29:03 -07002492 mView.draw(canvas);
2493
Svetoslav Ganov42138042012-03-20 11:51:39 -07002494 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002495 } finally {
2496 if (!attachInfo.mSetIgnoreDirtyState) {
2497 // Only clear the flag if it was not set during the mView.draw() call
2498 attachInfo.mIgnoreDirtyState = false;
2499 }
2500 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002501 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002502 try {
2503 surface.unlockCanvasAndPost(canvas);
2504 } catch (IllegalArgumentException e) {
2505 Log.e(TAG, "Could not unlock surface", e);
2506 mLayoutRequested = true; // ask wm for a new surface next time.
2507 //noinspection ReturnInsideFinallyBlock
2508 return false;
2509 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002510
Romain Guy25eba5c2012-04-04 17:29:03 -07002511 if (LOCAL_LOGV) {
2512 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2513 }
2514 }
2515 return true;
2516 }
2517
Svetoslav Ganov42138042012-03-20 11:51:39 -07002518 /**
2519 * We want to draw a highlight around the current accessibility focused.
2520 * Since adding a style for all possible view is not a viable option we
2521 * have this specialized drawing method.
2522 *
2523 * Note: We are doing this here to be able to draw the highlight for
2524 * virtual views in addition to real ones.
2525 *
2526 * @param canvas The canvas on which to draw.
2527 */
2528 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
Svetoslav Ganov07b726c2012-04-30 12:24:57 -07002529 AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2530 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002531 return;
2532 }
2533 if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
2534 return;
2535 }
2536 Drawable drawable = getAccessibilityFocusedDrawable();
2537 if (drawable == null) {
2538 return;
2539 }
2540 AccessibilityNodeProvider provider =
2541 mAccessibilityFocusedHost.getAccessibilityNodeProvider();
2542 Rect bounds = mView.mAttachInfo.mTmpInvalRect;
2543 if (provider == null) {
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002544 mAccessibilityFocusedHost.getBoundsOnScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002545 } else {
2546 if (mAccessibilityFocusedVirtualView == null) {
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07002547 return;
2548 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002549 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002550 }
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002551 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Svetoslav Ganova94c3192012-10-31 18:28:49 -07002552 bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002553 drawable.setBounds(bounds);
2554 drawable.draw(canvas);
2555 }
2556
2557 private Drawable getAccessibilityFocusedDrawable() {
2558 if (mAttachInfo != null) {
2559 // Lazily load the accessibility focus drawable.
2560 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2561 TypedValue value = new TypedValue();
2562 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2563 R.attr.accessibilityFocusedDrawable, value, true);
2564 if (resolved) {
2565 mAttachInfo.mAccessibilityFocusDrawable =
2566 mView.mContext.getResources().getDrawable(value.resourceId);
2567 }
2568 }
2569 return mAttachInfo.mAccessibilityFocusDrawable;
2570 }
2571 return null;
2572 }
2573
Romain Guy51e4d4d2012-03-15 18:30:47 -07002574 void invalidateDisplayLists() {
2575 final ArrayList<DisplayList> displayLists = mDisplayLists;
2576 final int count = displayLists.size();
2577
2578 for (int i = 0; i < count; i++) {
Romain Guy38c2ece2012-05-24 14:20:56 -07002579 final DisplayList displayList = displayLists.get(i);
Romain Guyfbb93fa2012-12-03 18:50:35 -08002580 if (displayList.isDirty()) {
Romain Guy46bfc482013-08-16 18:38:29 -07002581 displayList.reset();
Romain Guyfbb93fa2012-12-03 18:50:35 -08002582 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07002583 }
2584
2585 displayLists.clear();
2586 }
2587
Michael Jurkaf42d90102013-05-08 18:00:04 +02002588 /**
2589 * @hide
2590 */
2591 public void setDrawDuringWindowsAnimating(boolean value) {
2592 mDrawDuringWindowsAnimating = value;
2593 if (value) {
2594 handleDispatchDoneAnimating();
2595 }
2596 }
2597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002598 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2599 final View.AttachInfo attachInfo = mAttachInfo;
2600 final Rect ci = attachInfo.mContentInsets;
2601 final Rect vi = attachInfo.mVisibleInsets;
2602 int scrollY = 0;
2603 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002605 if (vi.left > ci.left || vi.top > ci.top
2606 || vi.right > ci.right || vi.bottom > ci.bottom) {
2607 // We'll assume that we aren't going to change the scroll
2608 // offset, since we want to avoid that unless it is actually
2609 // going to make the focus visible... otherwise we scroll
2610 // all over the place.
2611 scrollY = mScrollY;
2612 // We can be called for two different situations: during a draw,
2613 // to update the scroll position if the focus has changed (in which
2614 // case 'rectangle' is null), or in response to a
2615 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2616 // is non-null and we just want to scroll to whatever that
2617 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002618 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002619 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002620 return false;
2621 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002622 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002623 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002624 // If the focus has changed, then ignore any requests to scroll
2625 // to a rectangle; first we want to make sure the entire focus
2626 // view is visible.
2627 rectangle = null;
2628 }
2629 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2630 + " rectangle=" + rectangle + " ci=" + ci
2631 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002632 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 // Optimization: if the focus hasn't changed since last
2634 // time, and no layout has happened, then just leave things
2635 // as they are.
2636 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2637 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002638 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 // We need to determine if the currently focused view is
2640 // within the visible part of the window and, if not, apply
2641 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002642 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 mScrollMayChange = false;
2644 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2645 // Try to find the rectangle from the focus view.
2646 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2647 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2648 + mView.getWidth() + " h=" + mView.getHeight()
2649 + " ci=" + ci.toShortString()
2650 + " vi=" + vi.toShortString());
2651 if (rectangle == null) {
2652 focus.getFocusedRect(mTempRect);
2653 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2654 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002655 if (mView instanceof ViewGroup) {
2656 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2657 focus, mTempRect);
2658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2660 "Focus in window: focusRect="
2661 + mTempRect.toShortString()
2662 + " visRect=" + mVisRect.toShortString());
2663 } else {
2664 mTempRect.set(rectangle);
2665 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2666 "Request scroll to rect: "
2667 + mTempRect.toShortString()
2668 + " visRect=" + mVisRect.toShortString());
2669 }
2670 if (mTempRect.intersect(mVisRect)) {
2671 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2672 "Focus window visible rect: "
2673 + mTempRect.toShortString());
2674 if (mTempRect.height() >
2675 (mView.getHeight()-vi.top-vi.bottom)) {
2676 // If the focus simply is not going to fit, then
2677 // best is probably just to leave things as-is.
2678 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2679 "Too tall; leaving scrollY=" + scrollY);
2680 } else if ((mTempRect.top-scrollY) < vi.top) {
2681 scrollY -= vi.top - (mTempRect.top-scrollY);
2682 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2683 "Top covered; scrollY=" + scrollY);
2684 } else if ((mTempRect.bottom-scrollY)
2685 > (mView.getHeight()-vi.bottom)) {
2686 scrollY += (mTempRect.bottom-scrollY)
2687 - (mView.getHeight()-vi.bottom);
2688 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2689 "Bottom covered; scrollY=" + scrollY);
2690 }
2691 handled = true;
2692 }
2693 }
2694 }
2695 }
Romain Guy8506ab42009-06-11 17:35:47 -07002696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002697 if (scrollY != mScrollY) {
2698 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2699 + mScrollY + " , new=" + scrollY);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002700 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 if (mScroller == null) {
2702 mScroller = new Scroller(mView.getContext());
2703 }
2704 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2705 } else if (mScroller != null) {
2706 mScroller.abortAnimation();
2707 }
2708 mScrollY = scrollY;
2709 }
Romain Guy8506ab42009-06-11 17:35:47 -07002710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 return handled;
2712 }
Romain Guy8506ab42009-06-11 17:35:47 -07002713
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002714 /**
2715 * @hide
2716 */
2717 public View getAccessibilityFocusedHost() {
2718 return mAccessibilityFocusedHost;
2719 }
2720
2721 /**
2722 * @hide
2723 */
2724 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2725 return mAccessibilityFocusedVirtualView;
2726 }
2727
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002728 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002729 // If we have a virtual view with accessibility focus we need
2730 // to clear the focus and invalidate the virtual view bounds.
2731 if (mAccessibilityFocusedVirtualView != null) {
2732
2733 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2734 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002735
2736 // Wipe the state of the current accessibility focus since
2737 // the call into the provider to clear accessibility focus
2738 // will fire an accessibility event which will end up calling
2739 // this method and we want to have clean state when this
2740 // invocation happens.
2741 mAccessibilityFocusedHost = null;
2742 mAccessibilityFocusedVirtualView = null;
2743
Alan Viverette239a0c02013-05-07 17:17:35 -07002744 // Clear accessibility focus on the host after clearing state since
2745 // this method may be reentrant.
2746 focusHost.clearAccessibilityFocusNoCallbacks();
2747
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002748 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2749 if (provider != null) {
2750 // Invalidate the area of the cleared accessibility focus.
2751 focusNode.getBoundsInParent(mTempRect);
2752 focusHost.invalidate(mTempRect);
2753 // Clear accessibility focus in the virtual node.
2754 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2755 focusNode.getSourceNodeId());
2756 provider.performAction(virtualNodeId,
2757 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2758 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002759 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002760 }
2761 if (mAccessibilityFocusedHost != null) {
2762 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002763 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2764 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002765
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002766 // Set the new focus host and node.
2767 mAccessibilityFocusedHost = view;
2768 mAccessibilityFocusedVirtualView = node;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002769 }
2770
Igor Murashkina86ab6402013-08-30 12:58:36 -07002771 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002772 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002773 if (DEBUG_INPUT_RESIZE) {
2774 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002776 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002777 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002778 }
2779
Igor Murashkina86ab6402013-08-30 12:58:36 -07002780 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002782 if (DEBUG_INPUT_RESIZE) {
2783 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002784 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002785 checkThread();
2786 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002787 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002788
Svetoslav Ganov42138042012-03-20 11:51:39 -07002789 @Override
2790 public ViewParent getParentForAccessibility() {
2791 return null;
2792 }
2793
Igor Murashkina86ab6402013-08-30 12:58:36 -07002794 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 public void focusableViewAvailable(View v) {
2796 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002797 if (mView != null) {
2798 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002800 } else {
2801 // the one case where will transfer focus away from the current one
2802 // is if the current view is a view group that prefers to give focus
2803 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002804 View focused = mView.findFocus();
2805 if (focused instanceof ViewGroup) {
2806 ViewGroup group = (ViewGroup) focused;
2807 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2808 && isViewDescendantOf(v, focused)) {
2809 v.requestFocus();
2810 }
Romain Guy1c90f032011-05-24 14:59:50 -07002811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002812 }
2813 }
2814 }
2815
Igor Murashkina86ab6402013-08-30 12:58:36 -07002816 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002817 public void recomputeViewAttributes(View child) {
2818 checkThread();
2819 if (mView == child) {
2820 mAttachInfo.mRecomputeGlobalAttributes = true;
2821 if (!mWillDrawSoon) {
2822 scheduleTraversals();
2823 }
2824 }
2825 }
2826
2827 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002828 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002829 if (mAttachInfo.mHardwareRenderer != null &&
2830 mAttachInfo.mHardwareRenderer.isEnabled()) {
2831 mAttachInfo.mHardwareRenderer.validate();
2832 }
Dianne Hackborn961cae92013-03-20 14:59:43 -07002833 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002834 mView.dispatchDetachedFromWindow();
2835 }
2836
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002837 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2838 mAccessibilityManager.removeAccessibilityStateChangeListener(
2839 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002840 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002841
Romain Guya998dff2012-03-23 18:58:36 -07002842 destroyHardwareRenderer();
2843
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002844 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002845
Craig Mautner8f303ad2013-06-14 11:32:22 -07002846 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002847 mView = null;
2848 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07002849 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002851 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852
Jeff Browncc4f7db2011-08-30 20:34:48 -07002853 if (mInputQueueCallback != null && mInputQueue != null) {
2854 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002855 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002856 mInputQueueCallback = null;
2857 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002858 }
2859 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002860 mInputEventReceiver.dispose();
2861 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002864 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002865 } catch (RemoteException e) {
2866 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07002867
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002868 // Dispose the input channel after removing the window so the Window Manager
2869 // doesn't interpret the input channel being closed as an abnormal termination.
2870 if (mInputChannel != null) {
2871 mInputChannel.dispose();
2872 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002873 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002874
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002875 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 }
Romain Guy8506ab42009-06-11 17:35:47 -07002877
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002878 void updateConfiguration(Configuration config, boolean force) {
2879 if (DEBUG_CONFIGURATION) Log.v(TAG,
2880 "Applying new config to window "
2881 + mWindowAttributes.getTitle()
2882 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002883
Craig Mautner48d0d182013-06-11 07:53:06 -07002884 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
2885 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002886 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002887 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002888 }
2889
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002890 synchronized (sConfigCallbacks) {
2891 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2892 sConfigCallbacks.get(i).onConfigurationChanged(config);
2893 }
2894 }
2895 if (mView != null) {
2896 // At this point the resources have been updated to
2897 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002898 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002899 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002900 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002901 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2902 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002903 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07002904 if (lastLayoutDirection != currentLayoutDirection &&
2905 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002906 mView.setLayoutDirection(currentLayoutDirection);
2907 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002908 mView.dispatchConfigurationChanged(config);
2909 }
2910 }
2911 }
Michael Wrightbdffc3a2014-02-26 15:40:44 -08002912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 /**
2914 * Return true if child is an ancestor of parent, (or equal to the parent).
2915 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002916 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 if (child == parent) {
2918 return true;
2919 }
2920
2921 final ViewParent theParent = child.getParent();
2922 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2923 }
2924
Romain Guycdb86672010-03-18 18:54:50 -07002925 private static void forceLayout(View view) {
2926 view.forceLayout();
2927 if (view instanceof ViewGroup) {
2928 ViewGroup group = (ViewGroup) view;
2929 final int count = group.getChildCount();
2930 for (int i = 0; i < count; i++) {
2931 forceLayout(group.getChildAt(i));
2932 }
2933 }
2934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935
Jeff Browna175a5b2012-02-15 19:18:31 -08002936 private final static int MSG_INVALIDATE = 1;
2937 private final static int MSG_INVALIDATE_RECT = 2;
2938 private final static int MSG_DIE = 3;
2939 private final static int MSG_RESIZED = 4;
2940 private final static int MSG_RESIZED_REPORT = 5;
2941 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07002942 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08002943 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2944 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08002945 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2946 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2947 private final static int MSG_CHECK_FOCUS = 13;
2948 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2949 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2950 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2951 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2952 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002953 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2954 private final static int MSG_DISPATCH_SCREEN_STATE = 20;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002955 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
2956 private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
2957 private final static int MSG_INVALIDATE_WORLD = 23;
2958 private final static int MSG_WINDOW_MOVED = 24;
Romain Guy40543602013-06-12 15:31:28 -07002959 private final static int MSG_FLUSH_LAYER_UPDATES = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960
Jeff Browna175a5b2012-02-15 19:18:31 -08002961 final class ViewRootHandler extends Handler {
2962 @Override
2963 public String getMessageName(Message message) {
2964 switch (message.what) {
2965 case MSG_INVALIDATE:
2966 return "MSG_INVALIDATE";
2967 case MSG_INVALIDATE_RECT:
2968 return "MSG_INVALIDATE_RECT";
2969 case MSG_DIE:
2970 return "MSG_DIE";
2971 case MSG_RESIZED:
2972 return "MSG_RESIZED";
2973 case MSG_RESIZED_REPORT:
2974 return "MSG_RESIZED_REPORT";
2975 case MSG_WINDOW_FOCUS_CHANGED:
2976 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07002977 case MSG_DISPATCH_INPUT_EVENT:
2978 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08002979 case MSG_DISPATCH_APP_VISIBILITY:
2980 return "MSG_DISPATCH_APP_VISIBILITY";
2981 case MSG_DISPATCH_GET_NEW_SURFACE:
2982 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08002983 case MSG_DISPATCH_KEY_FROM_IME:
2984 return "MSG_DISPATCH_KEY_FROM_IME";
2985 case MSG_FINISH_INPUT_CONNECTION:
2986 return "MSG_FINISH_INPUT_CONNECTION";
2987 case MSG_CHECK_FOCUS:
2988 return "MSG_CHECK_FOCUS";
2989 case MSG_CLOSE_SYSTEM_DIALOGS:
2990 return "MSG_CLOSE_SYSTEM_DIALOGS";
2991 case MSG_DISPATCH_DRAG_EVENT:
2992 return "MSG_DISPATCH_DRAG_EVENT";
2993 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
2994 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
2995 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
2996 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
2997 case MSG_UPDATE_CONFIGURATION:
2998 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08002999 case MSG_PROCESS_INPUT_EVENTS:
3000 return "MSG_PROCESS_INPUT_EVENTS";
Romain Guy51e4d4d2012-03-15 18:30:47 -07003001 case MSG_DISPATCH_SCREEN_STATE:
3002 return "MSG_DISPATCH_SCREEN_STATE";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003003 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3004 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003005 case MSG_DISPATCH_DONE_ANIMATING:
3006 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003007 case MSG_WINDOW_MOVED:
3008 return "MSG_WINDOW_MOVED";
Romain Guy40543602013-06-12 15:31:28 -07003009 case MSG_FLUSH_LAYER_UPDATES:
3010 return "MSG_FLUSH_LAYER_UPDATES";
Jeff Browna175a5b2012-02-15 19:18:31 -08003011 }
3012 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003013 }
Romain Guyf9284692011-07-13 18:46:21 -07003014
Jeff Browna175a5b2012-02-15 19:18:31 -08003015 @Override
3016 public void handleMessage(Message msg) {
3017 switch (msg.what) {
3018 case MSG_INVALIDATE:
3019 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003021 case MSG_INVALIDATE_RECT:
3022 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3023 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003024 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003025 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003026 case MSG_PROCESS_INPUT_EVENTS:
3027 mProcessInputEventsScheduled = false;
3028 doProcessInputEvents();
3029 break;
3030 case MSG_DISPATCH_APP_VISIBILITY:
3031 handleAppVisibility(msg.arg1 != 0);
3032 break;
3033 case MSG_DISPATCH_GET_NEW_SURFACE:
3034 handleGetNewSurface();
3035 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003036 case MSG_RESIZED: {
3037 // Recycled in the fall through...
3038 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003039 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003040 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003041 && mPendingContentInsets.equals(args.arg2)
3042 && mPendingVisibleInsets.equals(args.arg3)
3043 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003044 break;
Romain Guycdb86672010-03-18 18:54:50 -07003045 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003046 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003047 case MSG_RESIZED_REPORT:
3048 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003049 SomeArgs args = (SomeArgs) msg.obj;
3050
3051 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003052 if (config != null) {
3053 updateConfiguration(config, false);
3054 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003055
3056 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003057 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003058 mPendingContentInsets.set((Rect) args.arg2);
3059 mPendingVisibleInsets.set((Rect) args.arg3);
3060
3061 args.recycle();
3062
Jeff Browna175a5b2012-02-15 19:18:31 -08003063 if (msg.what == MSG_RESIZED_REPORT) {
3064 mReportNextDraw = true;
3065 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003066
Jeff Browna175a5b2012-02-15 19:18:31 -08003067 if (mView != null) {
3068 forceLayout(mView);
3069 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003070
Jeff Browna175a5b2012-02-15 19:18:31 -08003071 requestLayout();
3072 }
3073 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003074 case MSG_WINDOW_MOVED:
3075 if (mAdded) {
3076 final int w = mWinFrame.width();
3077 final int h = mWinFrame.height();
3078 final int l = msg.arg1;
3079 final int t = msg.arg2;
3080 mWinFrame.left = l;
3081 mWinFrame.right = l + w;
3082 mWinFrame.top = t;
3083 mWinFrame.bottom = t + h;
3084
3085 if (mView != null) {
3086 forceLayout(mView);
3087 }
3088 requestLayout();
3089 }
3090 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003091 case MSG_WINDOW_FOCUS_CHANGED: {
3092 if (mAdded) {
3093 boolean hasWindowFocus = msg.arg1 != 0;
3094 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095
Jeff Browna175a5b2012-02-15 19:18:31 -08003096 profileRendering(hasWindowFocus);
3097
3098 if (hasWindowFocus) {
3099 boolean inTouchMode = msg.arg2 != 0;
3100 ensureTouchModeLocally(inTouchMode);
3101
Romain Guye55945e2013-04-04 15:26:04 -07003102 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003103 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003104 try {
Romain Guy3696779b2013-01-28 14:04:07 -08003105 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
3106 mWidth, mHeight, mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07003107 } catch (OutOfResourcesException e) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003108 Log.e(TAG, "OutOfResourcesException locking surface", e);
3109 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003110 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003111 Slog.w(TAG, "No processes killed for memory; killing self");
3112 Process.killProcess(Process.myPid());
3113 }
3114 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003115 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003116 // Retry in a bit.
3117 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3118 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003119 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003120 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121 }
Romain Guy8506ab42009-06-11 17:35:47 -07003122
Jeff Browna175a5b2012-02-15 19:18:31 -08003123 mLastWasImTarget = WindowManager.LayoutParams
3124 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003125
Jeff Browna175a5b2012-02-15 19:18:31 -08003126 InputMethodManager imm = InputMethodManager.peekInstance();
3127 if (mView != null) {
keunyoung30f420f2013-08-02 14:23:10 -07003128 if (hasWindowFocus && imm != null && mLastWasImTarget &&
3129 !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003130 imm.startGettingWindowFocus(mView);
3131 }
3132 mAttachInfo.mKeyDispatchState.reset();
3133 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003134 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003135 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003136
Jeff Browna175a5b2012-02-15 19:18:31 -08003137 // Note: must be done after the focus change callbacks,
3138 // so all of the view state is set up correctly.
3139 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003140 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003141 imm.onWindowFocus(mView, mView.findFocus(),
3142 mWindowAttributes.softInputMode,
3143 !mHasHadWindowFocus, mWindowAttributes.flags);
3144 }
3145 // Clear the forward bit. We can just do this directly, since
3146 // the window manager doesn't care about it.
3147 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003149 ((WindowManager.LayoutParams)mView.getLayoutParams())
3150 .softInputMode &=
3151 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3152 mHasHadWindowFocus = true;
3153 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003154
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003155 setAccessibilityFocus(null, null);
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07003156
Svetoslav Ganov42138042012-03-20 11:51:39 -07003157 if (mView != null && mAccessibilityManager.isEnabled()) {
3158 if (hasWindowFocus) {
3159 mView.sendAccessibilityEvent(
3160 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003161 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003162 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003163 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003164 } break;
3165 case MSG_DIE:
3166 doDie();
3167 break;
keunyoung30f420f2013-08-02 14:23:10 -07003168 case MSG_DISPATCH_INPUT_EVENT: {
3169 InputEvent event = (InputEvent)msg.obj;
Jeff Browna175a5b2012-02-15 19:18:31 -08003170 enqueueInputEvent(event, null, 0, true);
3171 } break;
3172 case MSG_DISPATCH_KEY_FROM_IME: {
3173 if (LOCAL_LOGV) Log.v(
3174 TAG, "Dispatching key "
3175 + msg.obj + " from IME to " + mView);
3176 KeyEvent event = (KeyEvent)msg.obj;
3177 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3178 // The IME is trying to say this event is from the
3179 // system! Bad bad bad!
3180 //noinspection UnusedAssignment
3181 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
3182 }
3183 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3184 } break;
3185 case MSG_FINISH_INPUT_CONNECTION: {
3186 InputMethodManager imm = InputMethodManager.peekInstance();
3187 if (imm != null) {
3188 imm.reportFinishInputConnection((InputConnection)msg.obj);
3189 }
3190 } break;
3191 case MSG_CHECK_FOCUS: {
3192 InputMethodManager imm = InputMethodManager.peekInstance();
3193 if (imm != null) {
3194 imm.checkFocus();
3195 }
3196 } break;
3197 case MSG_CLOSE_SYSTEM_DIALOGS: {
3198 if (mView != null) {
3199 mView.onCloseSystemDialogs((String)msg.obj);
3200 }
3201 } break;
3202 case MSG_DISPATCH_DRAG_EVENT:
3203 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3204 DragEvent event = (DragEvent)msg.obj;
3205 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3206 handleDragEvent(event);
3207 } break;
3208 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003209 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003210 } break;
3211 case MSG_UPDATE_CONFIGURATION: {
3212 Configuration config = (Configuration)msg.obj;
3213 if (config.isOtherSeqNewer(mLastConfiguration)) {
3214 config = mLastConfiguration;
3215 }
3216 updateConfiguration(config, false);
3217 } break;
Romain Guybb9908b2012-03-08 11:14:07 -08003218 case MSG_DISPATCH_SCREEN_STATE: {
Romain Guy7e4e5612012-03-05 14:37:29 -08003219 if (mView != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08003220 handleScreenStateChange(msg.arg1 == 1);
Romain Guy7e4e5612012-03-05 14:37:29 -08003221 }
3222 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003223 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003224 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003225 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003226 case MSG_DISPATCH_DONE_ANIMATING: {
3227 handleDispatchDoneAnimating();
3228 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003229 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003230 if (mView != null) {
3231 invalidateWorld(mView);
3232 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003233 } break;
Romain Guy40543602013-06-12 15:31:28 -07003234 case MSG_FLUSH_LAYER_UPDATES: {
3235 flushHardwareLayerUpdates();
3236 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 }
3239 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003240
Jeff Browna175a5b2012-02-15 19:18:31 -08003241 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 /**
3244 * Something in the current window tells us we need to change the touch mode. For
3245 * example, we are not in touch mode, and the user touches the screen.
3246 *
3247 * If the touch mode has changed, tell the window manager, and handle it locally.
3248 *
3249 * @param inTouchMode Whether we want to be in touch mode.
3250 * @return True if the touch mode changed and focus changed was changed as a result
3251 */
3252 boolean ensureTouchMode(boolean inTouchMode) {
3253 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3254 + "touch mode is " + mAttachInfo.mInTouchMode);
3255 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3256
3257 // tell the window manager
3258 try {
keunyoung30f420f2013-08-02 14:23:10 -07003259 if (!isInLocalFocusMode()) {
3260 mWindowSession.setInTouchMode(inTouchMode);
3261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 } catch (RemoteException e) {
3263 throw new RuntimeException(e);
3264 }
3265
3266 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003267 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003268 }
3269
3270 /**
3271 * Ensure that the touch mode for this window is set, and if it is changing,
3272 * take the appropriate action.
3273 * @param inTouchMode Whether we want to be in touch mode.
3274 * @return True if the touch mode changed and focus changed was changed as a result
3275 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003276 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3278 + "touch mode is " + mAttachInfo.mInTouchMode);
3279
3280 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3281
3282 mAttachInfo.mInTouchMode = inTouchMode;
3283 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3284
Romain Guy2d4cff62010-04-09 15:39:00 -07003285 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 }
3287
3288 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003289 if (mView != null && mView.hasFocus()) {
3290 // note: not relying on mFocusedView here because this could
3291 // be when the window is first being added, and mFocused isn't
3292 // set yet.
3293 final View focused = mView.findFocus();
3294 if (focused != null && !focused.isFocusableInTouchMode()) {
3295 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3296 if (ancestorToTakeFocus != null) {
3297 // there is an ancestor that wants focus after its
3298 // descendants that is focusable in touch mode.. give it
3299 // focus
3300 return ancestorToTakeFocus.requestFocus();
3301 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003302 // There's nothing to focus. Clear and propagate through the
3303 // hierarchy, but don't attempt to place new focus.
3304 focused.clearFocusInternal(true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003305 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 }
3307 }
3308 }
3309 return false;
3310 }
3311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003312 /**
3313 * Find an ancestor of focused that wants focus after its descendants and is
3314 * focusable in touch mode.
3315 * @param focused The currently focused view.
3316 * @return An appropriate view, or null if no such view exists.
3317 */
Romain Guya998dff2012-03-23 18:58:36 -07003318 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 ViewParent parent = focused.getParent();
3320 while (parent instanceof ViewGroup) {
3321 final ViewGroup vgParent = (ViewGroup) parent;
3322 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3323 && vgParent.isFocusableInTouchMode()) {
3324 return vgParent;
3325 }
3326 if (vgParent.isRootNamespace()) {
3327 return null;
3328 } else {
3329 parent = vgParent.getParent();
3330 }
3331 }
3332 return null;
3333 }
3334
3335 private boolean leaveTouchMode() {
3336 if (mView != null) {
3337 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003338 View focusedView = mView.findFocus();
3339 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003341 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003342 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3344 // some view group has focus, and doesn't prefer its children
3345 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003346 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 }
3348 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003349
3350 // find the best view to give focus to in this brave new non-touch-mode
3351 // world
3352 final View focused = focusSearch(null, View.FOCUS_DOWN);
3353 if (focused != null) {
3354 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 }
3356 }
3357 return false;
3358 }
3359
Jeff Brownf9e989d2013-04-04 23:04:03 -07003360 /**
3361 * Base class for implementing a stage in the chain of responsibility
3362 * for processing input events.
3363 * <p>
3364 * Events are delivered to the stage by the {@link #deliver} method. The stage
3365 * then has the choice of finishing the event or forwarding it to the next stage.
3366 * </p>
3367 */
3368 abstract class InputStage {
3369 private final InputStage mNext;
3370
3371 protected static final int FORWARD = 0;
3372 protected static final int FINISH_HANDLED = 1;
3373 protected static final int FINISH_NOT_HANDLED = 2;
3374
3375 /**
3376 * Creates an input stage.
3377 * @param next The next stage to which events should be forwarded.
3378 */
3379 public InputStage(InputStage next) {
3380 mNext = next;
3381 }
3382
3383 /**
3384 * Delivers an event to be processed.
3385 */
3386 public final void deliver(QueuedInputEvent q) {
3387 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3388 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003389 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003390 finish(q, false);
3391 } else {
3392 apply(q, onProcess(q));
3393 }
3394 }
3395
3396 /**
3397 * Marks the the input event as finished then forwards it to the next stage.
3398 */
3399 protected void finish(QueuedInputEvent q, boolean handled) {
3400 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3401 if (handled) {
3402 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3403 }
3404 forward(q);
3405 }
3406
3407 /**
3408 * Forwards the event to the next stage.
3409 */
3410 protected void forward(QueuedInputEvent q) {
3411 onDeliverToNext(q);
3412 }
3413
3414 /**
3415 * Applies a result code from {@link #onProcess} to the specified event.
3416 */
3417 protected void apply(QueuedInputEvent q, int result) {
3418 if (result == FORWARD) {
3419 forward(q);
3420 } else if (result == FINISH_HANDLED) {
3421 finish(q, true);
3422 } else if (result == FINISH_NOT_HANDLED) {
3423 finish(q, false);
3424 } else {
3425 throw new IllegalArgumentException("Invalid result: " + result);
3426 }
3427 }
3428
3429 /**
3430 * Called when an event is ready to be processed.
3431 * @return A result code indicating how the event was handled.
3432 */
3433 protected int onProcess(QueuedInputEvent q) {
3434 return FORWARD;
3435 }
3436
3437 /**
3438 * Called when an event is being delivered to the next stage.
3439 */
3440 protected void onDeliverToNext(QueuedInputEvent q) {
3441 if (mNext != null) {
3442 mNext.deliver(q);
3443 } else {
3444 finishInputEvent(q);
3445 }
3446 }
Jeff Brown5182c782013-10-15 20:31:52 -07003447
Michael Wright17d28ca2013-10-31 17:47:45 -07003448 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3449 if (mView == null || !mAdded) {
3450 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3451 return true;
3452 } else if (!mAttachInfo.mHasWindowFocus &&
3453 !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
3454 !isTerminalInputEvent(q.mEvent)) {
3455 // If this is a focused event and the window doesn't currently have input focus,
3456 // then drop this event. This could be an event that came back from the previous
3457 // stage but the window has lost focus in the meantime.
3458 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
3459 return true;
3460 }
3461 return false;
3462 }
3463
Jeff Brown5182c782013-10-15 20:31:52 -07003464 void dump(String prefix, PrintWriter writer) {
3465 if (mNext != null) {
3466 mNext.dump(prefix, writer);
3467 }
3468 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003469 }
3470
3471 /**
3472 * Base class for implementing an input pipeline stage that supports
3473 * asynchronous and out-of-order processing of input events.
3474 * <p>
3475 * In addition to what a normal input stage can do, an asynchronous
3476 * input stage may also defer an input event that has been delivered to it
3477 * and finish or forward it later.
3478 * </p>
3479 */
3480 abstract class AsyncInputStage extends InputStage {
3481 private final String mTraceCounter;
3482
3483 private QueuedInputEvent mQueueHead;
3484 private QueuedInputEvent mQueueTail;
3485 private int mQueueLength;
3486
3487 protected static final int DEFER = 3;
3488
3489 /**
3490 * Creates an asynchronous input stage.
3491 * @param next The next stage to which events should be forwarded.
3492 * @param traceCounter The name of a counter to record the size of
3493 * the queue of pending events.
3494 */
3495 public AsyncInputStage(InputStage next, String traceCounter) {
3496 super(next);
3497 mTraceCounter = traceCounter;
3498 }
3499
3500 /**
3501 * Marks the event as deferred, which is to say that it will be handled
3502 * asynchronously. The caller is responsible for calling {@link #forward}
3503 * or {@link #finish} later when it is done handling the event.
3504 */
3505 protected void defer(QueuedInputEvent q) {
3506 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3507 enqueue(q);
3508 }
3509
3510 @Override
3511 protected void forward(QueuedInputEvent q) {
3512 // Clear the deferred flag.
3513 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3514
3515 // Fast path if the queue is empty.
3516 QueuedInputEvent curr = mQueueHead;
3517 if (curr == null) {
3518 super.forward(q);
3519 return;
3520 }
3521
3522 // Determine whether the event must be serialized behind any others
3523 // before it can be delivered to the next stage. This is done because
3524 // deferred events might be handled out of order by the stage.
3525 final int deviceId = q.mEvent.getDeviceId();
3526 QueuedInputEvent prev = null;
3527 boolean blocked = false;
3528 while (curr != null && curr != q) {
3529 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3530 blocked = true;
3531 }
3532 prev = curr;
3533 curr = curr.mNext;
3534 }
3535
3536 // If the event is blocked, then leave it in the queue to be delivered later.
3537 // Note that the event might not yet be in the queue if it was not previously
3538 // deferred so we will enqueue it if needed.
3539 if (blocked) {
3540 if (curr == null) {
3541 enqueue(q);
3542 }
3543 return;
3544 }
3545
3546 // The event is not blocked. Deliver it immediately.
3547 if (curr != null) {
3548 curr = curr.mNext;
3549 dequeue(q, prev);
3550 }
3551 super.forward(q);
3552
3553 // Dequeuing this event may have unblocked successors. Deliver them.
3554 while (curr != null) {
3555 if (deviceId == curr.mEvent.getDeviceId()) {
3556 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3557 break;
3558 }
3559 QueuedInputEvent next = curr.mNext;
3560 dequeue(curr, prev);
3561 super.forward(curr);
3562 curr = next;
3563 } else {
3564 prev = curr;
3565 curr = curr.mNext;
3566 }
3567 }
3568 }
3569
3570 @Override
3571 protected void apply(QueuedInputEvent q, int result) {
3572 if (result == DEFER) {
3573 defer(q);
3574 } else {
3575 super.apply(q, result);
3576 }
3577 }
3578
3579 private void enqueue(QueuedInputEvent q) {
3580 if (mQueueTail == null) {
3581 mQueueHead = q;
3582 mQueueTail = q;
3583 } else {
3584 mQueueTail.mNext = q;
3585 mQueueTail = q;
3586 }
3587
3588 mQueueLength += 1;
3589 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3590 }
3591
3592 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3593 if (prev == null) {
3594 mQueueHead = q.mNext;
3595 } else {
3596 prev.mNext = q.mNext;
3597 }
3598 if (mQueueTail == q) {
3599 mQueueTail = prev;
3600 }
3601 q.mNext = null;
3602
3603 mQueueLength -= 1;
3604 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3605 }
Jeff Brown5182c782013-10-15 20:31:52 -07003606
3607 @Override
3608 void dump(String prefix, PrintWriter writer) {
3609 writer.print(prefix);
3610 writer.print(getClass().getName());
3611 writer.print(": mQueueLength=");
3612 writer.println(mQueueLength);
3613
3614 super.dump(prefix, writer);
3615 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003616 }
3617
3618 /**
3619 * Delivers pre-ime input events to a native activity.
3620 * Does not support pointer events.
3621 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003622 final class NativePreImeInputStage extends AsyncInputStage
3623 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003624 public NativePreImeInputStage(InputStage next, String traceCounter) {
3625 super(next, traceCounter);
3626 }
3627
3628 @Override
3629 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003630 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3631 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3632 return DEFER;
3633 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003634 return FORWARD;
3635 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003636
3637 @Override
3638 public void onFinishedInputEvent(Object token, boolean handled) {
3639 QueuedInputEvent q = (QueuedInputEvent)token;
3640 if (handled) {
3641 finish(q, true);
3642 return;
3643 }
3644 forward(q);
3645 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003646 }
3647
3648 /**
3649 * Delivers pre-ime input events to the view hierarchy.
3650 * Does not support pointer events.
3651 */
3652 final class ViewPreImeInputStage extends InputStage {
3653 public ViewPreImeInputStage(InputStage next) {
3654 super(next);
3655 }
3656
3657 @Override
3658 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003659 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003660 return processKeyEvent(q);
3661 }
3662 return FORWARD;
3663 }
3664
3665 private int processKeyEvent(QueuedInputEvent q) {
3666 final KeyEvent event = (KeyEvent)q.mEvent;
3667 if (mView.dispatchKeyEventPreIme(event)) {
3668 return FINISH_HANDLED;
3669 }
3670 return FORWARD;
3671 }
3672 }
3673
3674 /**
3675 * Delivers input events to the ime.
3676 * Does not support pointer events.
3677 */
3678 final class ImeInputStage extends AsyncInputStage
3679 implements InputMethodManager.FinishedInputEventCallback {
3680 public ImeInputStage(InputStage next, String traceCounter) {
3681 super(next, traceCounter);
3682 }
3683
3684 @Override
3685 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07003686 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003687 InputMethodManager imm = InputMethodManager.peekInstance();
3688 if (imm != null) {
3689 final InputEvent event = q.mEvent;
3690 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3691 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3692 if (result == InputMethodManager.DISPATCH_HANDLED) {
3693 return FINISH_HANDLED;
3694 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
3695 return FINISH_NOT_HANDLED;
3696 } else {
3697 return DEFER; // callback will be invoked later
3698 }
3699 }
3700 }
3701 return FORWARD;
3702 }
3703
3704 @Override
3705 public void onFinishedInputEvent(Object token, boolean handled) {
3706 QueuedInputEvent q = (QueuedInputEvent)token;
3707 if (handled) {
3708 finish(q, true);
3709 return;
3710 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003711 forward(q);
3712 }
3713 }
3714
3715 /**
3716 * Performs early processing of post-ime input events.
3717 */
3718 final class EarlyPostImeInputStage extends InputStage {
3719 public EarlyPostImeInputStage(InputStage next) {
3720 super(next);
3721 }
3722
3723 @Override
3724 protected int onProcess(QueuedInputEvent q) {
3725 if (q.mEvent instanceof KeyEvent) {
3726 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003727 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003728 final int source = q.mEvent.getSource();
3729 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003730 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003731 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003732 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003733 return FORWARD;
3734 }
3735
3736 private int processKeyEvent(QueuedInputEvent q) {
3737 final KeyEvent event = (KeyEvent)q.mEvent;
3738
3739 // If the key's purpose is to exit touch mode then we consume it
3740 // and consider it handled.
3741 if (checkForLeavingTouchModeAndConsume(event)) {
3742 return FINISH_HANDLED;
3743 }
3744
3745 // Make sure the fallback event policy sees all keys that will be
3746 // delivered to the view hierarchy.
3747 mFallbackEventHandler.preDispatchKeyEvent(event);
3748 return FORWARD;
3749 }
3750
3751 private int processPointerEvent(QueuedInputEvent q) {
3752 final MotionEvent event = (MotionEvent)q.mEvent;
3753
3754 // Translate the pointer event for compatibility, if needed.
3755 if (mTranslator != null) {
3756 mTranslator.translateEventInScreenToAppWindow(event);
3757 }
3758
3759 // Enter touch mode on down or scroll.
3760 final int action = event.getAction();
3761 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3762 ensureTouchMode(true);
3763 }
3764
3765 // Offset the scroll position.
3766 if (mCurScrollY != 0) {
3767 event.offsetLocation(0, mCurScrollY);
3768 }
3769
3770 // Remember the touch position for possible drag-initiation.
3771 if (event.isTouchEvent()) {
3772 mLastTouchPoint.x = event.getRawX();
3773 mLastTouchPoint.y = event.getRawY();
3774 }
3775 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003776 }
3777 }
3778
Jeff Brownf9e989d2013-04-04 23:04:03 -07003779 /**
3780 * Delivers post-ime input events to a native activity.
3781 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003782 final class NativePostImeInputStage extends AsyncInputStage
3783 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003784 public NativePostImeInputStage(InputStage next, String traceCounter) {
3785 super(next, traceCounter);
3786 }
3787
3788 @Override
3789 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003790 if (mInputQueue != null) {
3791 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3792 return DEFER;
3793 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003794 return FORWARD;
3795 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003796
3797 @Override
3798 public void onFinishedInputEvent(Object token, boolean handled) {
3799 QueuedInputEvent q = (QueuedInputEvent)token;
3800 if (handled) {
3801 finish(q, true);
3802 return;
3803 }
3804 forward(q);
3805 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003806 }
3807
3808 /**
3809 * Delivers post-ime input events to the view hierarchy.
3810 */
3811 final class ViewPostImeInputStage extends InputStage {
3812 public ViewPostImeInputStage(InputStage next) {
3813 super(next);
3814 }
3815
3816 @Override
3817 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003818 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003819 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003820 } else {
Dianne Hackborn021d2432013-10-13 15:20:09 -07003821 // If delivering a new non-key event, make sure the window is
3822 // now allowed to start updating.
3823 handleDispatchDoneAnimating();
Jeff Brown29c0ed22013-01-14 13:50:37 -08003824 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003825 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3826 return processPointerEvent(q);
3827 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3828 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003829 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003830 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003831 }
3832 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003833 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003834
Jeff Brownf9e989d2013-04-04 23:04:03 -07003835 private int processKeyEvent(QueuedInputEvent q) {
3836 final KeyEvent event = (KeyEvent)q.mEvent;
3837
Dianne Hackborn021d2432013-10-13 15:20:09 -07003838 if (event.getAction() != KeyEvent.ACTION_UP) {
3839 // If delivering a new key event, make sure the window is
3840 // now allowed to start updating.
3841 handleDispatchDoneAnimating();
3842 }
3843
Jeff Brownf9e989d2013-04-04 23:04:03 -07003844 // Deliver the key to the view hierarchy.
3845 if (mView.dispatchKeyEvent(event)) {
3846 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003847 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003848
Michael Wright17d28ca2013-10-31 17:47:45 -07003849 if (shouldDropInputEvent(q)) {
3850 return FINISH_NOT_HANDLED;
3851 }
3852
Jeff Brownf9e989d2013-04-04 23:04:03 -07003853 // If the Control modifier is held, try to interpret the key as a shortcut.
3854 if (event.getAction() == KeyEvent.ACTION_DOWN
3855 && event.isCtrlPressed()
3856 && event.getRepeatCount() == 0
3857 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3858 if (mView.dispatchKeyShortcutEvent(event)) {
3859 return FINISH_HANDLED;
3860 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003861 if (shouldDropInputEvent(q)) {
3862 return FINISH_NOT_HANDLED;
3863 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003864 }
3865
3866 // Apply the fallback event policy.
3867 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3868 return FINISH_HANDLED;
3869 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003870 if (shouldDropInputEvent(q)) {
3871 return FINISH_NOT_HANDLED;
3872 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003873
3874 // Handle automatic focus changes.
3875 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3876 int direction = 0;
3877 switch (event.getKeyCode()) {
3878 case KeyEvent.KEYCODE_DPAD_LEFT:
3879 if (event.hasNoModifiers()) {
3880 direction = View.FOCUS_LEFT;
3881 }
3882 break;
3883 case KeyEvent.KEYCODE_DPAD_RIGHT:
3884 if (event.hasNoModifiers()) {
3885 direction = View.FOCUS_RIGHT;
3886 }
3887 break;
3888 case KeyEvent.KEYCODE_DPAD_UP:
3889 if (event.hasNoModifiers()) {
3890 direction = View.FOCUS_UP;
3891 }
3892 break;
3893 case KeyEvent.KEYCODE_DPAD_DOWN:
3894 if (event.hasNoModifiers()) {
3895 direction = View.FOCUS_DOWN;
3896 }
3897 break;
3898 case KeyEvent.KEYCODE_TAB:
3899 if (event.hasNoModifiers()) {
3900 direction = View.FOCUS_FORWARD;
3901 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3902 direction = View.FOCUS_BACKWARD;
3903 }
3904 break;
3905 }
3906 if (direction != 0) {
3907 View focused = mView.findFocus();
3908 if (focused != null) {
3909 View v = focused.focusSearch(direction);
3910 if (v != null && v != focused) {
3911 // do the math the get the interesting rect
3912 // of previous focused into the coord system of
3913 // newly focused view
3914 focused.getFocusedRect(mTempRect);
3915 if (mView instanceof ViewGroup) {
3916 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3917 focused, mTempRect);
3918 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3919 v, mTempRect);
3920 }
3921 if (v.requestFocus(direction, mTempRect)) {
3922 playSoundEffect(SoundEffectConstants
3923 .getContantForFocusDirection(direction));
3924 return FINISH_HANDLED;
3925 }
3926 }
3927
3928 // Give the focused view a last chance to handle the dpad key.
3929 if (mView.dispatchUnhandledMove(focused, direction)) {
3930 return FINISH_HANDLED;
3931 }
3932 } else {
3933 // find the best view to give focus to in this non-touch-mode with no-focus
3934 View v = focusSearch(null, direction);
3935 if (v != null && v.requestFocus(direction)) {
3936 return FINISH_HANDLED;
3937 }
3938 }
3939 }
3940 }
3941 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003942 }
3943
Jeff Brownf9e989d2013-04-04 23:04:03 -07003944 private int processPointerEvent(QueuedInputEvent q) {
3945 final MotionEvent event = (MotionEvent)q.mEvent;
3946
3947 if (mView.dispatchPointerEvent(event)) {
3948 return FINISH_HANDLED;
3949 }
3950 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003951 }
3952
Jeff Brownf9e989d2013-04-04 23:04:03 -07003953 private int processTrackballEvent(QueuedInputEvent q) {
3954 final MotionEvent event = (MotionEvent)q.mEvent;
3955
3956 if (mView.dispatchTrackballEvent(event)) {
3957 return FINISH_HANDLED;
3958 }
3959 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960 }
3961
Jeff Brownf9e989d2013-04-04 23:04:03 -07003962 private int processGenericMotionEvent(QueuedInputEvent q) {
3963 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003964
Jeff Brownf9e989d2013-04-04 23:04:03 -07003965 // Deliver the event to the view.
3966 if (mView.dispatchGenericMotionEvent(event)) {
3967 return FINISH_HANDLED;
3968 }
3969 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003970 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003971 }
3972
Jeff Brownf9e989d2013-04-04 23:04:03 -07003973 /**
Jeff Brown678a1252013-04-09 17:46:25 -07003974 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07003975 */
3976 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07003977 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
3978 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
3979 private final SyntheticTouchNavigationHandler mTouchNavigation =
3980 new SyntheticTouchNavigationHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003981
3982 public SyntheticInputStage() {
3983 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08003984 }
3985
Jeff Brownf9e989d2013-04-04 23:04:03 -07003986 @Override
3987 protected int onProcess(QueuedInputEvent q) {
3988 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
3989 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07003990 final MotionEvent event = (MotionEvent)q.mEvent;
3991 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003992 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003993 mTrackball.process(event);
3994 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003995 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003996 mJoystick.process(event);
3997 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003998 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
3999 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004000 mTouchNavigation.process(event);
4001 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004002 }
4003 }
4004 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004005 }
4006
Jeff Brownf9e989d2013-04-04 23:04:03 -07004007 @Override
4008 protected void onDeliverToNext(QueuedInputEvent q) {
4009 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4010 // Cancel related synthetic events if any prior stage has handled the event.
4011 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004012 final MotionEvent event = (MotionEvent)q.mEvent;
4013 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004014 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004015 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004016 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004017 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004018 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4019 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004020 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004021 }
4022 }
4023 }
4024 super.onDeliverToNext(q);
4025 }
Jeff Brown678a1252013-04-09 17:46:25 -07004026 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004027
Jeff Brown678a1252013-04-09 17:46:25 -07004028 /**
4029 * Creates dpad events from unhandled trackball movements.
4030 */
4031 final class SyntheticTrackballHandler {
4032 private final TrackballAxis mX = new TrackballAxis();
4033 private final TrackballAxis mY = new TrackballAxis();
4034 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004035
Jeff Brown678a1252013-04-09 17:46:25 -07004036 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004037 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004038 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004039 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004040 // It has been too long since the last movement,
4041 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004042 mX.reset(0);
4043 mY.reset(0);
4044 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004045 }
4046
4047 final int action = event.getAction();
4048 final int metaState = event.getMetaState();
4049 switch (action) {
4050 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004051 mX.reset(2);
4052 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004053 enqueueInputEvent(new KeyEvent(curTime, curTime,
4054 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4055 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4056 InputDevice.SOURCE_KEYBOARD));
4057 break;
4058 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004059 mX.reset(2);
4060 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004061 enqueueInputEvent(new KeyEvent(curTime, curTime,
4062 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4063 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4064 InputDevice.SOURCE_KEYBOARD));
4065 break;
4066 }
4067
Jeff Brown678a1252013-04-09 17:46:25 -07004068 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4069 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004070 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004071 + " / Y=" + mY.position + " step="
4072 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004073 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004074 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4075 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004076
4077 // Generate DPAD events based on the trackball movement.
4078 // We pick the axis that has moved the most as the direction of
4079 // the DPAD. When we generate DPAD events for one axis, then the
4080 // other axis is reset -- we don't want to perform DPAD jumps due
4081 // to slight movements in the trackball when making major movements
4082 // along the other axis.
4083 int keycode = 0;
4084 int movement = 0;
4085 float accel = 1;
4086 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004087 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004088 if (movement != 0) {
4089 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4090 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004091 accel = mX.acceleration;
4092 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004093 }
4094 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004095 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004096 if (movement != 0) {
4097 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4098 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004099 accel = mY.acceleration;
4100 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004101 }
4102 }
4103
4104 if (keycode != 0) {
4105 if (movement < 0) movement = -movement;
4106 int accelMovement = (int)(movement * accel);
4107 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4108 + " accelMovement=" + accelMovement
4109 + " accel=" + accel);
4110 if (accelMovement > movement) {
4111 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4112 + keycode);
4113 movement--;
4114 int repeatCount = accelMovement - movement;
4115 enqueueInputEvent(new KeyEvent(curTime, curTime,
4116 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4117 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4118 InputDevice.SOURCE_KEYBOARD));
4119 }
4120 while (movement > 0) {
4121 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4122 + keycode);
4123 movement--;
4124 curTime = SystemClock.uptimeMillis();
4125 enqueueInputEvent(new KeyEvent(curTime, curTime,
4126 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4127 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4128 InputDevice.SOURCE_KEYBOARD));
4129 enqueueInputEvent(new KeyEvent(curTime, curTime,
4130 KeyEvent.ACTION_UP, keycode, 0, metaState,
4131 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4132 InputDevice.SOURCE_KEYBOARD));
4133 }
Jeff Brown678a1252013-04-09 17:46:25 -07004134 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004135 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004136 }
4137
Jeff Brown678a1252013-04-09 17:46:25 -07004138 public void cancel(MotionEvent event) {
4139 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004140
Jeff Brownf9e989d2013-04-04 23:04:03 -07004141 // If we reach this, we consumed a trackball event.
4142 // Because we will not translate the trackball event into a key event,
4143 // touch mode will not exit, so we exit touch mode here.
4144 if (mView != null && mAdded) {
4145 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004146 }
4147 }
Jeff Brown678a1252013-04-09 17:46:25 -07004148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149
Jeff Brown678a1252013-04-09 17:46:25 -07004150 /**
4151 * Maintains state information for a single trackball axis, generating
4152 * discrete (DPAD) movements based on raw trackball motion.
4153 */
4154 static final class TrackballAxis {
4155 /**
4156 * The maximum amount of acceleration we will apply.
4157 */
4158 static final float MAX_ACCELERATION = 20;
4159
4160 /**
4161 * The maximum amount of time (in milliseconds) between events in order
4162 * for us to consider the user to be doing fast trackball movements,
4163 * and thus apply an acceleration.
4164 */
4165 static final long FAST_MOVE_TIME = 150;
4166
4167 /**
4168 * Scaling factor to the time (in milliseconds) between events to how
4169 * much to multiple/divide the current acceleration. When movement
4170 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4171 * FAST_MOVE_TIME it divides it.
4172 */
4173 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4174
4175 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4176 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4177 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4178
4179 float position;
4180 float acceleration = 1;
4181 long lastMoveTime = 0;
4182 int step;
4183 int dir;
4184 int nonAccelMovement;
4185
4186 void reset(int _step) {
4187 position = 0;
4188 acceleration = 1;
4189 lastMoveTime = 0;
4190 step = _step;
4191 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004192 }
4193
Jeff Brown678a1252013-04-09 17:46:25 -07004194 /**
4195 * Add trackball movement into the state. If the direction of movement
4196 * has been reversed, the state is reset before adding the
4197 * movement (so that you don't have to compensate for any previously
4198 * collected movement before see the result of the movement in the
4199 * new direction).
4200 *
4201 * @return Returns the absolute value of the amount of movement
4202 * collected so far.
4203 */
4204 float collect(float off, long time, String axis) {
4205 long normTime;
4206 if (off > 0) {
4207 normTime = (long)(off * FAST_MOVE_TIME);
4208 if (dir < 0) {
4209 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4210 position = 0;
4211 step = 0;
4212 acceleration = 1;
4213 lastMoveTime = 0;
4214 }
4215 dir = 1;
4216 } else if (off < 0) {
4217 normTime = (long)((-off) * FAST_MOVE_TIME);
4218 if (dir > 0) {
4219 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4220 position = 0;
4221 step = 0;
4222 acceleration = 1;
4223 lastMoveTime = 0;
4224 }
4225 dir = -1;
4226 } else {
4227 normTime = 0;
4228 }
4229
4230 // The number of milliseconds between each movement that is
4231 // considered "normal" and will not result in any acceleration
4232 // or deceleration, scaled by the offset we have here.
4233 if (normTime > 0) {
4234 long delta = time - lastMoveTime;
4235 lastMoveTime = time;
4236 float acc = acceleration;
4237 if (delta < normTime) {
4238 // The user is scrolling rapidly, so increase acceleration.
4239 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4240 if (scale > 1) acc *= scale;
4241 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4242 + off + " normTime=" + normTime + " delta=" + delta
4243 + " scale=" + scale + " acc=" + acc);
4244 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4245 } else {
4246 // The user is scrolling slowly, so decrease acceleration.
4247 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4248 if (scale > 1) acc /= scale;
4249 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4250 + off + " normTime=" + normTime + " delta=" + delta
4251 + " scale=" + scale + " acc=" + acc);
4252 acceleration = acc > 1 ? acc : 1;
4253 }
4254 }
4255 position += off;
4256 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004257 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004258
Jeff Brown678a1252013-04-09 17:46:25 -07004259 /**
4260 * Generate the number of discrete movement events appropriate for
4261 * the currently collected trackball movement.
4262 *
4263 * @return Returns the number of discrete movements, either positive
4264 * or negative, or 0 if there is not enough trackball movement yet
4265 * for a discrete movement.
4266 */
4267 int generate() {
4268 int movement = 0;
4269 nonAccelMovement = 0;
4270 do {
4271 final int dir = position >= 0 ? 1 : -1;
4272 switch (step) {
4273 // If we are going to execute the first step, then we want
4274 // to do this as soon as possible instead of waiting for
4275 // a full movement, in order to make things look responsive.
4276 case 0:
4277 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4278 return movement;
4279 }
4280 movement += dir;
4281 nonAccelMovement += dir;
4282 step = 1;
4283 break;
4284 // If we have generated the first movement, then we need
4285 // to wait for the second complete trackball motion before
4286 // generating the second discrete movement.
4287 case 1:
4288 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4289 return movement;
4290 }
4291 movement += dir;
4292 nonAccelMovement += dir;
4293 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4294 step = 2;
4295 break;
4296 // After the first two, we generate discrete movements
4297 // consistently with the trackball, applying an acceleration
4298 // if the trackball is moving quickly. This is a simple
4299 // acceleration on top of what we already compute based
4300 // on how quickly the wheel is being turned, to apply
4301 // a longer increasing acceleration to continuous movement
4302 // in one direction.
4303 default:
4304 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4305 return movement;
4306 }
4307 movement += dir;
4308 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4309 float acc = acceleration;
4310 acc *= 1.1f;
4311 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4312 break;
4313 }
4314 } while (true);
4315 }
4316 }
4317
4318 /**
4319 * Creates dpad events from unhandled joystick movements.
4320 */
4321 final class SyntheticJoystickHandler extends Handler {
4322 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4323 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4324
4325 private int mLastXDirection;
4326 private int mLastYDirection;
4327 private int mLastXKeyCode;
4328 private int mLastYKeyCode;
4329
4330 public SyntheticJoystickHandler() {
4331 super(true);
4332 }
4333
4334 @Override
4335 public void handleMessage(Message msg) {
4336 switch (msg.what) {
4337 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4338 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4339 KeyEvent oldEvent = (KeyEvent)msg.obj;
4340 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4341 SystemClock.uptimeMillis(),
4342 oldEvent.getRepeatCount() + 1);
4343 if (mAttachInfo.mHasWindowFocus) {
4344 enqueueInputEvent(e);
4345 Message m = obtainMessage(msg.what, e);
4346 m.setAsynchronous(true);
4347 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4348 }
4349 } break;
4350 }
4351 }
4352
4353 public void process(MotionEvent event) {
4354 update(event, true);
4355 }
4356
4357 public void cancel(MotionEvent event) {
4358 update(event, false);
4359 }
4360
4361 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004362 final long time = event.getEventTime();
4363 final int metaState = event.getMetaState();
4364 final int deviceId = event.getDeviceId();
4365 final int source = event.getSource();
4366
4367 int xDirection = joystickAxisValueToDirection(
4368 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4369 if (xDirection == 0) {
4370 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004371 }
4372
Jeff Brownf9e989d2013-04-04 23:04:03 -07004373 int yDirection = joystickAxisValueToDirection(
4374 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4375 if (yDirection == 0) {
4376 yDirection = joystickAxisValueToDirection(event.getY());
4377 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004378
Jeff Brown678a1252013-04-09 17:46:25 -07004379 if (xDirection != mLastXDirection) {
4380 if (mLastXKeyCode != 0) {
4381 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004382 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004383 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004384 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004385 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004386 }
4387
Jeff Brown678a1252013-04-09 17:46:25 -07004388 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004389
4390 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004391 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004392 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4393 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004394 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004395 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4396 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004397 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004398 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004399 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004400 }
4401 }
4402
Jeff Brown678a1252013-04-09 17:46:25 -07004403 if (yDirection != mLastYDirection) {
4404 if (mLastYKeyCode != 0) {
4405 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004406 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004407 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004408 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004409 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004410 }
4411
Jeff Brown678a1252013-04-09 17:46:25 -07004412 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004413
4414 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004415 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004416 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4417 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004418 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004419 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4420 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004421 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004422 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004423 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004424 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004425 }
4426 }
4427
Jeff Brownf9e989d2013-04-04 23:04:03 -07004428 private int joystickAxisValueToDirection(float value) {
4429 if (value >= 0.5f) {
4430 return 1;
4431 } else if (value <= -0.5f) {
4432 return -1;
4433 } else {
4434 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004435 }
4436 }
Jeff Brown678a1252013-04-09 17:46:25 -07004437 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004438
Jeff Brown678a1252013-04-09 17:46:25 -07004439 /**
4440 * Creates dpad events from unhandled touch navigation movements.
4441 */
4442 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004443 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4444 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004445
Jeff Brown4dac9012013-04-10 01:03:19 -07004446 // Assumed nominal width and height in millimeters of a touch navigation pad,
4447 // if no resolution information is available from the input system.
4448 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4449 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004450
Jeff Brown4dac9012013-04-10 01:03:19 -07004451 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004452
Jeff Brown4dac9012013-04-10 01:03:19 -07004453 // The nominal distance traveled to move by one unit.
4454 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4455
4456 // Minimum and maximum fling velocity in ticks per second.
4457 // The minimum velocity should be set such that we perform enough ticks per
4458 // second that the fling appears to be fluid. For example, if we set the minimum
4459 // to 2 ticks per second, then there may be up to half a second delay between the next
4460 // to last and last ticks which is noticeably discrete and jerky. This value should
4461 // probably not be set to anything less than about 4.
4462 // If fling accuracy is a problem then consider tuning the tick distance instead.
4463 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4464 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4465
4466 // Fling velocity decay factor applied after each new key is emitted.
4467 // This parameter controls the deceleration and overall duration of the fling.
4468 // The fling stops automatically when its velocity drops below the minimum
4469 // fling velocity defined above.
4470 private static final float FLING_TICK_DECAY = 0.8f;
4471
4472 /* The input device that we are tracking. */
4473
4474 private int mCurrentDeviceId = -1;
4475 private int mCurrentSource;
4476 private boolean mCurrentDeviceSupported;
4477
4478 /* Configuration for the current input device. */
4479
Jeff Brown4dac9012013-04-10 01:03:19 -07004480 // The scaled tick distance. A movement of this amount should generally translate
4481 // into a single dpad event in a given direction.
4482 private float mConfigTickDistance;
4483
4484 // The minimum and maximum scaled fling velocity.
4485 private float mConfigMinFlingVelocity;
4486 private float mConfigMaxFlingVelocity;
4487
4488 /* Tracking state. */
4489
4490 // The velocity tracker for detecting flings.
4491 private VelocityTracker mVelocityTracker;
4492
4493 // The active pointer id, or -1 if none.
4494 private int mActivePointerId = -1;
4495
4496 // Time and location where tracking started.
4497 private long mStartTime;
4498 private float mStartX;
4499 private float mStartY;
4500
4501 // Most recently observed position.
4502 private float mLastX;
4503 private float mLastY;
4504
4505 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004506 private float mAccumulatedX;
4507 private float mAccumulatedY;
4508
Jeff Brown4dac9012013-04-10 01:03:19 -07004509 // Set to true if any movement was delivered to the app.
4510 // Implies that tap slop was exceeded.
4511 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004512
Jeff Brown4dac9012013-04-10 01:03:19 -07004513 // The most recently sent key down event.
4514 // The keycode remains set until the direction changes or a fling ends
4515 // so that repeated key events may be generated as required.
4516 private long mPendingKeyDownTime;
4517 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4518 private int mPendingKeyRepeatCount;
4519 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004520
Jeff Brown4dac9012013-04-10 01:03:19 -07004521 // The current fling velocity while a fling is in progress.
4522 private boolean mFlinging;
4523 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004524
Michael Wright25b0c302013-07-10 12:54:06 -07004525 // The last time a confirm key was pressed on the touch nav device
4526 private long mLastConfirmKeyTime = Long.MAX_VALUE;
4527
Jeff Brown678a1252013-04-09 17:46:25 -07004528 public SyntheticTouchNavigationHandler() {
4529 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004530 }
4531
4532 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004533 // Update the current device information.
4534 final long time = event.getEventTime();
4535 final int deviceId = event.getDeviceId();
4536 final int source = event.getSource();
4537 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4538 finishKeys(time);
4539 finishTracking(time);
4540 mCurrentDeviceId = deviceId;
4541 mCurrentSource = source;
4542 mCurrentDeviceSupported = false;
4543 InputDevice device = event.getDevice();
4544 if (device != null) {
4545 // In order to support an input device, we must know certain
4546 // characteristics about it, such as its size and resolution.
4547 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4548 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4549 if (xRange != null && yRange != null) {
4550 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004551
Jeff Brown4dac9012013-04-10 01:03:19 -07004552 // Infer the resolution if it not actually known.
4553 float xRes = xRange.getResolution();
4554 if (xRes <= 0) {
4555 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4556 }
4557 float yRes = yRange.getResolution();
4558 if (yRes <= 0) {
4559 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4560 }
4561 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004562
Jeff Brown4dac9012013-04-10 01:03:19 -07004563 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07004564 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4565 mConfigMinFlingVelocity =
4566 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4567 mConfigMaxFlingVelocity =
4568 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4569
4570 if (LOCAL_DEBUG) {
4571 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4572 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07004573 + ", mConfigTickDistance=" + mConfigTickDistance
4574 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4575 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4576 }
4577 }
4578 }
Jeff Brown678a1252013-04-09 17:46:25 -07004579 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004580 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004581 return;
4582 }
4583
Jeff Brown4dac9012013-04-10 01:03:19 -07004584 // Handle the event.
4585 final int action = event.getActionMasked();
4586 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004587 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004588 boolean caughtFling = mFlinging;
4589 finishKeys(time);
4590 finishTracking(time);
4591 mActivePointerId = event.getPointerId(0);
4592 mVelocityTracker = VelocityTracker.obtain();
4593 mVelocityTracker.addMovement(event);
4594 mStartTime = time;
4595 mStartX = event.getX();
4596 mStartY = event.getY();
4597 mLastX = mStartX;
4598 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004599 mAccumulatedX = 0;
4600 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004601
4602 // If we caught a fling, then pretend that the tap slop has already
4603 // been exceeded to suppress taps whose only purpose is to stop the fling.
4604 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004605 break;
4606 }
4607
Jeff Brown4dac9012013-04-10 01:03:19 -07004608 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004609 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004610 if (mActivePointerId < 0) {
4611 break;
4612 }
4613 final int index = event.findPointerIndex(mActivePointerId);
4614 if (index < 0) {
4615 finishKeys(time);
4616 finishTracking(time);
4617 break;
4618 }
Jeff Brown678a1252013-04-09 17:46:25 -07004619
Jeff Brown4dac9012013-04-10 01:03:19 -07004620 mVelocityTracker.addMovement(event);
4621 final float x = event.getX(index);
4622 final float y = event.getY(index);
4623 mAccumulatedX += x - mLastX;
4624 mAccumulatedY += y - mLastY;
4625 mLastX = x;
4626 mLastY = y;
4627
4628 // Consume any accumulated movement so far.
4629 final int metaState = event.getMetaState();
4630 consumeAccumulatedMovement(time, metaState);
4631
4632 // Detect taps and flings.
4633 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07004634 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004635 // It might be a fling.
4636 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4637 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4638 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4639 if (!startFling(time, vx, vy)) {
4640 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004641 }
4642 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004643 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004644 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004645 break;
4646 }
4647
4648 case MotionEvent.ACTION_CANCEL: {
4649 finishKeys(time);
4650 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004651 break;
4652 }
4653 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004654 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004655
4656 public void cancel(MotionEvent event) {
4657 if (mCurrentDeviceId == event.getDeviceId()
4658 && mCurrentSource == event.getSource()) {
4659 final long time = event.getEventTime();
4660 finishKeys(time);
4661 finishTracking(time);
4662 }
4663 }
4664
4665 private void finishKeys(long time) {
4666 cancelFling();
4667 sendKeyUp(time);
4668 }
4669
4670 private void finishTracking(long time) {
4671 if (mActivePointerId >= 0) {
4672 mActivePointerId = -1;
4673 mVelocityTracker.recycle();
4674 mVelocityTracker = null;
4675 }
4676 }
4677
4678 private void consumeAccumulatedMovement(long time, int metaState) {
4679 final float absX = Math.abs(mAccumulatedX);
4680 final float absY = Math.abs(mAccumulatedY);
4681 if (absX >= absY) {
4682 if (absX >= mConfigTickDistance) {
4683 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4684 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4685 mAccumulatedY = 0;
4686 mConsumedMovement = true;
4687 }
4688 } else {
4689 if (absY >= mConfigTickDistance) {
4690 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4691 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4692 mAccumulatedX = 0;
4693 mConsumedMovement = true;
4694 }
4695 }
4696 }
4697
4698 private float consumeAccumulatedMovement(long time, int metaState,
4699 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4700 while (accumulator <= -mConfigTickDistance) {
4701 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4702 accumulator += mConfigTickDistance;
4703 }
4704 while (accumulator >= mConfigTickDistance) {
4705 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4706 accumulator -= mConfigTickDistance;
4707 }
4708 return accumulator;
4709 }
4710
4711 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4712 if (mPendingKeyCode != keyCode) {
4713 sendKeyUp(time);
4714 mPendingKeyDownTime = time;
4715 mPendingKeyCode = keyCode;
4716 mPendingKeyRepeatCount = 0;
4717 } else {
4718 mPendingKeyRepeatCount += 1;
4719 }
4720 mPendingKeyMetaState = metaState;
4721
4722 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4723 // but it doesn't quite make sense when simulating the events in this way.
4724 if (LOCAL_DEBUG) {
4725 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4726 + ", repeatCount=" + mPendingKeyRepeatCount
4727 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4728 }
4729 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4730 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4731 mPendingKeyMetaState, mCurrentDeviceId,
4732 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4733 }
4734
4735 private void sendKeyUp(long time) {
4736 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4737 if (LOCAL_DEBUG) {
4738 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4739 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4740 }
4741 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4742 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4743 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4744 mCurrentSource));
4745 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4746 }
4747 }
4748
4749 private boolean startFling(long time, float vx, float vy) {
4750 if (LOCAL_DEBUG) {
4751 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4752 + ", min=" + mConfigMinFlingVelocity);
4753 }
4754
4755 // Flings must be oriented in the same direction as the preceding movements.
4756 switch (mPendingKeyCode) {
4757 case KeyEvent.KEYCODE_DPAD_LEFT:
4758 if (-vx >= mConfigMinFlingVelocity
4759 && Math.abs(vy) < mConfigMinFlingVelocity) {
4760 mFlingVelocity = -vx;
4761 break;
4762 }
4763 return false;
4764
4765 case KeyEvent.KEYCODE_DPAD_RIGHT:
4766 if (vx >= mConfigMinFlingVelocity
4767 && Math.abs(vy) < mConfigMinFlingVelocity) {
4768 mFlingVelocity = vx;
4769 break;
4770 }
4771 return false;
4772
4773 case KeyEvent.KEYCODE_DPAD_UP:
4774 if (-vy >= mConfigMinFlingVelocity
4775 && Math.abs(vx) < mConfigMinFlingVelocity) {
4776 mFlingVelocity = -vy;
4777 break;
4778 }
4779 return false;
4780
4781 case KeyEvent.KEYCODE_DPAD_DOWN:
4782 if (vy >= mConfigMinFlingVelocity
4783 && Math.abs(vx) < mConfigMinFlingVelocity) {
4784 mFlingVelocity = vy;
4785 break;
4786 }
4787 return false;
4788 }
4789
4790 // Post the first fling event.
4791 mFlinging = postFling(time);
4792 return mFlinging;
4793 }
4794
4795 private boolean postFling(long time) {
4796 // The idea here is to estimate the time when the pointer would have
4797 // traveled one tick distance unit given the current fling velocity.
4798 // This effect creates continuity of motion.
4799 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4800 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
4801 postAtTime(mFlingRunnable, time + delay);
4802 if (LOCAL_DEBUG) {
4803 Log.d(LOCAL_TAG, "Posted fling: velocity="
4804 + mFlingVelocity + ", delay=" + delay
4805 + ", keyCode=" + mPendingKeyCode);
4806 }
4807 return true;
4808 }
4809 return false;
4810 }
4811
4812 private void cancelFling() {
4813 if (mFlinging) {
4814 removeCallbacks(mFlingRunnable);
4815 mFlinging = false;
4816 }
4817 }
4818
4819 private final Runnable mFlingRunnable = new Runnable() {
4820 @Override
4821 public void run() {
4822 final long time = SystemClock.uptimeMillis();
4823 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
4824 mFlingVelocity *= FLING_TICK_DECAY;
4825 if (!postFling(time)) {
4826 mFlinging = false;
4827 finishKeys(time);
4828 }
4829 }
4830 };
Jeff Browncb1404e2011-01-15 18:14:15 -08004831 }
4832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004833 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004834 * Returns true if the key is used for keyboard navigation.
4835 * @param keyEvent The key event.
4836 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004837 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004838 private static boolean isNavigationKey(KeyEvent keyEvent) {
4839 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004840 case KeyEvent.KEYCODE_DPAD_LEFT:
4841 case KeyEvent.KEYCODE_DPAD_RIGHT:
4842 case KeyEvent.KEYCODE_DPAD_UP:
4843 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08004844 case KeyEvent.KEYCODE_DPAD_CENTER:
4845 case KeyEvent.KEYCODE_PAGE_UP:
4846 case KeyEvent.KEYCODE_PAGE_DOWN:
4847 case KeyEvent.KEYCODE_MOVE_HOME:
4848 case KeyEvent.KEYCODE_MOVE_END:
4849 case KeyEvent.KEYCODE_TAB:
4850 case KeyEvent.KEYCODE_SPACE:
4851 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004852 return true;
4853 }
4854 return false;
4855 }
4856
4857 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004858 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004859 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08004860 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004861 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004862 private static boolean isTypingKey(KeyEvent keyEvent) {
4863 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 }
4865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004866 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004867 * 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 -08004868 * @param event The key event.
4869 * @return Whether this key event should be consumed (meaning the act of
4870 * leaving touch mode alone is considered the event).
4871 */
4872 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004873 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004874 if (!mAttachInfo.mInTouchMode) {
4875 return false;
4876 }
4877
Jeff Brown4e6319b2010-12-13 10:36:51 -08004878 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
4879 final int action = event.getAction();
4880 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004881 return false;
4882 }
4883
Jeff Brown4e6319b2010-12-13 10:36:51 -08004884 // Don't leave touch mode if the IME told us not to.
4885 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
4886 return false;
4887 }
4888
4889 // If the key can be used for keyboard navigation then leave touch mode
4890 // and select a focused view if needed (in ensureTouchMode).
4891 // When a new focused view is selected, we consume the navigation key because
4892 // navigation doesn't make much sense unless a view already has focus so
4893 // the key's purpose is to set focus.
4894 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004895 return ensureTouchMode(false);
4896 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08004897
4898 // If the key can be used for typing then leave touch mode
4899 // and select a focused view if needed (in ensureTouchMode).
4900 // Always allow the view to process the typing key.
4901 if (isTypingKey(event)) {
4902 ensureTouchMode(false);
4903 return false;
4904 }
4905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004906 return false;
4907 }
4908
Christopher Tatea53146c2010-09-07 11:57:52 -07004909 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08004910 void setLocalDragState(Object obj) {
4911 mLocalDragState = obj;
4912 }
4913
Christopher Tatea53146c2010-09-07 11:57:52 -07004914 private void handleDragEvent(DragEvent event) {
4915 // From the root, only drag start/end/location are dispatched. entered/exited
4916 // are determined and dispatched by the viewgroup hierarchy, who then report
4917 // that back here for ultimate reporting back to the framework.
4918 if (mView != null && mAdded) {
4919 final int what = event.mAction;
4920
4921 if (what == DragEvent.ACTION_DRAG_EXITED) {
4922 // A direct EXITED event means that the window manager knows we've just crossed
4923 // a window boundary, so the current drag target within this one must have
4924 // just been exited. Send it the usual notifications and then we're done
4925 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07004926 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004927 } else {
4928 // Cache the drag description when the operation starts, then fill it in
4929 // on subsequent calls as a convenience
4930 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07004931 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07004932 mDragDescription = event.mClipDescription;
4933 } else {
4934 event.mClipDescription = mDragDescription;
4935 }
4936
4937 // For events with a [screen] location, translate into window coordinates
4938 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
4939 mDragPoint.set(event.mX, event.mY);
4940 if (mTranslator != null) {
4941 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
4942 }
4943
4944 if (mCurScrollY != 0) {
4945 mDragPoint.offset(0, mCurScrollY);
4946 }
4947
4948 event.mX = mDragPoint.x;
4949 event.mY = mDragPoint.y;
4950 }
4951
4952 // Remember who the current drag target is pre-dispatch
4953 final View prevDragView = mCurrentDragView;
4954
4955 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07004956 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004957
4958 // If we changed apparent drag target, tell the OS about it
4959 if (prevDragView != mCurrentDragView) {
4960 try {
4961 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07004962 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07004963 }
4964 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07004965 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07004966 }
4967 } catch (RemoteException e) {
4968 Slog.e(TAG, "Unable to note drag target change");
4969 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004970 }
Chris Tated4533f12010-10-19 15:15:08 -07004971
Christopher Tate407b4e92010-11-30 17:14:08 -08004972 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07004973 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08004974 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07004975 try {
4976 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07004977 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07004978 } catch (RemoteException e) {
4979 Log.e(TAG, "Unable to report drop result");
4980 }
4981 }
Christopher Tate407b4e92010-11-30 17:14:08 -08004982
4983 // When the drag operation ends, release any local state object
4984 // that may have been in use
4985 if (what == DragEvent.ACTION_DRAG_ENDED) {
4986 setLocalDragState(null);
4987 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004988 }
4989 }
4990 event.recycle();
4991 }
4992
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004993 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
4994 if (mSeq != args.seq) {
4995 // The sequence has changed, so we need to update our value and make
4996 // sure to do a traversal afterward so the window manager is given our
4997 // most recent data.
4998 mSeq = args.seq;
4999 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005000 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005001 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005002 if (mView == null) return;
5003 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005004 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005005 }
Dianne Hackborncf675782012-05-10 15:07:24 -07005006 if (mAttachInfo != null) {
5007 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5008 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5009 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5010 mView.dispatchSystemUiVisibilityChanged(visibility);
5011 }
5012 }
Joe Onorato664644d2011-01-23 17:53:23 -08005013 }
5014
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005015 public void handleDispatchDoneAnimating() {
5016 if (mWindowsAnimating) {
5017 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07005018 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005019 scheduleTraversals();
5020 }
5021 }
5022 }
5023
Christopher Tate2c095f32010-10-04 14:13:40 -07005024 public void getLastTouchPoint(Point outLocation) {
5025 outLocation.x = (int) mLastTouchPoint.x;
5026 outLocation.y = (int) mLastTouchPoint.y;
5027 }
5028
Chris Tate9d1ab882010-11-02 15:55:39 -07005029 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005030 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005031 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005032 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005033 }
5034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005035 private AudioManager getAudioManager() {
5036 if (mView == null) {
5037 throw new IllegalStateException("getAudioManager called when there is no mView");
5038 }
5039 if (mAudioManager == null) {
5040 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5041 }
5042 return mAudioManager;
5043 }
5044
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005045 public AccessibilityInteractionController getAccessibilityInteractionController() {
5046 if (mView == null) {
5047 throw new IllegalStateException("getAccessibilityInteractionController"
5048 + " called when there is no mView");
5049 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005050 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005051 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005052 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005053 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005054 }
5055
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005056 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5057 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005058
5059 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005060 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005061 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005062 restore = true;
5063 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005064 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005065 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005066 if (params != null) {
5067 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005068 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005069 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005070 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005071 if (params != null && mOrigWindowType != params.type) {
5072 // For compatibility with old apps, don't crash here.
5073 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
5074 Slog.w(TAG, "Window type can not be changed after "
5075 + "the window is added; ignoring change of " + mView);
5076 params.type = mOrigWindowType;
5077 }
5078 }
Jeff Brown98365d72012-08-19 20:30:52 -07005079 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005080 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005081 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5082 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005083 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005084 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005085 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005086 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005087 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005088 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005089 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005090
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005091 if (mTranslator != null) {
5092 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005093 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005094 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5095 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005096 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005097 return relayoutResult;
5098 }
Romain Guy8506ab42009-06-11 17:35:47 -07005099
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005100 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005101 * {@inheritDoc}
5102 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005103 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005104 public void playSoundEffect(int effectId) {
5105 checkThread();
5106
Dan Morrille4d9a012013-03-28 18:10:43 -07005107 if (mMediaDisabled) {
5108 return;
5109 }
5110
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005111 try {
5112 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005113
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005114 switch (effectId) {
5115 case SoundEffectConstants.CLICK:
5116 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5117 return;
5118 case SoundEffectConstants.NAVIGATION_DOWN:
5119 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5120 return;
5121 case SoundEffectConstants.NAVIGATION_LEFT:
5122 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5123 return;
5124 case SoundEffectConstants.NAVIGATION_RIGHT:
5125 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5126 return;
5127 case SoundEffectConstants.NAVIGATION_UP:
5128 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5129 return;
5130 default:
5131 throw new IllegalArgumentException("unknown effect id " + effectId +
5132 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5133 }
5134 } catch (IllegalStateException e) {
5135 // Exception thrown by getAudioManager() when mView is null
5136 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5137 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005138 }
5139 }
5140
5141 /**
5142 * {@inheritDoc}
5143 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005144 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005145 public boolean performHapticFeedback(int effectId, boolean always) {
5146 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005147 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005148 } catch (RemoteException e) {
5149 return false;
5150 }
5151 }
5152
5153 /**
5154 * {@inheritDoc}
5155 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005156 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005157 public View focusSearch(View focused, int direction) {
5158 checkThread();
5159 if (!(mView instanceof ViewGroup)) {
5160 return null;
5161 }
5162 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5163 }
5164
5165 public void debug() {
5166 mView.debug();
5167 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005168
Jeff Brown5182c782013-10-15 20:31:52 -07005169 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5170 String innerPrefix = prefix + " ";
5171 writer.print(prefix); writer.println("ViewRoot:");
5172 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5173 writer.print(" mRemoved="); writer.println(mRemoved);
5174 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5175 writer.println(mConsumeBatchedInputScheduled);
5176 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5177 writer.println(mPendingInputEventCount);
5178 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5179 writer.println(mProcessInputEventsScheduled);
5180 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5181 writer.print(mTraversalScheduled);
5182 if (mTraversalScheduled) {
5183 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5184 } else {
5185 writer.println();
5186 }
5187 mFirstInputStage.dump(innerPrefix, writer);
5188
5189 mChoreographer.dump(prefix, writer);
5190
5191 writer.print(prefix); writer.println("View Hierarchy:");
5192 dumpViewHierarchy(innerPrefix, writer, mView);
5193 }
5194
5195 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5196 writer.print(prefix);
5197 if (view == null) {
5198 writer.println("null");
5199 return;
5200 }
5201 writer.println(view.toString());
5202 if (!(view instanceof ViewGroup)) {
5203 return;
5204 }
5205 ViewGroup grp = (ViewGroup)view;
5206 final int N = grp.getChildCount();
5207 if (N <= 0) {
5208 return;
5209 }
5210 prefix = prefix + " ";
5211 for (int i=0; i<N; i++) {
5212 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5213 }
5214 }
5215
Romain Guy211370f2012-02-01 16:10:55 -08005216 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005217 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005218 if (mView != null) {
5219 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005220 }
5221 }
5222
Romain Guya998dff2012-03-23 18:58:36 -07005223 private static void getGfxInfo(View view, int[] info) {
Romain Guy65b345f2011-07-27 18:51:50 -07005224 DisplayList displayList = view.mDisplayList;
5225 info[0]++;
5226 if (displayList != null) {
5227 info[1] += displayList.getSize();
5228 }
5229
5230 if (view instanceof ViewGroup) {
5231 ViewGroup group = (ViewGroup) view;
5232
5233 int count = group.getChildCount();
5234 for (int i = 0; i < count; i++) {
5235 getGfxInfo(group.getChildAt(i), info);
5236 }
5237 }
5238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005239
Craig Mautner8f303ad2013-06-14 11:32:22 -07005240 /**
5241 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5242 * @return True, request has been queued. False, request has been completed.
5243 */
5244 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005245 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5246 // done by dispatchDetachedFromWindow will cause havoc on return.
5247 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005248 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005249 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005250 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005251
5252 if (!mIsDrawing) {
5253 destroyHardwareRenderer();
5254 } else {
5255 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5256 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5257 }
5258 mHandler.sendEmptyMessage(MSG_DIE);
5259 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005260 }
5261
5262 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005263 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005264 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005266 if (mRemoved) {
5267 return;
5268 }
5269 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005270 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005271 dispatchDetachedFromWindow();
5272 }
5273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005274 if (mAdded && !mFirst) {
Romain Guyfbb93fa2012-12-03 18:50:35 -08005275 invalidateDisplayLists();
Romain Guy29d89972010-09-22 16:10:57 -07005276 destroyHardwareRenderer();
5277
Romain Guyedbca122012-04-04 18:25:53 -07005278 if (mView != null) {
5279 int viewVisibility = mView.getVisibility();
5280 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5281 if (mWindowAttributesChanged || viewVisibilityChanged) {
5282 // If layout params have been changed, first give them
5283 // to the window manager to make sure it has the correct
5284 // animation info.
5285 try {
5286 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005287 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5288 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005289 }
5290 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005292 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005293
Romain Guyedbca122012-04-04 18:25:53 -07005294 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005296 }
Romain Guyedbca122012-04-04 18:25:53 -07005297
5298 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005299 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005300 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005301 }
5302
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005303 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005304 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5305 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005306 }
5307
Dianne Hackborna53de062012-05-08 18:53:51 -07005308 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005309 mHandler.post(new Runnable() {
5310 @Override
5311 public void run() {
5312 // Profiling
5313 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5314 profileRendering(mAttachInfo.mHasWindowFocus);
5315
Dan Morrille4d9a012013-03-28 18:10:43 -07005316 // Media (used by sound effects)
5317 mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
5318
Romain Guy5bb3c732012-11-29 17:52:58 -08005319 // Hardware rendering
5320 if (mAttachInfo.mHardwareRenderer != null) {
5321 if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mHolder.getSurface())) {
5322 invalidate();
5323 }
5324 }
5325
5326 // Layout debugging
5327 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5328 if (layout != mAttachInfo.mDebugLayout) {
5329 mAttachInfo.mDebugLayout = layout;
5330 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5331 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5332 }
5333 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005334 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005335 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005336 }
5337
Romain Guy29d89972010-09-22 16:10:57 -07005338 private void destroyHardwareRenderer() {
Romain Guya998dff2012-03-23 18:58:36 -07005339 AttachInfo attachInfo = mAttachInfo;
5340 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
5341
5342 if (hardwareRenderer != null) {
5343 if (mView != null) {
5344 hardwareRenderer.destroyHardwareResources(mView);
5345 }
5346 hardwareRenderer.destroy(true);
5347 hardwareRenderer.setRequested(false);
5348
5349 attachInfo.mHardwareRenderer = null;
5350 attachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005351 }
5352 }
5353
Jeff Browna175a5b2012-02-15 19:18:31 -08005354 public void dispatchFinishInputConnection(InputConnection connection) {
5355 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5356 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005357 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005358
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005359 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08005360 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005361 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5362 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005363 + " visibleInsets=" + visibleInsets.toShortString()
5364 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005365 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005366 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005367 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005368 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005369 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005370 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005371 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005372 SomeArgs args = SomeArgs.obtain();
5373 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5374 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5375 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5376 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5377 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005378 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005379 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005380 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005381 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005382
Craig Mautner5702d4d2012-06-30 14:10:16 -07005383 public void dispatchMoved(int newX, int newY) {
5384 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5385 if (mTranslator != null) {
5386 PointF point = new PointF(newX, newY);
5387 mTranslator.translatePointInScreenToAppWindow(point);
5388 newX = (int) (point.x + 0.5);
5389 newY = (int) (point.y + 0.5);
5390 }
5391 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5392 mHandler.sendMessage(msg);
5393 }
5394
Jeff Brown4952dfd2011-11-30 19:23:22 -08005395 /**
5396 * Represents a pending input event that is waiting in a queue.
5397 *
5398 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005399 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005400 * one input event to the application at a time and waits for the application
5401 * to finish handling it before delivering the next one.
5402 *
5403 * However, because the application or IME can synthesize and inject multiple
5404 * key events at a time without going through the input dispatcher, we end up
5405 * needing a queue on the application's side.
5406 */
5407 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005408 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5409 public static final int FLAG_DEFERRED = 1 << 1;
5410 public static final int FLAG_FINISHED = 1 << 2;
5411 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5412 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005413
5414 public QueuedInputEvent mNext;
5415
5416 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005417 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005418 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005419
5420 public boolean shouldSkipIme() {
5421 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5422 return true;
5423 }
5424 return mEvent instanceof MotionEvent
5425 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5426 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005427 }
5428
5429 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005430 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005431 QueuedInputEvent q = mQueuedInputEventPool;
5432 if (q != null) {
5433 mQueuedInputEventPoolSize -= 1;
5434 mQueuedInputEventPool = q.mNext;
5435 q.mNext = null;
5436 } else {
5437 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005438 }
5439
Jeff Brown4952dfd2011-11-30 19:23:22 -08005440 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005441 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005442 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005443 return q;
5444 }
5445
5446 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5447 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005448 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005449
5450 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5451 mQueuedInputEventPoolSize += 1;
5452 q.mNext = mQueuedInputEventPool;
5453 mQueuedInputEventPool = q;
5454 }
5455 }
5456
Jeff Brownf9261d22012-02-03 13:49:15 -08005457 void enqueueInputEvent(InputEvent event) {
5458 enqueueInputEvent(event, null, 0, false);
5459 }
5460
Jeff Brown4952dfd2011-11-30 19:23:22 -08005461 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005462 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005463 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005464
Jeff Brown4952dfd2011-11-30 19:23:22 -08005465 // Always enqueue the input event in order, regardless of its time stamp.
5466 // We do this because the application or the IME may inject key events
5467 // in response to touch events and we want to ensure that the injected keys
5468 // are processed in the order they were received and we cannot trust that
5469 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005470 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005471 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005472 mPendingInputEventHead = q;
5473 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005474 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005475 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005476 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005477 }
Michael Wright95ae9422013-03-14 10:58:50 -07005478 mPendingInputEventCount += 1;
5479 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5480 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005481
Jeff Brownf9261d22012-02-03 13:49:15 -08005482 if (processImmediately) {
5483 doProcessInputEvents();
5484 } else {
5485 scheduleProcessInputEvents();
5486 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005487 }
5488
5489 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005490 if (!mProcessInputEventsScheduled) {
5491 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005492 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5493 msg.setAsynchronous(true);
5494 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005495 }
5496 }
5497
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005498 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005499 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005500 while (mPendingInputEventHead != null) {
5501 QueuedInputEvent q = mPendingInputEventHead;
5502 mPendingInputEventHead = q.mNext;
5503 if (mPendingInputEventHead == null) {
5504 mPendingInputEventTail = null;
5505 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005506 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005507
Michael Wright95ae9422013-03-14 10:58:50 -07005508 mPendingInputEventCount -= 1;
5509 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5510 mPendingInputEventCount);
5511
Jeff Brownf9e989d2013-04-04 23:04:03 -07005512 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005513 }
5514
5515 // We are done processing all input events that we can process right now
5516 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005517 if (mProcessInputEventsScheduled) {
5518 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005519 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005520 }
5521 }
5522
Jeff Brownf9e989d2013-04-04 23:04:03 -07005523 private void deliverInputEvent(QueuedInputEvent q) {
5524 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
5525 try {
5526 if (mInputEventConsistencyVerifier != null) {
5527 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5528 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005529
Jeff Brownf9e989d2013-04-04 23:04:03 -07005530 InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5531 if (stage != null) {
5532 stage.deliver(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005533 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005534 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005535 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005536 } finally {
5537 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Michael Wrightbf020962013-03-28 17:27:50 -07005538 }
Michael Wrightbf020962013-03-28 17:27:50 -07005539 }
5540
Jeff Brownf9e989d2013-04-04 23:04:03 -07005541 private void finishInputEvent(QueuedInputEvent q) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005542 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005543 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005544 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005545 } else {
5546 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005547 }
5548
5549 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005550 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005551
Jeff Brownf9e989d2013-04-04 23:04:03 -07005552 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005553 if (event instanceof KeyEvent) {
5554 final KeyEvent keyEvent = (KeyEvent)event;
5555 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5556 } else {
5557 final MotionEvent motionEvent = (MotionEvent)event;
5558 final int action = motionEvent.getAction();
5559 return action == MotionEvent.ACTION_UP
5560 || action == MotionEvent.ACTION_CANCEL
5561 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005562 }
5563 }
5564
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005565 void scheduleConsumeBatchedInput() {
5566 if (!mConsumeBatchedInputScheduled) {
5567 mConsumeBatchedInputScheduled = true;
5568 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5569 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005570 }
5571 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005572
5573 void unscheduleConsumeBatchedInput() {
5574 if (mConsumeBatchedInputScheduled) {
5575 mConsumeBatchedInputScheduled = false;
5576 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5577 mConsumedBatchedInputRunnable, null);
5578 }
5579 }
5580
Jeff Brown771526c2012-04-27 15:13:25 -07005581 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005582 if (mConsumeBatchedInputScheduled) {
5583 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005584 if (mInputEventReceiver != null) {
Michael Wright62ce65d2013-10-25 14:50:36 -07005585 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)) {
5586 // If we consumed a batch here, we want to go ahead and schedule the
5587 // consumption of batched input events on the next frame. Otherwise, we would
5588 // wait until we have more input events pending and might get starved by other
5589 // things occurring in the process.
5590 scheduleConsumeBatchedInput();
5591 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005592 }
Jeff Brown330314c2012-04-27 02:20:22 -07005593 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005594 }
5595 }
5596
5597 final class TraversalRunnable implements Runnable {
5598 @Override
5599 public void run() {
5600 doTraversal();
5601 }
5602 }
5603 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005604
Jeff Brown32cbc38552011-12-01 14:01:49 -08005605 final class WindowInputEventReceiver extends InputEventReceiver {
5606 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5607 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005608 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005609
5610 @Override
5611 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005612 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005613 }
Jeff Brown072ec962012-02-07 14:46:57 -08005614
5615 @Override
5616 public void onBatchedInputEventPending() {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005617 scheduleConsumeBatchedInput();
5618 }
5619
5620 @Override
5621 public void dispose() {
5622 unscheduleConsumeBatchedInput();
5623 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005624 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005625 }
5626 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005627
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005628 final class ConsumeBatchedInputRunnable implements Runnable {
5629 @Override
5630 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005631 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005632 }
5633 }
5634 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5635 new ConsumeBatchedInputRunnable();
5636 boolean mConsumeBatchedInputScheduled;
5637
Jeff Brown6cb7b462012-03-05 13:21:17 -08005638 final class InvalidateOnAnimationRunnable implements Runnable {
5639 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005640 private final ArrayList<View> mViews = new ArrayList<View>();
5641 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08005642 new ArrayList<AttachInfo.InvalidateInfo>();
5643 private View[] mTempViews;
5644 private AttachInfo.InvalidateInfo[] mTempViewRects;
5645
5646 public void addView(View view) {
5647 synchronized (this) {
5648 mViews.add(view);
5649 postIfNeededLocked();
5650 }
5651 }
5652
5653 public void addViewRect(AttachInfo.InvalidateInfo info) {
5654 synchronized (this) {
5655 mViewRects.add(info);
5656 postIfNeededLocked();
5657 }
5658 }
5659
5660 public void removeView(View view) {
5661 synchronized (this) {
5662 mViews.remove(view);
5663
5664 for (int i = mViewRects.size(); i-- > 0; ) {
5665 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5666 if (info.target == view) {
5667 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005668 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005669 }
5670 }
5671
5672 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005673 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005674 mPosted = false;
5675 }
5676 }
5677 }
5678
5679 @Override
5680 public void run() {
5681 final int viewCount;
5682 final int viewRectCount;
5683 synchronized (this) {
5684 mPosted = false;
5685
5686 viewCount = mViews.size();
5687 if (viewCount != 0) {
5688 mTempViews = mViews.toArray(mTempViews != null
5689 ? mTempViews : new View[viewCount]);
5690 mViews.clear();
5691 }
5692
5693 viewRectCount = mViewRects.size();
5694 if (viewRectCount != 0) {
5695 mTempViewRects = mViewRects.toArray(mTempViewRects != null
5696 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
5697 mViewRects.clear();
5698 }
5699 }
5700
5701 for (int i = 0; i < viewCount; i++) {
5702 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07005703 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08005704 }
5705
5706 for (int i = 0; i < viewRectCount; i++) {
5707 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
5708 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005709 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005710 }
5711 }
5712
5713 private void postIfNeededLocked() {
5714 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005715 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005716 mPosted = true;
5717 }
5718 }
5719 }
5720 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
5721 new InvalidateOnAnimationRunnable();
5722
Jeff Browna175a5b2012-02-15 19:18:31 -08005723 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
5724 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
5725 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5726 }
5727
Jeff Browna175a5b2012-02-15 19:18:31 -08005728 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
5729 long delayMilliseconds) {
5730 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
5731 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5732 }
5733
Jeff Brown6cb7b462012-03-05 13:21:17 -08005734 public void dispatchInvalidateOnAnimation(View view) {
5735 mInvalidateOnAnimationRunnable.addView(view);
5736 }
5737
5738 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
5739 mInvalidateOnAnimationRunnable.addViewRect(info);
5740 }
5741
Romain Guy2a0f2282012-05-08 14:43:12 -07005742 public void enqueueDisplayList(DisplayList displayList) {
Romain Guy51e4d4d2012-03-15 18:30:47 -07005743 mDisplayLists.add(displayList);
Romain Guy2a0f2282012-05-08 14:43:12 -07005744 }
5745
Jeff Brown6cb7b462012-03-05 13:21:17 -08005746 public void cancelInvalidate(View view) {
5747 mHandler.removeMessages(MSG_INVALIDATE, view);
5748 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
5749 // them to the pool
5750 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
5751 mInvalidateOnAnimationRunnable.removeView(view);
5752 }
5753
keunyoung30f420f2013-08-02 14:23:10 -07005754 public void dispatchInputEvent(InputEvent event) {
5755 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005756 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005757 mHandler.sendMessage(msg);
5758 }
5759
5760 public void dispatchKeyFromIme(KeyEvent event) {
5761 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005762 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005763 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08005764 }
5765
John Reckd6b10982012-04-19 18:01:35 -07005766 public void dispatchUnhandledKey(KeyEvent event) {
5767 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
5768 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5769 final int keyCode = event.getKeyCode();
5770 final int metaState = event.getMetaState();
5771
Jeff Brownfd23e3e2012-05-09 13:34:28 -07005772 // Check for fallback actions specified by the key character map.
5773 KeyCharacterMap.FallbackAction fallbackAction =
5774 kcm.getFallbackAction(keyCode, metaState);
5775 if (fallbackAction != null) {
5776 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5777 KeyEvent fallbackEvent = KeyEvent.obtain(
5778 event.getDownTime(), event.getEventTime(),
5779 event.getAction(), fallbackAction.keyCode,
5780 event.getRepeatCount(), fallbackAction.metaState,
5781 event.getDeviceId(), event.getScanCode(),
5782 flags, event.getSource(), null);
5783 fallbackAction.recycle();
5784
keunyoung30f420f2013-08-02 14:23:10 -07005785 dispatchInputEvent(fallbackEvent);
John Reckd6b10982012-04-19 18:01:35 -07005786 }
5787 }
5788 }
5789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005790 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005791 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005792 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005793 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005794 }
5795
Romain Guybb9908b2012-03-08 11:14:07 -08005796 public void dispatchScreenStateChange(boolean on) {
5797 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
Romain Guy7e4e5612012-03-05 14:37:29 -08005798 msg.arg1 = on ? 1 : 0;
5799 mHandler.sendMessage(msg);
5800 }
5801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005802 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08005803 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
5804 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005805 }
5806
5807 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
5808 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005809 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005810 msg.arg1 = hasFocus ? 1 : 0;
5811 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005812 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005813 }
5814
Dianne Hackbornffa42482009-09-23 22:20:11 -07005815 public void dispatchCloseSystemDialogs(String reason) {
5816 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005817 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07005818 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08005819 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07005820 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005821
5822 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07005823 final int what;
5824 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005825 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
5826 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07005827 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08005828 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07005829 }
Jeff Browna175a5b2012-02-15 19:18:31 -08005830 Message msg = mHandler.obtainMessage(what, event);
5831 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07005832 }
5833
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005834 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
5835 int localValue, int localChanges) {
5836 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
5837 args.seq = seq;
5838 args.globalVisibility = globalVisibility;
5839 args.localValue = localValue;
5840 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08005841 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
5842 }
5843
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005844 public void dispatchDoneAnimating() {
5845 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
5846 }
5847
Jeff Browna175a5b2012-02-15 19:18:31 -08005848 public void dispatchCheckFocus() {
5849 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
5850 // This will result in a call to checkFocus() below.
5851 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
5852 }
Joe Onorato664644d2011-01-23 17:53:23 -08005853 }
5854
svetoslavganov75986cf2009-05-14 22:28:01 -07005855 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005856 * Post a callback to send a
5857 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07005858 * This event is send at most once every
5859 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005860 */
Alan Viverette77e9a282013-09-12 17:16:09 -07005861 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005862 if (mSendWindowContentChangedAccessibilityEvent == null) {
5863 mSendWindowContentChangedAccessibilityEvent =
5864 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005865 }
Alan Viverette77e9a282013-09-12 17:16:09 -07005866 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005867 }
5868
5869 /**
5870 * Remove a posted callback to send a
5871 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
5872 */
5873 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005874 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005875 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005876 }
5877 }
5878
Igor Murashkina86ab6402013-08-30 12:58:36 -07005879 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005880 public boolean showContextMenuForChild(View originalView) {
5881 return false;
5882 }
5883
Igor Murashkina86ab6402013-08-30 12:58:36 -07005884 @Override
Adam Powell6e346362010-07-23 10:18:23 -07005885 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
5886 return null;
5887 }
5888
Igor Murashkina86ab6402013-08-30 12:58:36 -07005889 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005890 public void createContextMenu(ContextMenu menu) {
5891 }
5892
Igor Murashkina86ab6402013-08-30 12:58:36 -07005893 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005894 public void childDrawableStateChanged(View child) {
5895 }
5896
Igor Murashkina86ab6402013-08-30 12:58:36 -07005897 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005898 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
5899 if (mView == null) {
5900 return false;
5901 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005902 // Intercept accessibility focus events fired by virtual nodes to keep
5903 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005904 final int eventType = event.getEventType();
5905 switch (eventType) {
5906 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005907 final long sourceNodeId = event.getSourceNodeId();
5908 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5909 sourceNodeId);
5910 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5911 if (source != null) {
5912 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5913 if (provider != null) {
5914 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
5915 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
5916 setAccessibilityFocus(source, node);
5917 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005918 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005919 } break;
5920 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005921 final long sourceNodeId = event.getSourceNodeId();
5922 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5923 sourceNodeId);
5924 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5925 if (source != null) {
5926 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5927 if (provider != null) {
5928 setAccessibilityFocus(null, null);
5929 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005930 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005931 } break;
5932 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005933 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005934 return true;
5935 }
5936
Svetoslav Ganov42138042012-03-20 11:51:39 -07005937 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07005938 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
5939 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07005940 }
5941
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08005942 @Override
5943 public boolean canResolveLayoutDirection() {
5944 return true;
5945 }
5946
5947 @Override
5948 public boolean isLayoutDirectionResolved() {
5949 return true;
5950 }
5951
5952 @Override
5953 public int getLayoutDirection() {
5954 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
5955 }
5956
5957 @Override
5958 public boolean canResolveTextDirection() {
5959 return true;
5960 }
5961
5962 @Override
5963 public boolean isTextDirectionResolved() {
5964 return true;
5965 }
5966
5967 @Override
5968 public int getTextDirection() {
5969 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
5970 }
5971
5972 @Override
5973 public boolean canResolveTextAlignment() {
5974 return true;
5975 }
5976
5977 @Override
5978 public boolean isTextAlignmentResolved() {
5979 return true;
5980 }
5981
5982 @Override
5983 public int getTextAlignment() {
5984 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
5985 }
5986
Svetoslav Ganov42138042012-03-20 11:51:39 -07005987 private View getCommonPredecessor(View first, View second) {
5988 if (mAttachInfo != null) {
5989 if (mTempHashSet == null) {
5990 mTempHashSet = new HashSet<View>();
5991 }
5992 HashSet<View> seen = mTempHashSet;
5993 seen.clear();
5994 View firstCurrent = first;
5995 while (firstCurrent != null) {
5996 seen.add(firstCurrent);
5997 ViewParent firstCurrentParent = firstCurrent.mParent;
5998 if (firstCurrentParent instanceof View) {
5999 firstCurrent = (View) firstCurrentParent;
6000 } else {
6001 firstCurrent = null;
6002 }
6003 }
6004 View secondCurrent = second;
6005 while (secondCurrent != null) {
6006 if (seen.contains(secondCurrent)) {
6007 seen.clear();
6008 return secondCurrent;
6009 }
6010 ViewParent secondCurrentParent = secondCurrent.mParent;
6011 if (secondCurrentParent instanceof View) {
6012 secondCurrent = (View) secondCurrentParent;
6013 } else {
6014 secondCurrent = null;
6015 }
6016 }
6017 seen.clear();
6018 }
6019 return null;
6020 }
6021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006022 void checkThread() {
6023 if (mThread != Thread.currentThread()) {
6024 throw new CalledFromWrongThreadException(
6025 "Only the original thread that created a view hierarchy can touch its views.");
6026 }
6027 }
6028
Igor Murashkina86ab6402013-08-30 12:58:36 -07006029 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006030 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006031 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006032 }
6033
Igor Murashkina86ab6402013-08-30 12:58:36 -07006034 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006035 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
6036 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
6037 if (rectangle != null) {
6038 mTempRect.set(rectangle);
6039 mTempRect.offset(0, -mCurScrollY);
6040 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6041 try {
6042 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
6043 } catch (RemoteException re) {
6044 /* ignore */
6045 }
6046 }
6047 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006048 }
Romain Guy8506ab42009-06-11 17:35:47 -07006049
Igor Murashkina86ab6402013-08-30 12:58:36 -07006050 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006051 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6052 // Do nothing.
6053 }
6054
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006055 void changeCanvasOpacity(boolean opaque) {
6056 // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
6057 Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
6058 }
6059
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006060 class TakenSurfaceHolder extends BaseSurfaceHolder {
6061 @Override
6062 public boolean onAllowLockCanvas() {
6063 return mDrawingAllowed;
6064 }
6065
6066 @Override
6067 public void onRelayoutContainer() {
6068 // Not currently interesting -- from changing between fixed and layout size.
6069 }
6070
Igor Murashkina86ab6402013-08-30 12:58:36 -07006071 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006072 public void setFormat(int format) {
6073 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6074 }
6075
Igor Murashkina86ab6402013-08-30 12:58:36 -07006076 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006077 public void setType(int type) {
6078 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6079 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006080
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006081 @Override
6082 public void onUpdateSurface() {
6083 // We take care of format and type changes on our own.
6084 throw new IllegalStateException("Shouldn't be here");
6085 }
6086
Igor Murashkina86ab6402013-08-30 12:58:36 -07006087 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006088 public boolean isCreating() {
6089 return mIsCreating;
6090 }
6091
6092 @Override
6093 public void setFixedSize(int width, int height) {
6094 throw new UnsupportedOperationException(
6095 "Currently only support sizing from layout");
6096 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006097
6098 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006099 public void setKeepScreenOn(boolean screenOn) {
6100 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6101 }
6102 }
Romain Guy8506ab42009-06-11 17:35:47 -07006103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006104 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006105 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006106 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006107
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006108 W(ViewRootImpl viewAncestor) {
6109 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006110 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006111 }
6112
Igor Murashkina86ab6402013-08-30 12:58:36 -07006113 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006114 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -07006115 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006116 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006117 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006118 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07006119 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006120 }
6121 }
6122
Craig Mautner5702d4d2012-06-30 14:10:16 -07006123 @Override
6124 public void moved(int newX, int newY) {
6125 final ViewRootImpl viewAncestor = mViewAncestor.get();
6126 if (viewAncestor != null) {
6127 viewAncestor.dispatchMoved(newX, newY);
6128 }
6129 }
6130
Igor Murashkina86ab6402013-08-30 12:58:36 -07006131 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006132 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006133 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006134 if (viewAncestor != null) {
6135 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006136 }
6137 }
6138
Igor Murashkina86ab6402013-08-30 12:58:36 -07006139 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08006140 public void dispatchScreenState(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -08006141 final ViewRootImpl viewAncestor = mViewAncestor.get();
6142 if (viewAncestor != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08006143 viewAncestor.dispatchScreenStateChange(on);
Romain Guy7e4e5612012-03-05 14:37:29 -08006144 }
6145 }
Romain Guybb9908b2012-03-08 11:14:07 -08006146
Igor Murashkina86ab6402013-08-30 12:58:36 -07006147 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006148 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006149 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006150 if (viewAncestor != null) {
6151 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006152 }
6153 }
6154
Igor Murashkina86ab6402013-08-30 12:58:36 -07006155 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006156 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006157 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006158 if (viewAncestor != null) {
6159 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006160 }
6161 }
6162
6163 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006164 try {
6165 return ActivityManagerNative.getDefault().checkPermission(
6166 permission, Binder.getCallingPid(), Binder.getCallingUid());
6167 } catch (RemoteException e) {
6168 return PackageManager.PERMISSION_DENIED;
6169 }
6170 }
6171
Igor Murashkina86ab6402013-08-30 12:58:36 -07006172 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006173 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006174 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006175 if (viewAncestor != null) {
6176 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006177 if (view != null) {
6178 if (checkCallingPermission(Manifest.permission.DUMP) !=
6179 PackageManager.PERMISSION_GRANTED) {
6180 throw new SecurityException("Insufficient permissions to invoke"
6181 + " executeCommand() from pid=" + Binder.getCallingPid()
6182 + ", uid=" + Binder.getCallingUid());
6183 }
6184
6185 OutputStream clientStream = null;
6186 try {
6187 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6188 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6189 } catch (IOException e) {
6190 e.printStackTrace();
6191 } finally {
6192 if (clientStream != null) {
6193 try {
6194 clientStream.close();
6195 } catch (IOException e) {
6196 e.printStackTrace();
6197 }
6198 }
6199 }
6200 }
6201 }
6202 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006203
6204 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006205 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006206 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006207 if (viewAncestor != null) {
6208 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006209 }
6210 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006211
6212 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006213 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6214 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006215 if (sync) {
6216 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006217 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006218 } catch (RemoteException e) {
6219 }
6220 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006221 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006222
Igor Murashkina86ab6402013-08-30 12:58:36 -07006223 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07006224 public void dispatchWallpaperCommand(String action, int x, int y,
6225 int z, Bundle extras, boolean sync) {
6226 if (sync) {
6227 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006228 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006229 } catch (RemoteException e) {
6230 }
6231 }
6232 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006233
6234 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006235 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07006236 public void dispatchDragEvent(DragEvent event) {
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.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006240 }
6241 }
Joe Onorato664644d2011-01-23 17:53:23 -08006242
Igor Murashkina86ab6402013-08-30 12:58:36 -07006243 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006244 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6245 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006246 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006247 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006248 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6249 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006250 }
6251 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006252
Igor Murashkina86ab6402013-08-30 12:58:36 -07006253 @Override
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006254 public void doneAnimating() {
6255 final ViewRootImpl viewAncestor = mViewAncestor.get();
6256 if (viewAncestor != null) {
6257 viewAncestor.dispatchDoneAnimating();
6258 }
6259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006260 }
6261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006262 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6263 public CalledFromWrongThreadException(String msg) {
6264 super(msg);
6265 }
6266 }
6267
Igor Murashkina86ab6402013-08-30 12:58:36 -07006268 private final SurfaceHolder mHolder = new SurfaceHolder() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006269 // we only need a SurfaceHolder for opengl. it would be nice
6270 // to implement everything else though, especially the callback
6271 // support (opengl doesn't make use of it right now, but eventually
6272 // will).
Igor Murashkina86ab6402013-08-30 12:58:36 -07006273 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006274 public Surface getSurface() {
6275 return mSurface;
6276 }
6277
Igor Murashkina86ab6402013-08-30 12:58:36 -07006278 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006279 public boolean isCreating() {
6280 return false;
6281 }
6282
Igor Murashkina86ab6402013-08-30 12:58:36 -07006283 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006284 public void addCallback(Callback callback) {
6285 }
6286
Igor Murashkina86ab6402013-08-30 12:58:36 -07006287 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006288 public void removeCallback(Callback callback) {
6289 }
6290
Igor Murashkina86ab6402013-08-30 12:58:36 -07006291 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006292 public void setFixedSize(int width, int height) {
6293 }
6294
Igor Murashkina86ab6402013-08-30 12:58:36 -07006295 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006296 public void setSizeFromLayout() {
6297 }
6298
Igor Murashkina86ab6402013-08-30 12:58:36 -07006299 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006300 public void setFormat(int format) {
6301 }
6302
Igor Murashkina86ab6402013-08-30 12:58:36 -07006303 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006304 public void setType(int type) {
6305 }
6306
Igor Murashkina86ab6402013-08-30 12:58:36 -07006307 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006308 public void setKeepScreenOn(boolean screenOn) {
6309 }
6310
Igor Murashkina86ab6402013-08-30 12:58:36 -07006311 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006312 public Canvas lockCanvas() {
6313 return null;
6314 }
6315
Igor Murashkina86ab6402013-08-30 12:58:36 -07006316 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006317 public Canvas lockCanvas(Rect dirty) {
6318 return null;
6319 }
6320
Igor Murashkina86ab6402013-08-30 12:58:36 -07006321 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006322 public void unlockCanvasAndPost(Canvas canvas) {
6323 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006324 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006325 public Rect getSurfaceFrame() {
6326 return null;
6327 }
6328 };
6329
6330 static RunQueue getRunQueue() {
6331 RunQueue rq = sRunQueues.get();
6332 if (rq != null) {
6333 return rq;
6334 }
6335 rq = new RunQueue();
6336 sRunQueues.set(rq);
6337 return rq;
6338 }
Romain Guy8506ab42009-06-11 17:35:47 -07006339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006340 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08006341 * The run queue is used to enqueue pending work from Views when no Handler is
6342 * attached. The work is executed during the next call to performTraversals on
6343 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006344 * @hide
6345 */
6346 static final class RunQueue {
6347 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
6348
6349 void post(Runnable action) {
6350 postDelayed(action, 0);
6351 }
6352
6353 void postDelayed(Runnable action, long delayMillis) {
6354 HandlerAction handlerAction = new HandlerAction();
6355 handlerAction.action = action;
6356 handlerAction.delay = delayMillis;
6357
6358 synchronized (mActions) {
6359 mActions.add(handlerAction);
6360 }
6361 }
6362
6363 void removeCallbacks(Runnable action) {
6364 final HandlerAction handlerAction = new HandlerAction();
6365 handlerAction.action = action;
6366
6367 synchronized (mActions) {
6368 final ArrayList<HandlerAction> actions = mActions;
6369
6370 while (actions.remove(handlerAction)) {
6371 // Keep going
6372 }
6373 }
6374 }
6375
6376 void executeActions(Handler handler) {
6377 synchronized (mActions) {
6378 final ArrayList<HandlerAction> actions = mActions;
6379 final int count = actions.size();
6380
6381 for (int i = 0; i < count; i++) {
6382 final HandlerAction handlerAction = actions.get(i);
6383 handler.postDelayed(handlerAction.action, handlerAction.delay);
6384 }
6385
Romain Guy15df6702009-08-17 20:17:30 -07006386 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006387 }
6388 }
6389
6390 private static class HandlerAction {
6391 Runnable action;
6392 long delay;
6393
6394 @Override
6395 public boolean equals(Object o) {
6396 if (this == o) return true;
6397 if (o == null || getClass() != o.getClass()) return false;
6398
6399 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006400 return !(action != null ? !action.equals(that.action) : that.action != null);
6401
6402 }
6403
6404 @Override
6405 public int hashCode() {
6406 int result = action != null ? action.hashCode() : 0;
6407 result = 31 * result + (int) (delay ^ (delay >>> 32));
6408 return result;
6409 }
6410 }
6411 }
6412
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006413 /**
6414 * Class for managing the accessibility interaction connection
6415 * based on the global accessibility state.
6416 */
6417 final class AccessibilityInteractionConnectionManager
6418 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07006419 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006420 public void onAccessibilityStateChanged(boolean enabled) {
6421 if (enabled) {
6422 ensureConnection();
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006423 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6424 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6425 View focusedView = mView.findFocus();
6426 if (focusedView != null && focusedView != mView) {
6427 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6428 }
6429 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006430 } else {
6431 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006432 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006433 }
6434 }
6435
6436 public void ensureConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006437 if (mAttachInfo != null) {
6438 final boolean registered =
6439 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
6440 if (!registered) {
6441 mAttachInfo.mAccessibilityWindowId =
6442 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6443 new AccessibilityInteractionConnection(ViewRootImpl.this));
6444 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006445 }
6446 }
6447
6448 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006449 final boolean registered =
6450 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006451 if (registered) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006452 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006453 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6454 }
6455 }
6456 }
6457
6458 /**
6459 * This class is an interface this ViewAncestor provides to the
6460 * AccessibilityManagerService to the latter can interact with
6461 * the view hierarchy in this ViewAncestor.
6462 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006463 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006464 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006465 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006466
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006467 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6468 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006469 }
6470
Svetoslav Ganov42138042012-03-20 11:51:39 -07006471 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006472 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006473 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006474 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006475 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6476 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006477 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006478 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006479 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6480 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006481 } else {
6482 // We cannot make the call and notify the caller so it does not wait.
6483 try {
6484 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6485 } catch (RemoteException re) {
6486 /* best effort - ignore */
6487 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006488 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006489 }
6490
Svetoslav Ganov42138042012-03-20 11:51:39 -07006491 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006492 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006493 Bundle arguments, int interactionId,
6494 IAccessibilityInteractionConnectionCallback callback, int flags,
6495 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006496 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6497 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006498 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006499 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006500 interactionId, callback, flags, interogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006501 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006502 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006503 try {
6504 callback.setPerformAccessibilityActionResult(false, interactionId);
6505 } catch (RemoteException re) {
6506 /* best effort - ignore */
6507 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006508 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006509 }
6510
Svetoslav Ganov42138042012-03-20 11:51:39 -07006511 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006512 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
6513 String viewId, int interactionId,
6514 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006515 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006516 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6517 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006518 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006519 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
6520 viewId, interactionId, callback, flags, interrogatingPid,
6521 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006522 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006523 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006524 try {
6525 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6526 } catch (RemoteException re) {
6527 /* best effort - ignore */
6528 }
6529 }
6530 }
6531
Svetoslav Ganov42138042012-03-20 11:51:39 -07006532 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006533 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006534 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006535 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006536 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6537 if (viewRootImpl != null && viewRootImpl.mView != null) {
6538 viewRootImpl.getAccessibilityInteractionController()
6539 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006540 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6541 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006542 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006543 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006544 try {
6545 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6546 } catch (RemoteException re) {
6547 /* best effort - ignore */
6548 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006549 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006550 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006551
Svetoslav Ganov42138042012-03-20 11:51:39 -07006552 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006553 public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
Svetoslav Ganov86783472012-06-06 21:12:20 -07006554 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006555 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006556 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6557 if (viewRootImpl != null && viewRootImpl.mView != null) {
6558 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006559 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006560 flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006561 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006562 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006563 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006564 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006565 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006566 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006567 }
6568 }
6569 }
6570
Svetoslav Ganov42138042012-03-20 11:51:39 -07006571 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006572 public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006573 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006574 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006575 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6576 if (viewRootImpl != null && viewRootImpl.mView != null) {
6577 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006578 .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006579 callback, flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006580 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006581 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006582 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006583 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006584 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006585 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006586 }
6587 }
6588 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006589 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006590
Svetoslav Ganova0156172011-06-26 17:55:44 -07006591 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07006592 private int mChangeTypes = 0;
6593
Svetoslav Ganov42138042012-03-20 11:51:39 -07006594 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07006595 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006596
Igor Murashkina86ab6402013-08-30 12:58:36 -07006597 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006598 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07006599 // The accessibility may be turned off while we were waiting so check again.
6600 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6601 mLastEventTimeMillis = SystemClock.uptimeMillis();
6602 AccessibilityEvent event = AccessibilityEvent.obtain();
6603 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07006604 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07006605 mSource.sendAccessibilityEventUnchecked(event);
6606 } else {
6607 mLastEventTimeMillis = 0;
6608 }
6609 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07006610 mSource.resetSubtreeAccessibilityStateChanged();
6611 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07006612 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07006613 }
6614
Alan Viverette77e9a282013-09-12 17:16:09 -07006615 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006616 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006617 // If there is no common predecessor, then mSource points to
6618 // a removed view, hence in this case always prefer the source.
6619 View predecessor = getCommonPredecessor(mSource, source);
6620 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006621 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006622 return;
6623 }
6624 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006625 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006626 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
6627 final long minEventIntevalMillis =
6628 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
6629 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006630 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07006631 run();
6632 } else {
6633 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006634 }
6635 }
6636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637}