blob: bc0d7e3c806be0a0f040e67017d0afc8b41419c6 [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
Michael Wright4567e402013-08-16 15:08:35 -0700235 boolean mFlipControllerFallbackKeys;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700238 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700241 // Surface can never be reassigned or cleared (use Surface.clear()).
242 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
244 boolean mAdded;
245 boolean mAddedTouchMode;
246
Craig Mautner48d0d182013-06-11 07:53:06 -0700247 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // These are accessed by multiple threads.
250 final Rect mWinFrame; // frame given by window manager.
251
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800252 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 final Rect mPendingVisibleInsets = new Rect();
254 final Rect mPendingContentInsets = new Rect();
255 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
256 = new ViewTreeObserver.InternalInsetsInfo();
257
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700258 final Rect mFitSystemWindowsInsets = new Rect();
259
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700260 final Configuration mLastConfiguration = new Configuration();
261 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 boolean mScrollMayChange;
264 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800265 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 int mScrollY;
267 int mCurScrollY;
268 Scroller mScroller;
Romain Guy7d70fbf2011-05-24 17:40:25 -0700269 HardwareLayer mResizeBuffer;
270 long mResizeBufferStartTime;
271 int mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800272 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700273 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700274
Romain Guy8506ab42009-06-11 17:35:47 -0700275 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276
Christopher Tatea53146c2010-09-07 11:57:52 -0700277 /* Drag/drop */
278 ClipDescription mDragDescription;
279 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800280 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700281 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700282 final PointF mLastTouchPoint = new PointF();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700283
284 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800285 private Choreographer.FrameCallback mRenderProfiler;
286 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700287
Dan Morrille4d9a012013-03-28 18:10:43 -0700288 private boolean mMediaDisabled;
289
Chet Haase2f2022a2011-10-11 06:41:59 -0700290 // Variables to track frames per second, enabled via DEBUG_FPS flag
291 private long mFpsStartTime = -1;
292 private long mFpsPrevTime = -1;
293 private int mFpsNumFrames;
294
Romain Guyfbb93fa2012-12-03 18:50:35 -0800295 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 /**
298 * see {@link #playSoundEffect(int)}
299 */
300 AudioManager mAudioManager;
301
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700302 final AccessibilityManager mAccessibilityManager;
303
Gilles Debunne5ac84422011-10-19 09:35:58 -0700304 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700305
306 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
307
Svetoslav Ganova0156172011-06-26 17:55:44 -0700308 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700309
Svetoslav Ganov42138042012-03-20 11:51:39 -0700310 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800311
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700312 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700313 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700314
Chet Haase97140572012-09-13 14:56:47 -0700315 private boolean mInLayout = false;
316 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
317 boolean mHandlingLayoutInLayoutRequest = false;
318
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700319 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700320
Craig Mautner8f303ad2013-06-14 11:32:22 -0700321 /** Set to true once doDie() has been called. */
322 private boolean mRemoved;
323
Jeff Brown21bc5c92011-02-28 18:27:14 -0800324 /**
325 * Consistency verifier for debugging purposes.
326 */
327 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
328 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
329 new InputEventConsistencyVerifier(this, 0) : null;
330
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700331 static final class SystemUiVisibilityInfo {
332 int seq;
333 int globalVisibility;
334 int localValue;
335 int localChanges;
336 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700337
Jeff Brown98365d72012-08-19 20:30:52 -0700338 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700339 mContext = context;
340 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700341 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800342 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700343
Craig Mautner48d0d182013-06-11 07:53:06 -0700344 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 mThread = Thread.currentThread();
347 mLocation = new WindowLeaked(null);
348 mLocation.fillInStackTrace();
349 mWidth = -1;
350 mHeight = -1;
351 mDirty = new Rect();
352 mTempRect = new Rect();
353 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700355 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700356 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 mViewVisibility = View.GONE;
358 mTransparentRegion = new Region();
359 mPreviousTransparentRegion = new Region();
360 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700362 mAccessibilityManager = AccessibilityManager.getInstance(context);
363 mAccessibilityInteractionConnectionManager =
364 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800365 mAccessibilityManager.addAccessibilityStateChangeListener(
366 mAccessibilityInteractionConnectionManager);
Jeff Brown98365d72012-08-19 20:30:52 -0700367 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700369 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700370 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700371 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800372 mChoreographer = Choreographer.getInstance();
Michael Wright4567e402013-08-16 15:08:35 -0700373 mFlipControllerFallbackKeys =
374 context.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
Romain Guy7e4e5612012-03-05 14:37:29 -0800375
376 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
377 mAttachInfo.mScreenOn = powerManager.isScreenOn();
Dianne Hackborna53de062012-05-08 18:53:51 -0700378 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800381 public static void addFirstDrawHandler(Runnable callback) {
382 synchronized (sFirstDrawHandlers) {
383 if (!sFirstDrawComplete) {
384 sFirstDrawHandlers.add(callback);
385 }
386 }
387 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700388
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800389 public static void addConfigCallback(ComponentCallbacks callback) {
390 synchronized (sConfigCallbacks) {
391 sConfigCallbacks.add(callback);
392 }
393 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 // FIXME for perf testing only
396 private boolean mProfile = false;
397
398 /**
399 * Call this to profile the next traversal call.
400 * FIXME for perf testing only. Remove eventually
401 */
402 public void profile() {
403 mProfile = true;
404 }
405
406 /**
407 * Indicates whether we are in touch mode. Calling this method triggers an IPC
408 * call and should be avoided whenever possible.
409 *
410 * @return True, if the device is in touch mode, false otherwise.
411 *
412 * @hide
413 */
414 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700415 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
416 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700418 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 } catch (RemoteException e) {
420 }
421 }
422 return false;
423 }
424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 /**
426 * We have one child
427 */
Romain Guye4d01122010-06-16 18:44:05 -0700428 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 synchronized (this) {
430 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700431 mView = view;
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700432 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700433 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700434 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800435 if (mWindowAttributes.packageName == null) {
436 mWindowAttributes.packageName = mBasePackageName;
437 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700438 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700439 // Keep track of the actual window flags supplied by the client.
440 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700441
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700442 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700443
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700444 if (view instanceof RootViewSurfaceTaker) {
445 mSurfaceHolderCallback =
446 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
447 if (mSurfaceHolderCallback != null) {
448 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700449 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700450 }
451 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800452
Craig Mautner48d0d182013-06-11 07:53:06 -0700453 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700454 mTranslator = compatibilityInfo.getTranslator();
Craig Mautner48d0d182013-06-11 07:53:06 -0700455 mDisplayAdjustments.setActivityToken(attrs.token);
Romain Guy856d4e12011-10-14 15:47:55 -0700456
Romain Guy1aec9a22011-01-05 09:37:12 -0800457 // If the application owns the surface, don't enable hardware acceleration
458 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700459 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800460 }
461
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700462 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700463 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700464 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700465 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700466 attrs.backup();
467 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700468 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700469 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
470
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700471 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700472 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700473 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700474 }
475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 mSoftInputMode = attrs.softInputMode;
477 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700478 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700480 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700481 mAttachInfo.mApplicationScale =
482 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 if (panelParentView != null) {
484 mAttachInfo.mPanelParentWindowToken
485 = panelParentView.getApplicationWindowToken();
486 }
487 mAdded = true;
488 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 // Schedule the first layout -before- adding to the window
491 // manager, to make sure we do the relayout before receiving
492 // any other events from the system.
493 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700494 if ((mWindowAttributes.inputFeatures
495 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
496 mInputChannel = new InputChannel();
497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700499 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700500 mAttachInfo.mRecomputeGlobalAttributes = true;
501 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700502 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
503 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700504 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 } catch (RemoteException e) {
506 mAdded = false;
507 mView = null;
508 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700509 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700510 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700512 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700514 } finally {
515 if (restore) {
516 attrs.restore();
517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700519
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700520 if (mTranslator != null) {
521 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700522 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800523 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 mPendingContentInsets.set(mAttachInfo.mContentInsets);
525 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800526 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700527 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 mAttachInfo.mRootView = null;
529 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700530 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700532 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700534 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
535 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
536 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 "Unable to add window -- token " + attrs.token
538 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700539 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
540 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 "Unable to add window -- token " + attrs.token
542 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700543 case WindowManagerGlobal.ADD_APP_EXITING:
544 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 "Unable to add window -- app for token " + attrs.token
546 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700547 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
548 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 "Unable to add window -- window " + mWindow
550 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700551 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 // Silently ignore -- we would have just removed it
553 // right away, anyway.
554 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700555 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
556 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 "Unable to add window " + mWindow +
558 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700559 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
560 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 "Unable to add window " + mWindow +
562 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700563 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
564 throw new WindowManager.InvalidDisplayException(
565 "Unable to add window " + mWindow +
566 " -- the specified display can not be found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568 throw new RuntimeException(
569 "Unable to add window -- unknown error code " + res);
570 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700571
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700572 if (view instanceof RootViewSurfaceTaker) {
573 mInputQueueCallback =
574 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
575 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700576 if (mInputChannel != null) {
577 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700578 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700579 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700580 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700581 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
582 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700583 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700586 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
587 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700588
589 if (mAccessibilityManager.isEnabled()) {
590 mAccessibilityInteractionConnectionManager.ensureConnection();
591 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700592
593 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
594 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
595 }
Michael Wright95ae9422013-03-14 10:58:50 -0700596
Jeff Brownf9e989d2013-04-04 23:04:03 -0700597 // Set up the input pipeline.
598 CharSequence counterSuffix = attrs.getTitle();
Michael Wright88d7f792013-08-27 15:45:42 -0700599 InputStage syntheticInputStage = new SyntheticInputStage();
600 InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700601 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
602 "aq:native-post-ime:" + counterSuffix);
603 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
604 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
605 "aq:ime:" + counterSuffix);
606 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
607 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
608 "aq:native-pre-ime:" + counterSuffix);
609
610 mFirstInputStage = nativePreImeStage;
611 mFirstPostImeInputStage = earlyPostImeStage;
612 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
614 }
615 }
616
keunyoung30f420f2013-08-02 14:23:10 -0700617 /** Whether the window is in local focus mode or not */
618 private boolean isInLocalFocusMode() {
619 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
620 }
621
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800622 void destroyHardwareResources() {
Romain Guy46bfc482013-08-16 18:38:29 -0700623 invalidateDisplayLists();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800624 if (mAttachInfo.mHardwareRenderer != null) {
625 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
626 mAttachInfo.mHardwareRenderer.destroy(false);
627 }
628 }
629
Romain Guy65b345f2011-07-27 18:51:50 -0700630 void destroyHardwareLayers() {
631 if (mThread != Thread.currentThread()) {
632 if (mAttachInfo.mHardwareRenderer != null &&
633 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700634 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700635 }
636 } else {
Romain Guy46bfc482013-08-16 18:38:29 -0700637 invalidateDisplayLists();
Romain Guy65b345f2011-07-27 18:51:50 -0700638 if (mAttachInfo.mHardwareRenderer != null &&
639 mAttachInfo.mHardwareRenderer.isEnabled()) {
640 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
641 }
642 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700643 }
644
Romain Guy11cb6422012-09-21 00:39:43 -0700645 void pushHardwareLayerUpdate(HardwareLayer layer) {
646 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
647 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
648 }
649 }
650
Romain Guy40543602013-06-12 15:31:28 -0700651 void flushHardwareLayerUpdates() {
652 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
653 mAttachInfo.mHardwareRenderer.validate()) {
654 mAttachInfo.mHardwareRenderer.flushLayerUpdates();
655 }
656 }
657
658 void dispatchFlushHardwareLayerUpdates() {
659 mHandler.removeMessages(MSG_FLUSH_LAYER_UPDATES);
660 mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
661 }
662
Chris Craik41ee4652012-05-31 15:05:57 -0700663 public boolean attachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700664 //noinspection SimplifiableIfStatement
Romain Guyba6be8a2012-04-23 18:22:09 -0700665 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Chris Craik41ee4652012-05-31 15:05:57 -0700666 return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700667 }
Chris Craik41ee4652012-05-31 15:05:57 -0700668 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -0700669 }
670
671 public void detachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700672 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700673 mAttachInfo.mHardwareRenderer.detachFunctor(functor);
674 }
675 }
676
Romain Guy3b748a42013-04-17 18:54:38 -0700677 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800678 mAttachInfo.mHardwareAccelerated = false;
679 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800680
Romain Guy856d4e12011-10-14 15:47:55 -0700681 // Don't enable hardware acceleration when the application is in compatibility mode
682 if (mTranslator != null) return;
683
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800684 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700685 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800686 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
687
Romain Guy566c3312011-03-21 18:21:28 -0700688 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700689 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700690 return;
691 }
692
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700693 // Persistent processes (including the system) should not do
694 // accelerated rendering on low-end devices. In that case,
695 // sRendererDisabled will be set. In addition, the system process
696 // itself should never do accelerated rendering. In that case, both
697 // sRendererDisabled and sSystemRendererDisabled are set. When
698 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
699 // can be used by code on the system process to escape that and enable
700 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800701
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700702 final boolean fakeHwAccelerated = (attrs.privateFlags &
703 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
704 final boolean forceHwAccelerated = (attrs.privateFlags &
705 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800706
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700707 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
708 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800709 // Don't enable hardware acceleration when we're not on the main thread
Romain Guy211370f2012-02-01 16:10:55 -0800710 if (!HardwareRenderer.sSystemRendererDisabled &&
711 Looper.getMainLooper() != Looper.myLooper()) {
Igor Murashkina86ab6402013-08-30 12:58:36 -0700712 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800713 + "acceleration outside of the main thread, aborting");
714 return;
715 }
716
Romain Guyb051e892010-09-28 19:09:36 -0700717 if (mAttachInfo.mHardwareRenderer != null) {
718 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy211370f2012-02-01 16:10:55 -0800719 }
720
721 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700722 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700723 if (mAttachInfo.mHardwareRenderer != null) {
724 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
725 mAttachInfo.mHardwareAccelerated =
726 mAttachInfo.mHardwareAccelerationRequested = true;
727 }
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700728 } else if (fakeHwAccelerated) {
729 // The window had wanted to use hardware acceleration, but this
730 // is not allowed in its process. By setting this flag, it can
731 // still render as if it was accelerated. This is basically for
732 // the preview windows the window manager shows for launching
733 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700734 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700735 }
736 }
737 }
738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 public View getView() {
740 return mView;
741 }
742
743 final WindowLeaked getLocation() {
744 return mLocation;
745 }
746
747 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
748 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700749 int oldSoftInputMode = mWindowAttributes.softInputMode;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700750 // Keep track of the actual window flags supplied by the client.
751 mClientWindowLayoutFlags = attrs.flags;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700752 // preserve compatible window flag if exists.
Adam Lesinski95c42972013-10-02 10:13:27 -0700753 int compatibleWindowFlag = mWindowAttributes.privateFlags
754 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Craig Mautner3fe38c02012-05-03 17:28:09 -0700755 // transfer over system UI visibility values as they carry current state.
756 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
757 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Romain Guyf21c9b02011-09-06 16:56:54 -0700758 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400759 if ((mWindowAttributesChangesFlag
760 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
761 // Recompute system ui visibility.
762 mAttachInfo.mRecomputeGlobalAttributes = true;
763 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800764 if (mWindowAttributes.packageName == null) {
765 mWindowAttributes.packageName = mBasePackageName;
766 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700767 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700768
769 applyKeepScreenOnFlag(mWindowAttributes);
770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 if (newView) {
772 mSoftInputMode = attrs.softInputMode;
773 requestLayout();
774 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700775 // Don't lose the mode we last auto-computed.
776 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
777 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
778 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
779 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
780 | (oldSoftInputMode
781 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 mWindowAttributesChanged = true;
784 scheduleTraversals();
785 }
786 }
787
788 void handleAppVisibility(boolean visible) {
789 if (mAppVisible != visible) {
790 mAppVisible = visible;
791 scheduleTraversals();
792 }
793 }
794
795 void handleGetNewSurface() {
796 mNewSurfaceNeeded = true;
797 mFullRedrawNeeded = true;
798 scheduleTraversals();
799 }
800
Romain Guybb9908b2012-03-08 11:14:07 -0800801 void handleScreenStateChange(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -0800802 if (on != mAttachInfo.mScreenOn) {
803 mAttachInfo.mScreenOn = on;
Romain Guybb9908b2012-03-08 11:14:07 -0800804 if (mView != null) {
805 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
806 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800807 if (on) {
808 mFullRedrawNeeded = true;
809 scheduleTraversals();
810 }
811 }
812 }
813
Craig Mautner6018aee2012-10-23 14:27:49 -0700814 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700815 public void requestFitSystemWindows() {
816 checkThread();
817 mFitSystemWindowsRequested = true;
818 scheduleTraversals();
819 }
820
Craig Mautner6018aee2012-10-23 14:27:49 -0700821 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800823 if (!mHandlingLayoutInLayoutRequest) {
824 checkThread();
825 mLayoutRequested = true;
826 scheduleTraversals();
827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
Craig Mautner6018aee2012-10-23 14:27:49 -0700830 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 public boolean isLayoutRequested() {
832 return mLayoutRequested;
833 }
834
Romain Guycfef1232012-02-23 13:50:37 -0800835 void invalidate() {
836 mDirty.set(0, 0, mWidth, mHeight);
837 scheduleTraversals();
838 }
839
Dianne Hackborna53de062012-05-08 18:53:51 -0700840 void invalidateWorld(View view) {
841 view.invalidate();
842 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700843 ViewGroup parent = (ViewGroup) view;
844 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700845 invalidateWorld(parent.getChildAt(i));
846 }
847 }
848 }
849
Craig Mautner6018aee2012-10-23 14:27:49 -0700850 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800852 invalidateChildInParent(null, dirty);
853 }
854
Craig Mautner8f303ad2013-06-14 11:32:22 -0700855 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800856 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700858 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800859
Chet Haase70d4ba12010-10-06 09:46:45 -0700860 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700861 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800862 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700863 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700864 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700865 }
Romain Guycfef1232012-02-23 13:50:37 -0800866
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700867 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700869 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700870 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800871 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700872 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700873 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700874 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700875 }
Romain Guy1e095972009-07-07 11:22:45 -0700876 if (mAttachInfo.mScalingRequired) {
877 dirty.inset(-1, -1);
878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
Romain Guycfef1232012-02-23 13:50:37 -0800880
881 final Rect localDirty = mDirty;
882 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700883 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800884 mAttachInfo.mIgnoreDirtyState = true;
885 }
Romain Guycfef1232012-02-23 13:50:37 -0800886
887 // Add the new dirty rect to the current one
888 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
889 // Intersect with the bounds of the window to skip
890 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700891 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700892 final boolean intersected = localDirty.intersect(0, 0,
893 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
894 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700895 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 }
Chet Haase3561d062012-10-23 12:54:51 -0700897 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
898 scheduleTraversals();
899 }
Romain Guycfef1232012-02-23 13:50:37 -0800900
901 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903
Dianne Hackbornce418e62011-03-01 14:31:38 -0800904 void setStopped(boolean stopped) {
905 if (mStopped != stopped) {
906 mStopped = stopped;
907 if (!stopped) {
908 scheduleTraversals();
909 }
910 }
911 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912
Craig Mautner8f303ad2013-06-14 11:32:22 -0700913 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800914 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 return null;
916 }
917
Craig Mautner8f303ad2013-06-14 11:32:22 -0700918 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700919 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 if (child != mView) {
921 throw new RuntimeException("child is not mine, honest!");
922 }
923 // Note: don't apply scroll offset, because we want to know its
924 // visibility in the virtual canvas being given to the view hierarchy.
925 return r.intersect(0, 0, mWidth, mHeight);
926 }
927
Igor Murashkina86ab6402013-08-30 12:58:36 -0700928 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 public void bringChildToFront(View child) {
930 }
931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 int getHostVisibility() {
933 return mAppVisible ? mView.getVisibility() : View.GONE;
934 }
Romain Guy8506ab42009-06-11 17:35:47 -0700935
Romain Guy7d70fbf2011-05-24 17:40:25 -0700936 void disposeResizeBuffer() {
Romain Guy27e0bf62013-06-21 14:07:07 -0700937 if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) {
938 mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
939 @Override
940 public void run() {
941 mResizeBuffer.destroy();
942 mResizeBuffer = null;
943 }
944 });
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800945 }
946 }
947
Chet Haasecca2c982011-05-20 14:34:18 -0700948 /**
949 * Add LayoutTransition to the list of transitions to be started in the next traversal.
950 * This list will be cleared after the transitions on the list are start()'ed. These
951 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
952 * happens during the layout phase of traversal, which we want to complete before any of the
953 * animations are started (because those animations may side-effect properties that layout
954 * depends upon, like the bounding rectangles of the affected views). So we add the transition
955 * to the list and it is started just prior to starting the drawing phase of traversal.
956 *
957 * @param transition The LayoutTransition to be started on the next traversal.
958 *
959 * @hide
960 */
961 public void requestTransitionStart(LayoutTransition transition) {
962 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
963 if (mPendingTransitions == null) {
964 mPendingTransitions = new ArrayList<LayoutTransition>();
965 }
966 mPendingTransitions.add(transition);
967 }
968 }
969
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700970 void scheduleTraversals() {
971 if (!mTraversalScheduled) {
972 mTraversalScheduled = true;
973 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
974 mChoreographer.postCallback(
975 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Jeff Brown330314c2012-04-27 02:20:22 -0700976 scheduleConsumeBatchedInput();
Jeff Brown96e942d2011-11-30 19:55:01 -0800977 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700978 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800979
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700980 void unscheduleTraversals() {
981 if (mTraversalScheduled) {
982 mTraversalScheduled = false;
983 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
984 mChoreographer.removeCallbacks(
985 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
986 }
987 }
988
989 void doTraversal() {
990 if (mTraversalScheduled) {
991 mTraversalScheduled = false;
992 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
993
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700994 if (mProfile) {
995 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -0800996 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800997
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700998 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
999 try {
1000 performTraversals();
1001 } finally {
1002 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1003 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001004
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001005 if (mProfile) {
1006 Debug.stopMethodTracing();
1007 mProfile = false;
1008 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001009 }
1010 }
1011
Dianne Hackborn9d090892012-06-11 18:35:41 -07001012 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1013 // Update window's global keep screen on flag: if a view has requested
1014 // that the screen be kept on, then it is always set; otherwise, it is
1015 // set to whatever the client last requested for the global state.
1016 if (mAttachInfo.mKeepScreenOn) {
1017 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1018 } else {
1019 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1020 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1021 }
1022 }
1023
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001024 private boolean collectViewAttributes() {
1025 final View.AttachInfo attachInfo = mAttachInfo;
1026 if (attachInfo.mRecomputeGlobalAttributes) {
1027 //Log.i(TAG, "Computing view hierarchy attributes!");
1028 attachInfo.mRecomputeGlobalAttributes = false;
1029 boolean oldScreenOn = attachInfo.mKeepScreenOn;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001030 attachInfo.mKeepScreenOn = false;
1031 attachInfo.mSystemUiVisibility = 0;
1032 attachInfo.mHasSystemUiListeners = false;
1033 mView.dispatchCollectViewAttributes(attachInfo, 0);
Dianne Hackborn139e5aa2012-05-05 20:36:38 -07001034 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001035 WindowManager.LayoutParams params = mWindowAttributes;
John Spurlockbd957402013-10-03 11:38:39 -04001036 attachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001037 if (attachInfo.mKeepScreenOn != oldScreenOn
Craig Mautner7eac0f52012-09-13 13:14:14 -07001038 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1039 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001040 applyKeepScreenOnFlag(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001041 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1042 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1043 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1044 return true;
1045 }
1046 }
1047 return false;
1048 }
1049
John Spurlockbd957402013-10-03 11:38:39 -04001050 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1051 int vis = 0;
1052 // Translucent decor window flags imply stable system ui visibility.
1053 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1054 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1055 }
1056 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1057 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1058 }
1059 return vis;
1060 }
1061
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001062 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1063 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1064 int childWidthMeasureSpec;
1065 int childHeightMeasureSpec;
1066 boolean windowSizeMayChange = false;
1067
1068 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1069 "Measuring " + host + " in display " + desiredWindowWidth
1070 + "x" + desiredWindowHeight + "...");
1071
1072 boolean goodMeasure = false;
1073 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1074 // On large screens, we don't want to allow dialogs to just
1075 // stretch to fill the entire width of the screen to display
1076 // one line of text. First try doing the layout at a smaller
1077 // size to see if it will fit.
1078 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1079 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1080 int baseSize = 0;
1081 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1082 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1083 }
1084 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1085 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1086 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1087 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001088 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001089 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1090 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1091 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1092 goodMeasure = true;
1093 } else {
1094 // Didn't fit in that size... try expanding a bit.
1095 baseSize = (baseSize+desiredWindowWidth)/2;
1096 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1097 + baseSize);
1098 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001099 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001100 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1101 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1102 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1103 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1104 goodMeasure = true;
1105 }
1106 }
1107 }
1108 }
1109
1110 if (!goodMeasure) {
1111 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1112 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001113 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001114 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1115 windowSizeMayChange = true;
1116 }
1117 }
1118
1119 if (DBG) {
1120 System.out.println("======================================");
1121 System.out.println("performTraversals -- after measure");
1122 host.debug();
1123 }
1124
1125 return windowSizeMayChange;
1126 }
1127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 private void performTraversals() {
1129 // cache mView since it is used so much below...
1130 final View host = mView;
1131
1132 if (DBG) {
1133 System.out.println("======================================");
1134 System.out.println("performTraversals");
1135 host.debug();
1136 }
1137
1138 if (host == null || !mAdded)
1139 return;
1140
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001141 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001143 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001145 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 WindowManager.LayoutParams lp = mWindowAttributes;
1147
1148 int desiredWindowWidth;
1149 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150
1151 final View.AttachInfo attachInfo = mAttachInfo;
1152
1153 final int viewVisibility = getHostVisibility();
1154 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1155 || mNewSurfaceNeeded;
1156
1157 WindowManager.LayoutParams params = null;
1158 if (mWindowAttributesChanged) {
1159 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001160 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 params = lp;
1162 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001163 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001164 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1165 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001166 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001167 mLayoutRequested = true;
1168 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001169 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001170 mLastInCompatMode = false;
1171 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001172 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001173 mLastInCompatMode = true;
1174 }
1175 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001176
Romain Guyf21c9b02011-09-06 16:56:54 -07001177 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001178
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001179 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001181 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 mLayoutRequested = true;
1183
John Spurlockf8508272013-10-14 21:06:52 -04001184 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1185 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001186 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001187 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001188 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001189 desiredWindowWidth = size.x;
1190 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001191 } else {
1192 DisplayMetrics packageMetrics =
1193 mView.getContext().getResources().getDisplayMetrics();
1194 desiredWindowWidth = packageMetrics.widthPixels;
1195 desiredWindowHeight = packageMetrics.heightPixels;
1196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197
1198 // For the very first time, tell the view hierarchy that it
1199 // is attached to the window. Note that at this point the surface
1200 // object is not initialized to its backing store, but soon it
1201 // will be (assuming the window is visible).
1202 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -08001203 // We used to use the following condition to choose 32 bits drawing caches:
1204 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1205 // However, windows are now always 32 bits by default, so choose 32 bits
1206 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 attachInfo.mHasWindowFocus = false;
1208 attachInfo.mWindowVisibility = viewVisibility;
1209 attachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001211 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001212 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001213 // Set the layout direction if it has not been set before (inherit is the default)
1214 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1215 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 host.dispatchAttachedToWindow(attachInfo, 0);
Dianne Hackborn961cae92013-03-20 14:59:43 -07001218 attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001219 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1220 host.fitSystemWindows(mFitSystemWindowsInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001224 desiredWindowWidth = frame.width();
1225 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001227 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001228 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001229 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001231 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233 }
1234
1235 if (viewVisibilityChanged) {
1236 attachInfo.mWindowVisibility = viewVisibility;
1237 host.dispatchWindowVisibilityChanged(viewVisibility);
1238 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001239 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 }
1241 if (viewVisibility == View.GONE) {
1242 // After making a window gone, we will count it as being
1243 // shown for the first time the next time it gets focus.
1244 mHasHadWindowFocus = false;
1245 }
1246 }
1247
Chet Haaseb78c2842012-04-19 13:39:50 -07001248 // Execute enqueued actions on every traversal in case a detached view enqueued an action
1249 getRunQueue().executeActions(attachInfo.mHandler);
1250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001252
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001253 boolean layoutRequested = mLayoutRequested && !mStopped;
1254 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001255
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001256 final Resources res = mView.getContext().getResources();
1257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 // make sure touch mode code executes by setting cached value
1260 // to opposite of the added touch mode.
1261 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001262 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001264 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1265 insetsChanged = true;
1266 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001267 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001270 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1272 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1273 + mAttachInfo.mVisibleInsets);
1274 }
1275 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1276 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001277 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278
John Spurlockf8508272013-10-14 21:06:52 -04001279 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1280 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001281 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001282 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001283 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001284 desiredWindowWidth = size.x;
1285 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001286 } else {
1287 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1288 desiredWindowWidth = packageMetrics.widthPixels;
1289 desiredWindowHeight = packageMetrics.heightPixels;
1290 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
1292 }
1293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001295 windowSizeMayChange |= measureHierarchy(host, lp, res,
1296 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 }
1298
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001299 if (collectViewAttributes()) {
1300 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001302 if (attachInfo.mForceReportNewAttributes) {
1303 attachInfo.mForceReportNewAttributes = false;
1304 params = lp;
1305 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306
1307 if (mFirst || attachInfo.mViewVisibilityChanged) {
1308 attachInfo.mViewVisibilityChanged = false;
1309 int resizeMode = mSoftInputMode &
1310 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1311 // If we are in auto resize mode, then we need to determine
1312 // what mode to use now.
1313 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1314 final int N = attachInfo.mScrollContainers.size();
1315 for (int i=0; i<N; i++) {
1316 if (attachInfo.mScrollContainers.get(i).isShown()) {
1317 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1318 }
1319 }
1320 if (resizeMode == 0) {
1321 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1322 }
1323 if ((lp.softInputMode &
1324 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1325 lp.softInputMode = (lp.softInputMode &
1326 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1327 resizeMode;
1328 params = lp;
1329 }
1330 }
1331 }
Romain Guy8506ab42009-06-11 17:35:47 -07001332
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001333 if (params != null) {
1334 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1335 if (!PixelFormat.formatHasAlpha(params.format)) {
1336 params.format = PixelFormat.TRANSLUCENT;
1337 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001339 mAttachInfo.mOverscanRequested = (params.flags
1340 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 }
1342
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001343 if (mFitSystemWindowsRequested) {
1344 mFitSystemWindowsRequested = false;
1345 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001346 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001347 host.fitSystemWindows(mFitSystemWindowsInsets);
1348 if (mLayoutRequested) {
1349 // Short-circuit catching a new layout request here, so
1350 // we don't need to go through two layout passes when things
1351 // change due to fitting system windows, which can happen a lot.
1352 windowSizeMayChange |= measureHierarchy(host, lp,
1353 mView.getContext().getResources(),
1354 desiredWindowWidth, desiredWindowHeight);
1355 }
1356 }
1357
1358 if (layoutRequested) {
1359 // Clear this now, so that if anything requests a layout in the
1360 // rest of this function we will catch it and re-run a full
1361 // layout pass.
1362 mLayoutRequested = false;
1363 }
1364
1365 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001366 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001367 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1368 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1369 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1370 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371
Jeff Brown2e05ec32013-09-30 15:57:43 -07001372 // Determine whether to compute insets.
1373 // If there are no inset listeners remaining then we may still need to compute
1374 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 final boolean computesInternalInsets =
Jeff Brown2e05ec32013-09-30 15:57:43 -07001376 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1377 || attachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 boolean insetsPending = false;
1380 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001381
1382 if (mFirst || windowShouldResize || insetsChanged ||
1383 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384
1385 if (viewVisibility == View.VISIBLE) {
1386 // If this window is giving internal insets to the window
1387 // manager, and it is being added or changing its visibility,
1388 // then we want to first give the window manager "fake"
1389 // insets to cause it to effectively ignore the content of
1390 // the window during layout. This avoids it briefly causing
1391 // other windows to resize/move based on the raw frame of the
1392 // window, waiting until we can finish laying out this window
1393 // and get back to the window manager with the ultimately
1394 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001395 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 }
1397
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001398 if (mSurfaceHolder != null) {
1399 mSurfaceHolder.mSurfaceLock.lock();
1400 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001401 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001402
Romain Guyc361da82010-10-25 15:29:10 -07001403 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001405 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001408 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001409 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1410 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001411 }
Romain Guy2a83f002011-01-18 18:28:21 -08001412
1413 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001414 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
Dianne Hackborn021d2432013-10-13 15:20:09 -07001415 if (!mDrawDuringWindowsAnimating &&
1416 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
1417 mWindowsAnimating = true;
Michael Jurkaf42d90102013-05-08 18:00:04 +02001418 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001421 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 + " content=" + mPendingContentInsets.toShortString()
1423 + " visible=" + mPendingVisibleInsets.toShortString()
1424 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001425
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001426 if (mPendingConfiguration.seq != 0) {
1427 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1428 + mPendingConfiguration);
1429 updateConfiguration(mPendingConfiguration, !mFirst);
1430 mPendingConfiguration.seq = 0;
1431 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001432
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001433 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1434 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 contentInsetsChanged = !mPendingContentInsets.equals(
1436 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001437 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 mAttachInfo.mVisibleInsets);
1439 if (contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001440 if (mWidth > 0 && mHeight > 0 && lp != null &&
1441 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1442 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001443 mSurface != null && mSurface.isValid() &&
1444 !mAttachInfo.mTurnOffWindowResizeAnim &&
1445 mAttachInfo.mHardwareRenderer != null &&
1446 mAttachInfo.mHardwareRenderer.isEnabled() &&
1447 mAttachInfo.mHardwareRenderer.validate() &&
1448 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1449
1450 disposeResizeBuffer();
1451
1452 boolean completed = false;
Romain Guyc89b14b2012-08-08 14:53:48 -07001453 HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
Chet Haase08837c22011-11-28 11:53:21 -08001454 HardwareCanvas layerCanvas = null;
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001455 try {
1456 if (mResizeBuffer == null) {
1457 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1458 mWidth, mHeight, false);
1459 } else if (mResizeBuffer.getWidth() != mWidth ||
1460 mResizeBuffer.getHeight() != mHeight) {
1461 mResizeBuffer.resize(mWidth, mHeight);
1462 }
Chet Haase603f6de2012-09-14 15:31:25 -07001463 // TODO: should handle create/resize failure
Romain Guyc89b14b2012-08-08 14:53:48 -07001464 layerCanvas = mResizeBuffer.start(hwRendererCanvas);
Chet Haase08837c22011-11-28 11:53:21 -08001465 final int restoreCount = layerCanvas.save();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001466
1467 int yoff;
1468 final boolean scrolling = mScroller != null
1469 && mScroller.computeScrollOffset();
1470 if (scrolling) {
1471 yoff = mScroller.getCurrY();
1472 mScroller.abortAnimation();
1473 } else {
1474 yoff = mScrollY;
1475 }
1476
Chet Haase08837c22011-11-28 11:53:21 -08001477 layerCanvas.translate(0, -yoff);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001478 if (mTranslator != null) {
Chet Haase08837c22011-11-28 11:53:21 -08001479 mTranslator.translateCanvas(layerCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001480 }
1481
Romain Guy3a2d6aa2012-10-23 13:25:13 -07001482 DisplayList displayList = mView.mDisplayList;
Romain Guyf6664562013-09-04 14:14:07 -07001483 if (displayList != null && displayList.isValid()) {
Romain Guy3a2d6aa2012-10-23 13:25:13 -07001484 layerCanvas.drawDisplayList(displayList, null,
1485 DisplayList.FLAG_CLIP_CHILDREN);
1486 } else {
1487 mView.draw(layerCanvas);
1488 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001489
Svetoslav Ganov42138042012-03-20 11:51:39 -07001490 drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1491
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001492 mResizeBufferStartTime = SystemClock.uptimeMillis();
1493 mResizeBufferDuration = mView.getResources().getInteger(
1494 com.android.internal.R.integer.config_mediumAnimTime);
1495 completed = true;
1496
Chet Haase08837c22011-11-28 11:53:21 -08001497 layerCanvas.restoreToCount(restoreCount);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001498 } catch (OutOfMemoryError e) {
1499 Log.w(TAG, "Not enough memory for content change anim buffer", e);
1500 } finally {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001501 if (mResizeBuffer != null) {
Romain Guyc89b14b2012-08-08 14:53:48 -07001502 mResizeBuffer.end(hwRendererCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001503 if (!completed) {
Romain Guy27e0bf62013-06-21 14:07:07 -07001504 disposeResizeBuffer();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001505 }
1506 }
1507 }
1508 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1511 + mAttachInfo.mContentInsets);
1512 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001513 if (overscanInsetsChanged) {
1514 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1515 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1516 + mAttachInfo.mOverscanInsets);
1517 // Need to relayout with content insets.
1518 contentInsetsChanged = true;
1519 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001520 if (contentInsetsChanged || mLastSystemUiVisibility !=
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001521 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
1522 || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001523 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001524 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001525 mFitSystemWindowsRequested = false;
1526 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1527 host.fitSystemWindows(mFitSystemWindowsInsets);
1528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 if (visibleInsetsChanged) {
1530 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1531 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1532 + mAttachInfo.mVisibleInsets);
1533 }
1534
1535 if (!hadSurface) {
1536 if (mSurface.isValid()) {
1537 // If we are creating a new surface, then we need to
1538 // completely redraw it. Also, when we get to the
1539 // point of drawing it we will hold off and schedule
1540 // a new traversal instead. This is so we can tell the
1541 // window manager about all of the windows being displayed
1542 // before actually drawing them, so it can display then
1543 // all at once.
1544 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001545 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001546 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001547
Romain Guyb051e892010-09-28 19:09:36 -07001548 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001549 try {
Romain Guy786fc932012-07-24 16:24:56 -07001550 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
1551 mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07001552 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001553 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001554 return;
1555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 }
1557 }
1558 } else if (!mSurface.isValid()) {
1559 // If the surface has been removed, then reset the scroll
1560 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001561 if (mLastScrolledFocus != null) {
1562 mLastScrolledFocus.clear();
1563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 mScrollY = mCurScrollY = 0;
1565 if (mScroller != null) {
1566 mScroller.abortAnimation();
1567 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001568 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001569 // Our surface is gone
1570 if (mAttachInfo.mHardwareRenderer != null &&
1571 mAttachInfo.mHardwareRenderer.isEnabled()) {
1572 mAttachInfo.mHardwareRenderer.destroy(true);
1573 }
Romain Guy2a83f002011-01-18 18:28:21 -08001574 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1575 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001576 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001577 try {
Romain Guy786fc932012-07-24 16:24:56 -07001578 mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07001579 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001580 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001581 return;
1582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 }
1584 } catch (RemoteException e) {
1585 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001588 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589
1590 attachInfo.mWindowLeft = frame.left;
1591 attachInfo.mWindowTop = frame.top;
1592
1593 // !!FIXME!! This next section handles the case where we did not get the
1594 // window size we asked for. We should avoid this by getting a maximum size from
1595 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001596 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001597 mWidth = frame.width();
1598 mHeight = frame.height();
1599 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001601 if (mSurfaceHolder != null) {
1602 // The app owns the surface; tell it about what is going on.
1603 if (mSurface.isValid()) {
1604 // XXX .copyFrom() doesn't work!
1605 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1606 mSurfaceHolder.mSurface = mSurface;
1607 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001608 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001609 mSurfaceHolder.mSurfaceLock.unlock();
1610 if (mSurface.isValid()) {
1611 if (!hadSurface) {
1612 mSurfaceHolder.ungetCallbacks();
1613
1614 mIsCreating = true;
1615 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1616 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1617 if (callbacks != null) {
1618 for (SurfaceHolder.Callback c : callbacks) {
1619 c.surfaceCreated(mSurfaceHolder);
1620 }
1621 }
1622 surfaceChanged = true;
1623 }
1624 if (surfaceChanged) {
1625 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1626 lp.format, mWidth, mHeight);
1627 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1628 if (callbacks != null) {
1629 for (SurfaceHolder.Callback c : callbacks) {
1630 c.surfaceChanged(mSurfaceHolder, lp.format,
1631 mWidth, mHeight);
1632 }
1633 }
1634 }
1635 mIsCreating = false;
1636 } else if (hadSurface) {
1637 mSurfaceHolder.ungetCallbacks();
1638 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1639 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1640 if (callbacks != null) {
1641 for (SurfaceHolder.Callback c : callbacks) {
1642 c.surfaceDestroyed(mSurfaceHolder);
1643 }
1644 }
1645 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001646 try {
1647 mSurfaceHolder.mSurface = new Surface();
1648 } finally {
1649 mSurfaceHolder.mSurfaceLock.unlock();
1650 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001651 }
1652 }
Romain Guy53389bd2010-09-07 17:16:32 -07001653
Chet Haase40e03832011-10-06 08:34:13 -07001654 if (mAttachInfo.mHardwareRenderer != null &&
1655 mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guy370ab062013-05-21 12:15:07 -07001656 if (hwInitialized ||
Chet Haase40e03832011-10-06 08:34:13 -07001657 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1658 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1659 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1660 if (!hwInitialized) {
Romain Guy786fc932012-07-24 16:24:56 -07001661 mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
Chet Haase391fef02012-09-27 15:26:36 -07001662 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001663 }
Romain Guy03985752011-07-11 15:33:51 -07001664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 }
1666
Dianne Hackbornce418e62011-03-01 14:31:38 -08001667 if (!mStopped) {
1668 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001669 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001670 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1671 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001672 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1673 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001674
Dianne Hackbornce418e62011-03-01 14:31:38 -08001675 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1676 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1677 + " mHeight=" + mHeight
1678 + " measuredHeight=" + host.getMeasuredHeight()
1679 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001680
Dianne Hackbornce418e62011-03-01 14:31:38 -08001681 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001682 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001683
Dianne Hackbornce418e62011-03-01 14:31:38 -08001684 // Implementation of weights from WindowManager.LayoutParams
1685 // We just grow the dimensions as needed and re-measure if
1686 // needs be
1687 int width = host.getMeasuredWidth();
1688 int height = host.getMeasuredHeight();
1689 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001690
Dianne Hackbornce418e62011-03-01 14:31:38 -08001691 if (lp.horizontalWeight > 0.0f) {
1692 width += (int) ((mWidth - width) * lp.horizontalWeight);
1693 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1694 MeasureSpec.EXACTLY);
1695 measureAgain = true;
1696 }
1697 if (lp.verticalWeight > 0.0f) {
1698 height += (int) ((mHeight - height) * lp.verticalWeight);
1699 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1700 MeasureSpec.EXACTLY);
1701 measureAgain = true;
1702 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001703
Dianne Hackbornce418e62011-03-01 14:31:38 -08001704 if (measureAgain) {
1705 if (DEBUG_LAYOUT) Log.v(TAG,
1706 "And hey let's measure once more: width=" + width
1707 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001708 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001709 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001710
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001711 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001714 } else {
1715 // Not the first pass and no window/insets/visibility change but the window
1716 // may have moved and we need check that and if so to update the left and right
1717 // in the attach info. We translate only the window frame since on window move
1718 // the window manager tells us only for the new frame but the insets are the
1719 // same and we do not want to translate them more than once.
1720
1721 // TODO: Well, we are checking whether the frame has changed similarly
1722 // to how this is done for the insets. This is however incorrect since
1723 // the insets and the frame are translated. For example, the old frame
1724 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1725 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1726 // true since we are comparing a not translated value to a translated one.
1727 // This scenario is rare but we may want to fix that.
1728
1729 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1730 || attachInfo.mWindowTop != frame.top);
1731 if (windowMoved) {
1732 if (mTranslator != null) {
1733 mTranslator.translateRectInScreenToAppWinFrame(frame);
1734 }
1735 attachInfo.mWindowLeft = frame.left;
1736 attachInfo.mWindowTop = frame.top;
1737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 }
1739
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001740 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 boolean triggerGlobalLayoutListener = didLayout
1742 || attachInfo.mRecomputeGlobalAttributes;
1743 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001744 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001746 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 // We can compute the transparent area
1748
Dianne Hackborn4702a852012-08-17 15:18:29 -07001749 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 // start out transparent
1751 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1752 host.getLocationInWindow(mTmpLocation);
1753 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1754 mTmpLocation[0] + host.mRight - host.mLeft,
1755 mTmpLocation[1] + host.mBottom - host.mTop);
1756
1757 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001758 if (mTranslator != null) {
1759 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1760 }
1761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1763 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001764 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 // reconfigure window manager
1766 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001767 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 } catch (RemoteException e) {
1769 }
1770 }
1771 }
1772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 if (DBG) {
1774 System.out.println("======================================");
1775 System.out.println("performTraversals -- after setFrame");
1776 host.debug();
1777 }
1778 }
1779
1780 if (triggerGlobalLayoutListener) {
1781 attachInfo.mRecomputeGlobalAttributes = false;
1782 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1783 }
1784
1785 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001786 // Clear the original insets.
1787 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1788 insets.reset();
1789
1790 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brown2e05ec32013-09-30 15:57:43 -07001792 attachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08001793
1794 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1796 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001797
1798 // Translate insets to screen coordinates if needed.
1799 final Rect contentInsets;
1800 final Rect visibleInsets;
1801 final Region touchableRegion;
1802 if (mTranslator != null) {
1803 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1804 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1805 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1806 } else {
1807 contentInsets = insets.contentInsets;
1808 visibleInsets = insets.visibleInsets;
1809 touchableRegion = insets.touchableRegion;
1810 }
1811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001813 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001814 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 } catch (RemoteException e) {
1816 }
1817 }
1818 }
Romain Guy8506ab42009-06-11 17:35:47 -07001819
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001820 boolean skipDraw = false;
1821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 if (mFirst) {
1823 // handle first focus request
1824 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1825 + mView.hasFocus());
1826 if (mView != null) {
1827 if (!mView.hasFocus()) {
1828 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001830 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001833 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835 }
Jeff Brown98365d72012-08-19 20:30:52 -07001836 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001837 // The first time we relayout the window, if the system is
1838 // doing window animations, we want to hold of on any future
1839 // draws until the animation is done.
1840 mWindowsAnimating = true;
1841 }
1842 } else if (mWindowsAnimating) {
1843 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 }
1845
1846 mFirst = false;
1847 mWillDrawSoon = false;
1848 mNewSurfaceNeeded = false;
1849 mViewVisibility = viewVisibility;
1850
keunyoung30f420f2013-08-02 14:23:10 -07001851 if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 final boolean imTarget = WindowManager.LayoutParams
1853 .mayUseInputMethod(mWindowAttributes.flags);
1854 if (imTarget != mLastWasImTarget) {
1855 mLastWasImTarget = imTarget;
1856 InputMethodManager imm = InputMethodManager.peekInstance();
1857 if (imm != null && imTarget) {
1858 imm.startGettingWindowFocus(mView);
1859 imm.onWindowFocus(mView, mView.findFocus(),
1860 mWindowAttributes.softInputMode,
1861 !mHasHadWindowFocus, mWindowAttributes.flags);
1862 }
1863 }
1864 }
Romain Guy8506ab42009-06-11 17:35:47 -07001865
Jeff Brown96e942d2011-11-30 19:55:01 -08001866 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001867 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001868 mReportNextDraw = true;
1869 }
1870
Romain Guyea835032011-07-28 19:24:37 -07001871 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1872 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873
Chet Haase61158c62011-09-06 22:19:45 -07001874 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001875 if (!skipDraw || mReportNextDraw) {
1876 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1877 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1878 mPendingTransitions.get(i).startChangingAnimations();
1879 }
1880 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001881 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001882
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001883 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001886 if (viewVisibility == View.VISIBLE) {
1887 // Try again
1888 scheduleTraversals();
1889 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001890 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1891 mPendingTransitions.get(i).endChangingAnimations();
1892 }
1893 mPendingTransitions.clear();
1894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001896
1897 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 }
1899
Romain Guy3696779b2013-01-28 14:04:07 -08001900 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
1901 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1902 try {
1903 if (!mWindowSession.outOfMemory(mWindow) &&
1904 Process.myUid() != Process.SYSTEM_UID) {
1905 Slog.w(TAG, "No processes killed for memory; killing self");
1906 Process.killProcess(Process.myPid());
1907 }
1908 } catch (RemoteException ex) {
1909 }
1910 mLayoutRequested = true; // ask wm for a new surface next time.
1911 }
1912
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001913 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1914 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1915 try {
1916 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1917 } finally {
1918 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1919 }
1920 }
1921
Chet Haase97140572012-09-13 14:56:47 -07001922 /**
1923 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
1924 * is currently undergoing a layout pass.
1925 *
1926 * @return whether the view hierarchy is currently undergoing a layout pass
1927 */
1928 boolean isInLayout() {
1929 return mInLayout;
1930 }
1931
1932 /**
Chet Haasecc699b42012-12-13 09:06:55 -08001933 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
1934 * undergoing a layout pass. requestLayout() should not generally be called during layout,
1935 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
1936 * all children in that container hierarchy are measured and laid out at the end of the layout
1937 * pass for that container). If requestLayout() is called anyway, we handle it correctly
1938 * by registering all requesters during a frame as it proceeds. At the end of the frame,
1939 * we check all of those views to see if any still have pending layout requests, which
1940 * indicates that they were not correctly handled by their container hierarchy. If that is
1941 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
1942 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07001943 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08001944 * requests to the next frame to avoid possible infinite loops.
1945 *
1946 * <p>The return value from this method indicates whether the request should proceed
1947 * (if it is a request during the first layout pass) or should be skipped and posted to the
1948 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07001949 *
1950 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08001951 *
1952 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07001953 */
Chet Haasecc699b42012-12-13 09:06:55 -08001954 boolean requestLayoutDuringLayout(final View view) {
1955 if (view.mParent == null || view.mAttachInfo == null) {
1956 // Would not normally trigger another layout, so just let it pass through as usual
1957 return true;
1958 }
Chet Haase107a4822013-03-13 06:46:50 -07001959 if (!mLayoutRequesters.contains(view)) {
1960 mLayoutRequesters.add(view);
1961 }
Chet Haase97140572012-09-13 14:56:47 -07001962 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07001963 // Let the request proceed normally; it will be processed in a second layout pass
1964 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08001965 return true;
Chet Haase97140572012-09-13 14:56:47 -07001966 } else {
Chet Haase107a4822013-03-13 06:46:50 -07001967 // Don't let the request proceed during the second layout pass.
1968 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08001969 return false;
Chet Haase97140572012-09-13 14:56:47 -07001970 }
1971 }
1972
Chet Haase3efa7b52012-12-03 08:33:17 -08001973 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
1974 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001975 mLayoutRequested = false;
1976 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07001977 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001978
1979 final View host = mView;
1980 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1981 Log.v(TAG, "Laying out " + host + " to (" +
1982 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
1983 }
1984
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001985 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
1986 try {
1987 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08001988
Chet Haased5a83522012-11-21 16:24:44 -08001989 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07001990 int numViewsRequestingLayout = mLayoutRequesters.size();
1991 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08001992 // requestLayout() was called during layout.
1993 // If no layout-request flags are set on the requesting views, there is no problem.
1994 // If some requests are still pending, then we need to clear those flags and do
1995 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07001996 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
1997 false);
1998 if (validLayoutRequesters != null) {
1999 // Set this flag to indicate that any further requests are happening during
2000 // the second pass, which may result in posting those requests to the next
2001 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002002 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002003
2004 // Process fresh layout requests, then measure and layout
2005 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002006 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002007 final View view = validLayoutRequesters.get(i);
2008 Log.w("View", "requestLayout() improperly called by " + view +
2009 " during layout: running second layout pass");
2010 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002011 }
2012 measureHierarchy(host, lp, mView.getContext().getResources(),
2013 desiredWindowWidth, desiredWindowHeight);
2014 mInLayout = true;
2015 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002016
Chet Haasecc699b42012-12-13 09:06:55 -08002017 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002018
2019 // Check the valid requests again, this time without checking/clearing the
2020 // layout flags, since requests happening during the second pass get noop'd
2021 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2022 if (validLayoutRequesters != null) {
2023 final ArrayList<View> finalRequesters = validLayoutRequesters;
2024 // Post second-pass requests to the next frame
2025 getRunQueue().post(new Runnable() {
2026 @Override
2027 public void run() {
2028 int numValidRequests = finalRequesters.size();
2029 for (int i = 0; i < numValidRequests; ++i) {
2030 final View view = finalRequesters.get(i);
2031 Log.w("View", "requestLayout() improperly called by " + view +
2032 " during second layout pass: posting in next frame");
2033 view.requestLayout();
2034 }
2035 }
2036 });
2037 }
Chet Haasecc699b42012-12-13 09:06:55 -08002038 }
Chet Haase107a4822013-03-13 06:46:50 -07002039
Chet Haase97140572012-09-13 14:56:47 -07002040 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002041 } finally {
2042 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2043 }
Chet Haase97140572012-09-13 14:56:47 -07002044 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002045 }
2046
Chet Haase107a4822013-03-13 06:46:50 -07002047 /**
2048 * This method is called during layout when there have been calls to requestLayout() during
2049 * layout. It walks through the list of views that requested layout to determine which ones
2050 * still need it, based on visibility in the hierarchy and whether they have already been
2051 * handled (as is usually the case with ListView children).
2052 *
2053 * @param layoutRequesters The list of views that requested layout during layout
2054 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2055 * If so, the FORCE_LAYOUT flag was not set on requesters.
2056 * @return A list of the actual views that still need to be laid out.
2057 */
2058 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2059 boolean secondLayoutRequests) {
2060
2061 int numViewsRequestingLayout = layoutRequesters.size();
2062 ArrayList<View> validLayoutRequesters = null;
2063 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2064 View view = layoutRequesters.get(i);
2065 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2066 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2067 View.PFLAG_FORCE_LAYOUT)) {
2068 boolean gone = false;
2069 View parent = view;
2070 // Only trigger new requests for views in a non-GONE hierarchy
2071 while (parent != null) {
2072 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2073 gone = true;
2074 break;
2075 }
2076 if (parent.mParent instanceof View) {
2077 parent = (View) parent.mParent;
2078 } else {
2079 parent = null;
2080 }
2081 }
2082 if (!gone) {
2083 if (validLayoutRequesters == null) {
2084 validLayoutRequesters = new ArrayList<View>();
2085 }
2086 validLayoutRequesters.add(view);
2087 }
2088 }
2089 }
2090 if (!secondLayoutRequests) {
2091 // If we're checking the layout flags, then we need to clean them up also
2092 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2093 View view = layoutRequesters.get(i);
2094 while (view != null &&
2095 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2096 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2097 if (view.mParent instanceof View) {
2098 view = (View) view.mParent;
2099 } else {
2100 view = null;
2101 }
2102 }
2103 }
2104 }
2105 layoutRequesters.clear();
2106 return validLayoutRequesters;
2107 }
2108
Igor Murashkina86ab6402013-08-30 12:58:36 -07002109 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 public void requestTransparentRegion(View child) {
2111 // the test below should not fail unless someone is messing with us
2112 checkThread();
2113 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002114 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 // Need to make sure we re-evaluate the window attributes next
2116 // time around, to ensure the window has the correct format.
2117 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002118 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002119 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121 }
2122
2123 /**
2124 * Figures out the measure spec for the root view in a window based on it's
2125 * layout params.
2126 *
2127 * @param windowSize
2128 * The available width or height of the window
2129 *
2130 * @param rootDimension
2131 * The layout params for one dimension (width or height) of the
2132 * window.
2133 *
2134 * @return The measure spec to use to measure the root view.
2135 */
Romain Guya998dff2012-03-23 18:58:36 -07002136 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 int measureSpec;
2138 switch (rootDimension) {
2139
Romain Guy980a9382010-01-08 15:06:28 -08002140 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 // Window can't resize. Force root view to be windowSize.
2142 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2143 break;
2144 case ViewGroup.LayoutParams.WRAP_CONTENT:
2145 // Window can resize. Set max size for root view.
2146 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2147 break;
2148 default:
2149 // Window wants to be an exact size. Force root view to be that size.
2150 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2151 break;
2152 }
2153 return measureSpec;
2154 }
2155
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002156 int mHardwareYOffset;
2157 int mResizeAlpha;
2158 final Paint mResizePaint = new Paint();
2159
Igor Murashkina86ab6402013-08-30 12:58:36 -07002160 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002161 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002162 canvas.translate(0, -mHardwareYOffset);
2163 }
2164
Igor Murashkina86ab6402013-08-30 12:58:36 -07002165 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002166 public void onHardwarePostDraw(HardwareCanvas canvas) {
2167 if (mResizeBuffer != null) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002168 mResizePaint.setAlpha(mResizeAlpha);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002169 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002170 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002171 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002172 }
2173
Chet Haaseed30fd82011-04-22 16:18:45 -07002174 /**
2175 * @hide
2176 */
2177 void outputDisplayList(View view) {
2178 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
Chet Haaseed30fd82011-04-22 16:18:45 -07002179 DisplayList displayList = view.getDisplayList();
2180 if (displayList != null) {
Romain Guy59a12ca2011-06-09 17:48:21 -07002181 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
2182 }
2183 }
2184 }
2185
2186 /**
2187 * @see #PROPERTY_PROFILE_RENDERING
2188 */
2189 private void profileRendering(boolean enabled) {
2190 if (mProfileRendering) {
2191 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002192
2193 if (mRenderProfiler != null) {
2194 mChoreographer.removeFrameCallback(mRenderProfiler);
2195 }
2196 if (mRenderProfilingEnabled) {
2197 if (mRenderProfiler == null) {
2198 mRenderProfiler = new Choreographer.FrameCallback() {
2199 @Override
2200 public void doFrame(long frameTimeNanos) {
2201 mDirty.set(0, 0, mWidth, mHeight);
2202 scheduleTraversals();
2203 if (mRenderProfilingEnabled) {
2204 mChoreographer.postFrameCallback(mRenderProfiler);
2205 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002206 }
Chris Craikae4f32042013-02-07 12:57:10 -08002207 };
2208 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002209 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002210 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002211 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002212 }
2213 }
2214 }
2215
Chet Haase2f2022a2011-10-11 06:41:59 -07002216 /**
2217 * Called from draw() when DEBUG_FPS is enabled
2218 */
2219 private void trackFPS() {
2220 // Tracks frames per second drawn. First value in a series of draws may be bogus
2221 // because it down not account for the intervening idle time
2222 long nowTime = System.currentTimeMillis();
2223 if (mFpsStartTime < 0) {
2224 mFpsStartTime = mFpsPrevTime = nowTime;
2225 mFpsNumFrames = 0;
2226 } else {
2227 ++mFpsNumFrames;
2228 String thisHash = Integer.toHexString(System.identityHashCode(this));
2229 long frameTime = nowTime - mFpsPrevTime;
2230 long totalTime = nowTime - mFpsStartTime;
2231 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2232 mFpsPrevTime = nowTime;
2233 if (totalTime > 1000) {
2234 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2235 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2236 mFpsStartTime = nowTime;
2237 mFpsNumFrames = 0;
2238 }
2239 }
2240 }
2241
Jeff Brown96e942d2011-11-30 19:55:01 -08002242 private void performDraw() {
Craig Mautner006f0e42012-03-21 11:00:32 -07002243 if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2244 return;
2245 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002246
Jeff Brown96e942d2011-11-30 19:55:01 -08002247 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2248 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002249
Romain Guy1f59e5c2012-05-06 14:11:16 -07002250 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002251 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2252 try {
2253 draw(fullRedrawNeeded);
2254 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002255 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002256 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2257 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002258
Jeff Brown96e942d2011-11-30 19:55:01 -08002259 if (mReportNextDraw) {
2260 mReportNextDraw = false;
2261
2262 if (LOCAL_LOGV) {
2263 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2264 }
2265 if (mSurfaceHolder != null && mSurface.isValid()) {
2266 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2267 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2268 if (callbacks != null) {
2269 for (SurfaceHolder.Callback c : callbacks) {
2270 if (c instanceof SurfaceHolder.Callback2) {
2271 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2272 mSurfaceHolder);
2273 }
2274 }
2275 }
2276 }
2277 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002278 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002279 } catch (RemoteException e) {
2280 }
2281 }
2282 }
2283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002284 private void draw(boolean fullRedrawNeeded) {
2285 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002286 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002287 return;
2288 }
2289
Chet Haase2f2022a2011-10-11 06:41:59 -07002290 if (DEBUG_FPS) {
2291 trackFPS();
2292 }
2293
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002294 if (!sFirstDrawComplete) {
2295 synchronized (sFirstDrawHandlers) {
2296 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002297 final int count = sFirstDrawHandlers.size();
2298 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002299 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002300 }
2301 }
2302 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304 scrollToRectOrFocus(null, false);
2305
Romain Guy25eba5c2012-04-04 17:29:03 -07002306 final AttachInfo attachInfo = mAttachInfo;
2307 if (attachInfo.mViewScrollChanged) {
2308 attachInfo.mViewScrollChanged = false;
2309 attachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 }
Romain Guy8506ab42009-06-11 17:35:47 -07002311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002313 boolean animating = mScroller != null && mScroller.computeScrollOffset();
2314 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002315 yoff = mScroller.getCurrY();
2316 } else {
2317 yoff = mScrollY;
2318 }
2319 if (mCurScrollY != yoff) {
2320 mCurScrollY = yoff;
2321 fullRedrawNeeded = true;
2322 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002323
Romain Guy25eba5c2012-04-04 17:29:03 -07002324 final float appScale = attachInfo.mApplicationScale;
2325 final boolean scalingRequired = attachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002327 int resizeAlpha = 0;
Romain Guy7d70fbf2011-05-24 17:40:25 -07002328 if (mResizeBuffer != null) {
2329 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2330 if (deltaTime < mResizeBufferDuration) {
2331 float amt = deltaTime/(float) mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002332 amt = mResizeInterpolator.getInterpolation(amt);
2333 animating = true;
2334 resizeAlpha = 255 - (int)(amt*255);
2335 } else {
Romain Guy7d70fbf2011-05-24 17:40:25 -07002336 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002337 }
2338 }
2339
Jeff Brown96e942d2011-11-30 19:55:01 -08002340 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002341 if (mSurfaceHolder != null) {
2342 // The app owns the surface, we won't draw.
2343 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002344 if (animating) {
2345 if (mScroller != null) {
2346 mScroller.abortAnimation();
2347 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07002348 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002349 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002350 return;
2351 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002352
2353 if (fullRedrawNeeded) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002354 attachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002355 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002356 }
Chet Haasead4f7032011-06-22 09:18:31 -07002357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002359 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002360 + mWindowAttributes.getTitle()
2361 + ": dirty={" + dirty.left + "," + dirty.top
2362 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002363 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2364 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 }
2366
Romain Guyfbb93fa2012-12-03 18:50:35 -08002367 invalidateDisplayLists();
2368
Romain Guy25eba5c2012-04-04 17:29:03 -07002369 attachInfo.mTreeObserver.dispatchOnDraw();
2370
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002371 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002372 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002373 // Draw with hardware renderer.
2374 mIsAnimating = false;
2375 mHardwareYOffset = yoff;
2376 mResizeAlpha = resizeAlpha;
Romain Guyfea12b82011-01-27 15:36:40 -08002377
Jeff Brown96e942d2011-11-30 19:55:01 -08002378 mCurrentDirty.set(dirty);
Jeff Brown96e942d2011-11-30 19:55:01 -08002379 dirty.setEmpty();
2380
Romain Guye55945e2013-04-04 15:26:04 -07002381 attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
2382 animating ? null : mCurrentDirty);
Romain Guy3696779b2013-01-28 14:04:07 -08002383 } else {
2384 // If we get here with a disabled & requested hardware renderer, something went
2385 // wrong (an invalidate posted right before we destroyed the hardware surface
2386 // for instance) so we should just bail out. Locking the surface with software
2387 // rendering at this point would lock it forever and prevent hardware renderer
2388 // from doing its job when it comes back.
2389 // Before we request a new frame we must however attempt to reinitiliaze the
2390 // hardware renderer if it's in requested state. This would happen after an
2391 // eglTerminate() for instance.
2392 if (attachInfo.mHardwareRenderer != null &&
2393 !attachInfo.mHardwareRenderer.isEnabled() &&
2394 attachInfo.mHardwareRenderer.isRequested()) {
2395
2396 try {
2397 attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
2398 mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07002399 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002400 handleOutOfResourcesException(e);
2401 return;
2402 }
2403
2404 mFullRedrawNeeded = true;
2405 scheduleTraversals();
2406 return;
2407 }
2408
2409 if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2410 return;
2411 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002413 }
Romain Guy8506ab42009-06-11 17:35:47 -07002414
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002415 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002416 mFullRedrawNeeded = true;
2417 scheduleTraversals();
2418 }
2419 }
2420
Romain Guy25eba5c2012-04-04 17:29:03 -07002421 /**
Romain Guyedbca122012-04-04 18:25:53 -07002422 * @return true if drawing was succesfull, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002423 */
2424 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2425 boolean scalingRequired, Rect dirty) {
2426
2427 // Draw with software renderer.
2428 Canvas canvas;
2429 try {
2430 int left = dirty.left;
2431 int top = dirty.top;
2432 int right = dirty.right;
2433 int bottom = dirty.bottom;
2434
Romain Guy25eba5c2012-04-04 17:29:03 -07002435 canvas = mSurface.lockCanvas(dirty);
2436
Romain Guye55945e2013-04-04 15:26:04 -07002437 // The dirty rectangle can be modified by Surface.lockCanvas()
2438 //noinspection ConstantConditions
Romain Guy25eba5c2012-04-04 17:29:03 -07002439 if (left != dirty.left || top != dirty.top || right != dirty.right ||
2440 bottom != dirty.bottom) {
2441 attachInfo.mIgnoreDirtyState = true;
2442 }
2443
2444 // TODO: Do this in native
2445 canvas.setDensity(mDensity);
2446 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002447 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002448 return false;
2449 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002450 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002451 // Don't assume this is due to out of memory, it could be
2452 // something else, and if it is something else then we could
2453 // kill stuff (or ourself) for no reason.
2454 mLayoutRequested = true; // ask wm for a new surface next time.
2455 return false;
2456 }
2457
2458 try {
2459 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2460 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2461 + canvas.getWidth() + ", h=" + canvas.getHeight());
2462 //canvas.drawARGB(255, 255, 0, 0);
2463 }
2464
Romain Guy25eba5c2012-04-04 17:29:03 -07002465 // If this bitmap's format includes an alpha channel, we
2466 // need to clear it before drawing so that the child will
2467 // properly re-composite its drawing on a transparent
2468 // background. This automatically respects the clip/dirty region
2469 // or
2470 // If we are applying an offset, we need to clear the area
2471 // where the offset doesn't appear to avoid having garbage
2472 // left in the blank areas.
2473 if (!canvas.isOpaque() || yoff != 0) {
2474 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2475 }
2476
2477 dirty.setEmpty();
2478 mIsAnimating = false;
2479 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002480 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002481
2482 if (DEBUG_DRAW) {
2483 Context cxt = mView.getContext();
2484 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2485 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2486 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2487 }
2488 try {
2489 canvas.translate(0, -yoff);
2490 if (mTranslator != null) {
2491 mTranslator.translateCanvas(canvas);
2492 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002493 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002494 attachInfo.mSetIgnoreDirtyState = false;
2495
Romain Guy25eba5c2012-04-04 17:29:03 -07002496 mView.draw(canvas);
2497
Svetoslav Ganov42138042012-03-20 11:51:39 -07002498 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002499 } finally {
2500 if (!attachInfo.mSetIgnoreDirtyState) {
2501 // Only clear the flag if it was not set during the mView.draw() call
2502 attachInfo.mIgnoreDirtyState = false;
2503 }
2504 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002505 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002506 try {
2507 surface.unlockCanvasAndPost(canvas);
2508 } catch (IllegalArgumentException e) {
2509 Log.e(TAG, "Could not unlock surface", e);
2510 mLayoutRequested = true; // ask wm for a new surface next time.
2511 //noinspection ReturnInsideFinallyBlock
2512 return false;
2513 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002514
Romain Guy25eba5c2012-04-04 17:29:03 -07002515 if (LOCAL_LOGV) {
2516 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2517 }
2518 }
2519 return true;
2520 }
2521
Svetoslav Ganov42138042012-03-20 11:51:39 -07002522 /**
2523 * We want to draw a highlight around the current accessibility focused.
2524 * Since adding a style for all possible view is not a viable option we
2525 * have this specialized drawing method.
2526 *
2527 * Note: We are doing this here to be able to draw the highlight for
2528 * virtual views in addition to real ones.
2529 *
2530 * @param canvas The canvas on which to draw.
2531 */
2532 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
Svetoslav Ganov07b726c2012-04-30 12:24:57 -07002533 AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2534 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002535 return;
2536 }
2537 if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
2538 return;
2539 }
2540 Drawable drawable = getAccessibilityFocusedDrawable();
2541 if (drawable == null) {
2542 return;
2543 }
2544 AccessibilityNodeProvider provider =
2545 mAccessibilityFocusedHost.getAccessibilityNodeProvider();
2546 Rect bounds = mView.mAttachInfo.mTmpInvalRect;
2547 if (provider == null) {
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002548 mAccessibilityFocusedHost.getBoundsOnScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002549 } else {
2550 if (mAccessibilityFocusedVirtualView == null) {
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07002551 return;
2552 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002553 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002554 }
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002555 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Svetoslav Ganova94c3192012-10-31 18:28:49 -07002556 bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002557 drawable.setBounds(bounds);
2558 drawable.draw(canvas);
2559 }
2560
2561 private Drawable getAccessibilityFocusedDrawable() {
2562 if (mAttachInfo != null) {
2563 // Lazily load the accessibility focus drawable.
2564 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2565 TypedValue value = new TypedValue();
2566 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2567 R.attr.accessibilityFocusedDrawable, value, true);
2568 if (resolved) {
2569 mAttachInfo.mAccessibilityFocusDrawable =
2570 mView.mContext.getResources().getDrawable(value.resourceId);
2571 }
2572 }
2573 return mAttachInfo.mAccessibilityFocusDrawable;
2574 }
2575 return null;
2576 }
2577
Romain Guy51e4d4d2012-03-15 18:30:47 -07002578 void invalidateDisplayLists() {
2579 final ArrayList<DisplayList> displayLists = mDisplayLists;
2580 final int count = displayLists.size();
2581
2582 for (int i = 0; i < count; i++) {
Romain Guy38c2ece2012-05-24 14:20:56 -07002583 final DisplayList displayList = displayLists.get(i);
Romain Guyfbb93fa2012-12-03 18:50:35 -08002584 if (displayList.isDirty()) {
Romain Guy46bfc482013-08-16 18:38:29 -07002585 displayList.reset();
Romain Guyfbb93fa2012-12-03 18:50:35 -08002586 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07002587 }
2588
2589 displayLists.clear();
2590 }
2591
Michael Jurkaf42d90102013-05-08 18:00:04 +02002592 /**
2593 * @hide
2594 */
2595 public void setDrawDuringWindowsAnimating(boolean value) {
2596 mDrawDuringWindowsAnimating = value;
2597 if (value) {
2598 handleDispatchDoneAnimating();
2599 }
2600 }
2601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002602 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2603 final View.AttachInfo attachInfo = mAttachInfo;
2604 final Rect ci = attachInfo.mContentInsets;
2605 final Rect vi = attachInfo.mVisibleInsets;
2606 int scrollY = 0;
2607 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 if (vi.left > ci.left || vi.top > ci.top
2610 || vi.right > ci.right || vi.bottom > ci.bottom) {
2611 // We'll assume that we aren't going to change the scroll
2612 // offset, since we want to avoid that unless it is actually
2613 // going to make the focus visible... otherwise we scroll
2614 // all over the place.
2615 scrollY = mScrollY;
2616 // We can be called for two different situations: during a draw,
2617 // to update the scroll position if the focus has changed (in which
2618 // case 'rectangle' is null), or in response to a
2619 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2620 // is non-null and we just want to scroll to whatever that
2621 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002622 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002623 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002624 return false;
2625 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002626 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002627 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 // If the focus has changed, then ignore any requests to scroll
2629 // to a rectangle; first we want to make sure the entire focus
2630 // view is visible.
2631 rectangle = null;
2632 }
2633 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2634 + " rectangle=" + rectangle + " ci=" + ci
2635 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002636 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002637 // Optimization: if the focus hasn't changed since last
2638 // time, and no layout has happened, then just leave things
2639 // as they are.
2640 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2641 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002642 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 // We need to determine if the currently focused view is
2644 // within the visible part of the window and, if not, apply
2645 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002646 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 mScrollMayChange = false;
2648 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2649 // Try to find the rectangle from the focus view.
2650 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2651 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2652 + mView.getWidth() + " h=" + mView.getHeight()
2653 + " ci=" + ci.toShortString()
2654 + " vi=" + vi.toShortString());
2655 if (rectangle == null) {
2656 focus.getFocusedRect(mTempRect);
2657 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2658 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002659 if (mView instanceof ViewGroup) {
2660 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2661 focus, mTempRect);
2662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2664 "Focus in window: focusRect="
2665 + mTempRect.toShortString()
2666 + " visRect=" + mVisRect.toShortString());
2667 } else {
2668 mTempRect.set(rectangle);
2669 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2670 "Request scroll to rect: "
2671 + mTempRect.toShortString()
2672 + " visRect=" + mVisRect.toShortString());
2673 }
2674 if (mTempRect.intersect(mVisRect)) {
2675 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2676 "Focus window visible rect: "
2677 + mTempRect.toShortString());
2678 if (mTempRect.height() >
2679 (mView.getHeight()-vi.top-vi.bottom)) {
2680 // If the focus simply is not going to fit, then
2681 // best is probably just to leave things as-is.
2682 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2683 "Too tall; leaving scrollY=" + scrollY);
2684 } else if ((mTempRect.top-scrollY) < vi.top) {
2685 scrollY -= vi.top - (mTempRect.top-scrollY);
2686 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2687 "Top covered; scrollY=" + scrollY);
2688 } else if ((mTempRect.bottom-scrollY)
2689 > (mView.getHeight()-vi.bottom)) {
2690 scrollY += (mTempRect.bottom-scrollY)
2691 - (mView.getHeight()-vi.bottom);
2692 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2693 "Bottom covered; scrollY=" + scrollY);
2694 }
2695 handled = true;
2696 }
2697 }
2698 }
2699 }
Romain Guy8506ab42009-06-11 17:35:47 -07002700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 if (scrollY != mScrollY) {
2702 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2703 + mScrollY + " , new=" + scrollY);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002704 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 if (mScroller == null) {
2706 mScroller = new Scroller(mView.getContext());
2707 }
2708 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2709 } else if (mScroller != null) {
2710 mScroller.abortAnimation();
2711 }
2712 mScrollY = scrollY;
2713 }
Romain Guy8506ab42009-06-11 17:35:47 -07002714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 return handled;
2716 }
Romain Guy8506ab42009-06-11 17:35:47 -07002717
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002718 /**
2719 * @hide
2720 */
2721 public View getAccessibilityFocusedHost() {
2722 return mAccessibilityFocusedHost;
2723 }
2724
2725 /**
2726 * @hide
2727 */
2728 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2729 return mAccessibilityFocusedVirtualView;
2730 }
2731
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002732 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002733 // If we have a virtual view with accessibility focus we need
2734 // to clear the focus and invalidate the virtual view bounds.
2735 if (mAccessibilityFocusedVirtualView != null) {
2736
2737 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2738 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002739
2740 // Wipe the state of the current accessibility focus since
2741 // the call into the provider to clear accessibility focus
2742 // will fire an accessibility event which will end up calling
2743 // this method and we want to have clean state when this
2744 // invocation happens.
2745 mAccessibilityFocusedHost = null;
2746 mAccessibilityFocusedVirtualView = null;
2747
Alan Viverette239a0c02013-05-07 17:17:35 -07002748 // Clear accessibility focus on the host after clearing state since
2749 // this method may be reentrant.
2750 focusHost.clearAccessibilityFocusNoCallbacks();
2751
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002752 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2753 if (provider != null) {
2754 // Invalidate the area of the cleared accessibility focus.
2755 focusNode.getBoundsInParent(mTempRect);
2756 focusHost.invalidate(mTempRect);
2757 // Clear accessibility focus in the virtual node.
2758 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2759 focusNode.getSourceNodeId());
2760 provider.performAction(virtualNodeId,
2761 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2762 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002763 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002764 }
2765 if (mAccessibilityFocusedHost != null) {
2766 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002767 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2768 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002769
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002770 // Set the new focus host and node.
2771 mAccessibilityFocusedHost = view;
2772 mAccessibilityFocusedVirtualView = node;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002773 }
2774
Igor Murashkina86ab6402013-08-30 12:58:36 -07002775 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002776 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002777 if (DEBUG_INPUT_RESIZE) {
2778 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002780 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002781 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 }
2783
Igor Murashkina86ab6402013-08-30 12:58:36 -07002784 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002785 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002786 if (DEBUG_INPUT_RESIZE) {
2787 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002788 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002789 checkThread();
2790 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002791 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002792
Svetoslav Ganov42138042012-03-20 11:51:39 -07002793 @Override
2794 public ViewParent getParentForAccessibility() {
2795 return null;
2796 }
2797
Igor Murashkina86ab6402013-08-30 12:58:36 -07002798 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 public void focusableViewAvailable(View v) {
2800 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002801 if (mView != null) {
2802 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002803 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002804 } else {
2805 // the one case where will transfer focus away from the current one
2806 // is if the current view is a view group that prefers to give focus
2807 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002808 View focused = mView.findFocus();
2809 if (focused instanceof ViewGroup) {
2810 ViewGroup group = (ViewGroup) focused;
2811 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2812 && isViewDescendantOf(v, focused)) {
2813 v.requestFocus();
2814 }
Romain Guy1c90f032011-05-24 14:59:50 -07002815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002816 }
2817 }
2818 }
2819
Igor Murashkina86ab6402013-08-30 12:58:36 -07002820 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 public void recomputeViewAttributes(View child) {
2822 checkThread();
2823 if (mView == child) {
2824 mAttachInfo.mRecomputeGlobalAttributes = true;
2825 if (!mWillDrawSoon) {
2826 scheduleTraversals();
2827 }
2828 }
2829 }
2830
2831 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002832 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002833 if (mAttachInfo.mHardwareRenderer != null &&
2834 mAttachInfo.mHardwareRenderer.isEnabled()) {
2835 mAttachInfo.mHardwareRenderer.validate();
2836 }
Dianne Hackborn961cae92013-03-20 14:59:43 -07002837 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002838 mView.dispatchDetachedFromWindow();
2839 }
2840
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002841 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2842 mAccessibilityManager.removeAccessibilityStateChangeListener(
2843 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002844 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002845
Romain Guya998dff2012-03-23 18:58:36 -07002846 destroyHardwareRenderer();
2847
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002848 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002849
Craig Mautner8f303ad2013-06-14 11:32:22 -07002850 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 mView = null;
2852 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07002853 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002855 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002856
Jeff Browncc4f7db2011-08-30 20:34:48 -07002857 if (mInputQueueCallback != null && mInputQueue != null) {
2858 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002859 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002860 mInputQueueCallback = null;
2861 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002862 }
2863 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002864 mInputEventReceiver.dispose();
2865 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002867 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002868 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 } catch (RemoteException e) {
2870 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07002871
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002872 // Dispose the input channel after removing the window so the Window Manager
2873 // doesn't interpret the input channel being closed as an abnormal termination.
2874 if (mInputChannel != null) {
2875 mInputChannel.dispose();
2876 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002877 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002878
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002879 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880 }
Romain Guy8506ab42009-06-11 17:35:47 -07002881
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002882 void updateConfiguration(Configuration config, boolean force) {
2883 if (DEBUG_CONFIGURATION) Log.v(TAG,
2884 "Applying new config to window "
2885 + mWindowAttributes.getTitle()
2886 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002887
Craig Mautner48d0d182013-06-11 07:53:06 -07002888 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
2889 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002890 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002891 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002892 }
2893
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002894 synchronized (sConfigCallbacks) {
2895 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2896 sConfigCallbacks.get(i).onConfigurationChanged(config);
2897 }
2898 }
2899 if (mView != null) {
2900 // At this point the resources have been updated to
2901 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002902 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002903 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002904 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002905 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2906 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002907 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07002908 if (lastLayoutDirection != currentLayoutDirection &&
2909 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002910 mView.setLayoutDirection(currentLayoutDirection);
2911 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002912 mView.dispatchConfigurationChanged(config);
2913 }
2914 }
Michael Wright4567e402013-08-16 15:08:35 -07002915
2916 mFlipControllerFallbackKeys =
2917 mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002918 }
Michael Wright4567e402013-08-16 15:08:35 -07002919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 /**
2921 * Return true if child is an ancestor of parent, (or equal to the parent).
2922 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002923 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002924 if (child == parent) {
2925 return true;
2926 }
2927
2928 final ViewParent theParent = child.getParent();
2929 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2930 }
2931
Romain Guycdb86672010-03-18 18:54:50 -07002932 private static void forceLayout(View view) {
2933 view.forceLayout();
2934 if (view instanceof ViewGroup) {
2935 ViewGroup group = (ViewGroup) view;
2936 final int count = group.getChildCount();
2937 for (int i = 0; i < count; i++) {
2938 forceLayout(group.getChildAt(i));
2939 }
2940 }
2941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942
Jeff Browna175a5b2012-02-15 19:18:31 -08002943 private final static int MSG_INVALIDATE = 1;
2944 private final static int MSG_INVALIDATE_RECT = 2;
2945 private final static int MSG_DIE = 3;
2946 private final static int MSG_RESIZED = 4;
2947 private final static int MSG_RESIZED_REPORT = 5;
2948 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07002949 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08002950 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2951 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08002952 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2953 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2954 private final static int MSG_CHECK_FOCUS = 13;
2955 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2956 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2957 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2958 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2959 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002960 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2961 private final static int MSG_DISPATCH_SCREEN_STATE = 20;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002962 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
2963 private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
2964 private final static int MSG_INVALIDATE_WORLD = 23;
2965 private final static int MSG_WINDOW_MOVED = 24;
Romain Guy40543602013-06-12 15:31:28 -07002966 private final static int MSG_FLUSH_LAYER_UPDATES = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967
Jeff Browna175a5b2012-02-15 19:18:31 -08002968 final class ViewRootHandler extends Handler {
2969 @Override
2970 public String getMessageName(Message message) {
2971 switch (message.what) {
2972 case MSG_INVALIDATE:
2973 return "MSG_INVALIDATE";
2974 case MSG_INVALIDATE_RECT:
2975 return "MSG_INVALIDATE_RECT";
2976 case MSG_DIE:
2977 return "MSG_DIE";
2978 case MSG_RESIZED:
2979 return "MSG_RESIZED";
2980 case MSG_RESIZED_REPORT:
2981 return "MSG_RESIZED_REPORT";
2982 case MSG_WINDOW_FOCUS_CHANGED:
2983 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07002984 case MSG_DISPATCH_INPUT_EVENT:
2985 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08002986 case MSG_DISPATCH_APP_VISIBILITY:
2987 return "MSG_DISPATCH_APP_VISIBILITY";
2988 case MSG_DISPATCH_GET_NEW_SURFACE:
2989 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08002990 case MSG_DISPATCH_KEY_FROM_IME:
2991 return "MSG_DISPATCH_KEY_FROM_IME";
2992 case MSG_FINISH_INPUT_CONNECTION:
2993 return "MSG_FINISH_INPUT_CONNECTION";
2994 case MSG_CHECK_FOCUS:
2995 return "MSG_CHECK_FOCUS";
2996 case MSG_CLOSE_SYSTEM_DIALOGS:
2997 return "MSG_CLOSE_SYSTEM_DIALOGS";
2998 case MSG_DISPATCH_DRAG_EVENT:
2999 return "MSG_DISPATCH_DRAG_EVENT";
3000 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3001 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3002 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3003 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3004 case MSG_UPDATE_CONFIGURATION:
3005 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003006 case MSG_PROCESS_INPUT_EVENTS:
3007 return "MSG_PROCESS_INPUT_EVENTS";
Romain Guy51e4d4d2012-03-15 18:30:47 -07003008 case MSG_DISPATCH_SCREEN_STATE:
3009 return "MSG_DISPATCH_SCREEN_STATE";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003010 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3011 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003012 case MSG_DISPATCH_DONE_ANIMATING:
3013 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003014 case MSG_WINDOW_MOVED:
3015 return "MSG_WINDOW_MOVED";
Romain Guy40543602013-06-12 15:31:28 -07003016 case MSG_FLUSH_LAYER_UPDATES:
3017 return "MSG_FLUSH_LAYER_UPDATES";
Jeff Browna175a5b2012-02-15 19:18:31 -08003018 }
3019 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003020 }
Romain Guyf9284692011-07-13 18:46:21 -07003021
Jeff Browna175a5b2012-02-15 19:18:31 -08003022 @Override
3023 public void handleMessage(Message msg) {
3024 switch (msg.what) {
3025 case MSG_INVALIDATE:
3026 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003027 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003028 case MSG_INVALIDATE_RECT:
3029 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3030 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003031 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003032 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003033 case MSG_PROCESS_INPUT_EVENTS:
3034 mProcessInputEventsScheduled = false;
3035 doProcessInputEvents();
3036 break;
3037 case MSG_DISPATCH_APP_VISIBILITY:
3038 handleAppVisibility(msg.arg1 != 0);
3039 break;
3040 case MSG_DISPATCH_GET_NEW_SURFACE:
3041 handleGetNewSurface();
3042 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003043 case MSG_RESIZED: {
3044 // Recycled in the fall through...
3045 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003046 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003047 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003048 && mPendingContentInsets.equals(args.arg2)
3049 && mPendingVisibleInsets.equals(args.arg3)
3050 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003051 break;
Romain Guycdb86672010-03-18 18:54:50 -07003052 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003053 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003054 case MSG_RESIZED_REPORT:
3055 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003056 SomeArgs args = (SomeArgs) msg.obj;
3057
3058 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003059 if (config != null) {
3060 updateConfiguration(config, false);
3061 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003062
3063 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003064 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003065 mPendingContentInsets.set((Rect) args.arg2);
3066 mPendingVisibleInsets.set((Rect) args.arg3);
3067
3068 args.recycle();
3069
Jeff Browna175a5b2012-02-15 19:18:31 -08003070 if (msg.what == MSG_RESIZED_REPORT) {
3071 mReportNextDraw = true;
3072 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003073
Jeff Browna175a5b2012-02-15 19:18:31 -08003074 if (mView != null) {
3075 forceLayout(mView);
3076 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003077
Jeff Browna175a5b2012-02-15 19:18:31 -08003078 requestLayout();
3079 }
3080 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003081 case MSG_WINDOW_MOVED:
3082 if (mAdded) {
3083 final int w = mWinFrame.width();
3084 final int h = mWinFrame.height();
3085 final int l = msg.arg1;
3086 final int t = msg.arg2;
3087 mWinFrame.left = l;
3088 mWinFrame.right = l + w;
3089 mWinFrame.top = t;
3090 mWinFrame.bottom = t + h;
3091
3092 if (mView != null) {
3093 forceLayout(mView);
3094 }
3095 requestLayout();
3096 }
3097 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003098 case MSG_WINDOW_FOCUS_CHANGED: {
3099 if (mAdded) {
3100 boolean hasWindowFocus = msg.arg1 != 0;
3101 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102
Jeff Browna175a5b2012-02-15 19:18:31 -08003103 profileRendering(hasWindowFocus);
3104
3105 if (hasWindowFocus) {
3106 boolean inTouchMode = msg.arg2 != 0;
3107 ensureTouchModeLocally(inTouchMode);
3108
Romain Guye55945e2013-04-04 15:26:04 -07003109 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003110 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003111 try {
Romain Guy3696779b2013-01-28 14:04:07 -08003112 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
3113 mWidth, mHeight, mHolder.getSurface());
Igor Murashkina86ab6402013-08-30 12:58:36 -07003114 } catch (OutOfResourcesException e) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003115 Log.e(TAG, "OutOfResourcesException locking surface", e);
3116 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003117 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003118 Slog.w(TAG, "No processes killed for memory; killing self");
3119 Process.killProcess(Process.myPid());
3120 }
3121 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003122 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003123 // Retry in a bit.
3124 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3125 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003126 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 }
Romain Guy8506ab42009-06-11 17:35:47 -07003129
Jeff Browna175a5b2012-02-15 19:18:31 -08003130 mLastWasImTarget = WindowManager.LayoutParams
3131 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003132
Jeff Browna175a5b2012-02-15 19:18:31 -08003133 InputMethodManager imm = InputMethodManager.peekInstance();
3134 if (mView != null) {
keunyoung30f420f2013-08-02 14:23:10 -07003135 if (hasWindowFocus && imm != null && mLastWasImTarget &&
3136 !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003137 imm.startGettingWindowFocus(mView);
3138 }
3139 mAttachInfo.mKeyDispatchState.reset();
3140 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003141 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003143
Jeff Browna175a5b2012-02-15 19:18:31 -08003144 // Note: must be done after the focus change callbacks,
3145 // so all of the view state is set up correctly.
3146 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003147 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003148 imm.onWindowFocus(mView, mView.findFocus(),
3149 mWindowAttributes.softInputMode,
3150 !mHasHadWindowFocus, mWindowAttributes.flags);
3151 }
3152 // Clear the forward bit. We can just do this directly, since
3153 // the window manager doesn't care about it.
3154 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003156 ((WindowManager.LayoutParams)mView.getLayoutParams())
3157 .softInputMode &=
3158 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3159 mHasHadWindowFocus = true;
3160 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003161
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003162 setAccessibilityFocus(null, null);
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07003163
Svetoslav Ganov42138042012-03-20 11:51:39 -07003164 if (mView != null && mAccessibilityManager.isEnabled()) {
3165 if (hasWindowFocus) {
3166 mView.sendAccessibilityEvent(
3167 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003168 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003169 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003170 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003171 } break;
3172 case MSG_DIE:
3173 doDie();
3174 break;
keunyoung30f420f2013-08-02 14:23:10 -07003175 case MSG_DISPATCH_INPUT_EVENT: {
3176 InputEvent event = (InputEvent)msg.obj;
Jeff Browna175a5b2012-02-15 19:18:31 -08003177 enqueueInputEvent(event, null, 0, true);
3178 } break;
3179 case MSG_DISPATCH_KEY_FROM_IME: {
3180 if (LOCAL_LOGV) Log.v(
3181 TAG, "Dispatching key "
3182 + msg.obj + " from IME to " + mView);
3183 KeyEvent event = (KeyEvent)msg.obj;
3184 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3185 // The IME is trying to say this event is from the
3186 // system! Bad bad bad!
3187 //noinspection UnusedAssignment
3188 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
3189 }
3190 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3191 } break;
3192 case MSG_FINISH_INPUT_CONNECTION: {
3193 InputMethodManager imm = InputMethodManager.peekInstance();
3194 if (imm != null) {
3195 imm.reportFinishInputConnection((InputConnection)msg.obj);
3196 }
3197 } break;
3198 case MSG_CHECK_FOCUS: {
3199 InputMethodManager imm = InputMethodManager.peekInstance();
3200 if (imm != null) {
3201 imm.checkFocus();
3202 }
3203 } break;
3204 case MSG_CLOSE_SYSTEM_DIALOGS: {
3205 if (mView != null) {
3206 mView.onCloseSystemDialogs((String)msg.obj);
3207 }
3208 } break;
3209 case MSG_DISPATCH_DRAG_EVENT:
3210 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3211 DragEvent event = (DragEvent)msg.obj;
3212 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3213 handleDragEvent(event);
3214 } break;
3215 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003216 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003217 } break;
3218 case MSG_UPDATE_CONFIGURATION: {
3219 Configuration config = (Configuration)msg.obj;
3220 if (config.isOtherSeqNewer(mLastConfiguration)) {
3221 config = mLastConfiguration;
3222 }
3223 updateConfiguration(config, false);
3224 } break;
Romain Guybb9908b2012-03-08 11:14:07 -08003225 case MSG_DISPATCH_SCREEN_STATE: {
Romain Guy7e4e5612012-03-05 14:37:29 -08003226 if (mView != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08003227 handleScreenStateChange(msg.arg1 == 1);
Romain Guy7e4e5612012-03-05 14:37:29 -08003228 }
3229 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003230 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003231 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003232 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003233 case MSG_DISPATCH_DONE_ANIMATING: {
3234 handleDispatchDoneAnimating();
3235 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003236 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003237 if (mView != null) {
3238 invalidateWorld(mView);
3239 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003240 } break;
Romain Guy40543602013-06-12 15:31:28 -07003241 case MSG_FLUSH_LAYER_UPDATES: {
3242 flushHardwareLayerUpdates();
3243 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 }
3246 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003247
Jeff Browna175a5b2012-02-15 19:18:31 -08003248 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003250 /**
3251 * Something in the current window tells us we need to change the touch mode. For
3252 * example, we are not in touch mode, and the user touches the screen.
3253 *
3254 * If the touch mode has changed, tell the window manager, and handle it locally.
3255 *
3256 * @param inTouchMode Whether we want to be in touch mode.
3257 * @return True if the touch mode changed and focus changed was changed as a result
3258 */
3259 boolean ensureTouchMode(boolean inTouchMode) {
3260 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3261 + "touch mode is " + mAttachInfo.mInTouchMode);
3262 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3263
3264 // tell the window manager
3265 try {
keunyoung30f420f2013-08-02 14:23:10 -07003266 if (!isInLocalFocusMode()) {
3267 mWindowSession.setInTouchMode(inTouchMode);
3268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 } catch (RemoteException e) {
3270 throw new RuntimeException(e);
3271 }
3272
3273 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003274 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 }
3276
3277 /**
3278 * Ensure that the touch mode for this window is set, and if it is changing,
3279 * take the appropriate action.
3280 * @param inTouchMode Whether we want to be in touch mode.
3281 * @return True if the touch mode changed and focus changed was changed as a result
3282 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003283 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3285 + "touch mode is " + mAttachInfo.mInTouchMode);
3286
3287 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3288
3289 mAttachInfo.mInTouchMode = inTouchMode;
3290 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3291
Romain Guy2d4cff62010-04-09 15:39:00 -07003292 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 }
3294
3295 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003296 if (mView != null && mView.hasFocus()) {
3297 // note: not relying on mFocusedView here because this could
3298 // be when the window is first being added, and mFocused isn't
3299 // set yet.
3300 final View focused = mView.findFocus();
3301 if (focused != null && !focused.isFocusableInTouchMode()) {
3302 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3303 if (ancestorToTakeFocus != null) {
3304 // there is an ancestor that wants focus after its
3305 // descendants that is focusable in touch mode.. give it
3306 // focus
3307 return ancestorToTakeFocus.requestFocus();
3308 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003309 // There's nothing to focus. Clear and propagate through the
3310 // hierarchy, but don't attempt to place new focus.
3311 focused.clearFocusInternal(true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003312 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 }
3314 }
3315 }
3316 return false;
3317 }
3318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 /**
3320 * Find an ancestor of focused that wants focus after its descendants and is
3321 * focusable in touch mode.
3322 * @param focused The currently focused view.
3323 * @return An appropriate view, or null if no such view exists.
3324 */
Romain Guya998dff2012-03-23 18:58:36 -07003325 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 ViewParent parent = focused.getParent();
3327 while (parent instanceof ViewGroup) {
3328 final ViewGroup vgParent = (ViewGroup) parent;
3329 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3330 && vgParent.isFocusableInTouchMode()) {
3331 return vgParent;
3332 }
3333 if (vgParent.isRootNamespace()) {
3334 return null;
3335 } else {
3336 parent = vgParent.getParent();
3337 }
3338 }
3339 return null;
3340 }
3341
3342 private boolean leaveTouchMode() {
3343 if (mView != null) {
3344 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003345 View focusedView = mView.findFocus();
3346 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003348 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003349 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3351 // some view group has focus, and doesn't prefer its children
3352 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003353 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003354 }
3355 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003356
3357 // find the best view to give focus to in this brave new non-touch-mode
3358 // world
3359 final View focused = focusSearch(null, View.FOCUS_DOWN);
3360 if (focused != null) {
3361 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 }
3363 }
3364 return false;
3365 }
3366
Jeff Brownf9e989d2013-04-04 23:04:03 -07003367 /**
3368 * Base class for implementing a stage in the chain of responsibility
3369 * for processing input events.
3370 * <p>
3371 * Events are delivered to the stage by the {@link #deliver} method. The stage
3372 * then has the choice of finishing the event or forwarding it to the next stage.
3373 * </p>
3374 */
3375 abstract class InputStage {
3376 private final InputStage mNext;
3377
3378 protected static final int FORWARD = 0;
3379 protected static final int FINISH_HANDLED = 1;
3380 protected static final int FINISH_NOT_HANDLED = 2;
3381
3382 /**
3383 * Creates an input stage.
3384 * @param next The next stage to which events should be forwarded.
3385 */
3386 public InputStage(InputStage next) {
3387 mNext = next;
3388 }
3389
3390 /**
3391 * Delivers an event to be processed.
3392 */
3393 public final void deliver(QueuedInputEvent q) {
3394 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3395 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003396 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003397 finish(q, false);
3398 } else {
3399 apply(q, onProcess(q));
3400 }
3401 }
3402
3403 /**
3404 * Marks the the input event as finished then forwards it to the next stage.
3405 */
3406 protected void finish(QueuedInputEvent q, boolean handled) {
3407 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3408 if (handled) {
3409 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3410 }
3411 forward(q);
3412 }
3413
3414 /**
3415 * Forwards the event to the next stage.
3416 */
3417 protected void forward(QueuedInputEvent q) {
3418 onDeliverToNext(q);
3419 }
3420
3421 /**
3422 * Applies a result code from {@link #onProcess} to the specified event.
3423 */
3424 protected void apply(QueuedInputEvent q, int result) {
3425 if (result == FORWARD) {
3426 forward(q);
3427 } else if (result == FINISH_HANDLED) {
3428 finish(q, true);
3429 } else if (result == FINISH_NOT_HANDLED) {
3430 finish(q, false);
3431 } else {
3432 throw new IllegalArgumentException("Invalid result: " + result);
3433 }
3434 }
3435
3436 /**
3437 * Called when an event is ready to be processed.
3438 * @return A result code indicating how the event was handled.
3439 */
3440 protected int onProcess(QueuedInputEvent q) {
3441 return FORWARD;
3442 }
3443
3444 /**
3445 * Called when an event is being delivered to the next stage.
3446 */
3447 protected void onDeliverToNext(QueuedInputEvent q) {
3448 if (mNext != null) {
3449 mNext.deliver(q);
3450 } else {
3451 finishInputEvent(q);
3452 }
3453 }
Jeff Brown5182c782013-10-15 20:31:52 -07003454
Michael Wright17d28ca2013-10-31 17:47:45 -07003455 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3456 if (mView == null || !mAdded) {
3457 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3458 return true;
3459 } else if (!mAttachInfo.mHasWindowFocus &&
3460 !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
3461 !isTerminalInputEvent(q.mEvent)) {
3462 // If this is a focused event and the window doesn't currently have input focus,
3463 // then drop this event. This could be an event that came back from the previous
3464 // stage but the window has lost focus in the meantime.
3465 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
3466 return true;
3467 }
3468 return false;
3469 }
3470
Jeff Brown5182c782013-10-15 20:31:52 -07003471 void dump(String prefix, PrintWriter writer) {
3472 if (mNext != null) {
3473 mNext.dump(prefix, writer);
3474 }
3475 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003476 }
3477
3478 /**
3479 * Base class for implementing an input pipeline stage that supports
3480 * asynchronous and out-of-order processing of input events.
3481 * <p>
3482 * In addition to what a normal input stage can do, an asynchronous
3483 * input stage may also defer an input event that has been delivered to it
3484 * and finish or forward it later.
3485 * </p>
3486 */
3487 abstract class AsyncInputStage extends InputStage {
3488 private final String mTraceCounter;
3489
3490 private QueuedInputEvent mQueueHead;
3491 private QueuedInputEvent mQueueTail;
3492 private int mQueueLength;
3493
3494 protected static final int DEFER = 3;
3495
3496 /**
3497 * Creates an asynchronous input stage.
3498 * @param next The next stage to which events should be forwarded.
3499 * @param traceCounter The name of a counter to record the size of
3500 * the queue of pending events.
3501 */
3502 public AsyncInputStage(InputStage next, String traceCounter) {
3503 super(next);
3504 mTraceCounter = traceCounter;
3505 }
3506
3507 /**
3508 * Marks the event as deferred, which is to say that it will be handled
3509 * asynchronously. The caller is responsible for calling {@link #forward}
3510 * or {@link #finish} later when it is done handling the event.
3511 */
3512 protected void defer(QueuedInputEvent q) {
3513 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3514 enqueue(q);
3515 }
3516
3517 @Override
3518 protected void forward(QueuedInputEvent q) {
3519 // Clear the deferred flag.
3520 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3521
3522 // Fast path if the queue is empty.
3523 QueuedInputEvent curr = mQueueHead;
3524 if (curr == null) {
3525 super.forward(q);
3526 return;
3527 }
3528
3529 // Determine whether the event must be serialized behind any others
3530 // before it can be delivered to the next stage. This is done because
3531 // deferred events might be handled out of order by the stage.
3532 final int deviceId = q.mEvent.getDeviceId();
3533 QueuedInputEvent prev = null;
3534 boolean blocked = false;
3535 while (curr != null && curr != q) {
3536 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3537 blocked = true;
3538 }
3539 prev = curr;
3540 curr = curr.mNext;
3541 }
3542
3543 // If the event is blocked, then leave it in the queue to be delivered later.
3544 // Note that the event might not yet be in the queue if it was not previously
3545 // deferred so we will enqueue it if needed.
3546 if (blocked) {
3547 if (curr == null) {
3548 enqueue(q);
3549 }
3550 return;
3551 }
3552
3553 // The event is not blocked. Deliver it immediately.
3554 if (curr != null) {
3555 curr = curr.mNext;
3556 dequeue(q, prev);
3557 }
3558 super.forward(q);
3559
3560 // Dequeuing this event may have unblocked successors. Deliver them.
3561 while (curr != null) {
3562 if (deviceId == curr.mEvent.getDeviceId()) {
3563 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3564 break;
3565 }
3566 QueuedInputEvent next = curr.mNext;
3567 dequeue(curr, prev);
3568 super.forward(curr);
3569 curr = next;
3570 } else {
3571 prev = curr;
3572 curr = curr.mNext;
3573 }
3574 }
3575 }
3576
3577 @Override
3578 protected void apply(QueuedInputEvent q, int result) {
3579 if (result == DEFER) {
3580 defer(q);
3581 } else {
3582 super.apply(q, result);
3583 }
3584 }
3585
3586 private void enqueue(QueuedInputEvent q) {
3587 if (mQueueTail == null) {
3588 mQueueHead = q;
3589 mQueueTail = q;
3590 } else {
3591 mQueueTail.mNext = q;
3592 mQueueTail = q;
3593 }
3594
3595 mQueueLength += 1;
3596 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3597 }
3598
3599 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3600 if (prev == null) {
3601 mQueueHead = q.mNext;
3602 } else {
3603 prev.mNext = q.mNext;
3604 }
3605 if (mQueueTail == q) {
3606 mQueueTail = prev;
3607 }
3608 q.mNext = null;
3609
3610 mQueueLength -= 1;
3611 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3612 }
Jeff Brown5182c782013-10-15 20:31:52 -07003613
3614 @Override
3615 void dump(String prefix, PrintWriter writer) {
3616 writer.print(prefix);
3617 writer.print(getClass().getName());
3618 writer.print(": mQueueLength=");
3619 writer.println(mQueueLength);
3620
3621 super.dump(prefix, writer);
3622 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003623 }
3624
3625 /**
3626 * Delivers pre-ime input events to a native activity.
3627 * Does not support pointer events.
3628 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003629 final class NativePreImeInputStage extends AsyncInputStage
3630 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003631 public NativePreImeInputStage(InputStage next, String traceCounter) {
3632 super(next, traceCounter);
3633 }
3634
3635 @Override
3636 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003637 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3638 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3639 return DEFER;
3640 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003641 return FORWARD;
3642 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003643
3644 @Override
3645 public void onFinishedInputEvent(Object token, boolean handled) {
3646 QueuedInputEvent q = (QueuedInputEvent)token;
3647 if (handled) {
3648 finish(q, true);
3649 return;
3650 }
3651 forward(q);
3652 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003653 }
3654
3655 /**
3656 * Delivers pre-ime input events to the view hierarchy.
3657 * Does not support pointer events.
3658 */
3659 final class ViewPreImeInputStage extends InputStage {
3660 public ViewPreImeInputStage(InputStage next) {
3661 super(next);
3662 }
3663
3664 @Override
3665 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003666 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003667 return processKeyEvent(q);
3668 }
3669 return FORWARD;
3670 }
3671
3672 private int processKeyEvent(QueuedInputEvent q) {
3673 final KeyEvent event = (KeyEvent)q.mEvent;
3674 if (mView.dispatchKeyEventPreIme(event)) {
3675 return FINISH_HANDLED;
3676 }
3677 return FORWARD;
3678 }
3679 }
3680
3681 /**
3682 * Delivers input events to the ime.
3683 * Does not support pointer events.
3684 */
3685 final class ImeInputStage extends AsyncInputStage
3686 implements InputMethodManager.FinishedInputEventCallback {
3687 public ImeInputStage(InputStage next, String traceCounter) {
3688 super(next, traceCounter);
3689 }
3690
3691 @Override
3692 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07003693 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003694 InputMethodManager imm = InputMethodManager.peekInstance();
3695 if (imm != null) {
3696 final InputEvent event = q.mEvent;
3697 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3698 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3699 if (result == InputMethodManager.DISPATCH_HANDLED) {
3700 return FINISH_HANDLED;
3701 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
3702 return FINISH_NOT_HANDLED;
3703 } else {
3704 return DEFER; // callback will be invoked later
3705 }
3706 }
3707 }
3708 return FORWARD;
3709 }
3710
3711 @Override
3712 public void onFinishedInputEvent(Object token, boolean handled) {
3713 QueuedInputEvent q = (QueuedInputEvent)token;
3714 if (handled) {
3715 finish(q, true);
3716 return;
3717 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003718 forward(q);
3719 }
3720 }
3721
3722 /**
3723 * Performs early processing of post-ime input events.
3724 */
3725 final class EarlyPostImeInputStage extends InputStage {
3726 public EarlyPostImeInputStage(InputStage next) {
3727 super(next);
3728 }
3729
3730 @Override
3731 protected int onProcess(QueuedInputEvent q) {
3732 if (q.mEvent instanceof KeyEvent) {
3733 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003734 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003735 final int source = q.mEvent.getSource();
3736 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003737 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003738 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003739 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003740 return FORWARD;
3741 }
3742
3743 private int processKeyEvent(QueuedInputEvent q) {
3744 final KeyEvent event = (KeyEvent)q.mEvent;
3745
3746 // If the key's purpose is to exit touch mode then we consume it
3747 // and consider it handled.
3748 if (checkForLeavingTouchModeAndConsume(event)) {
3749 return FINISH_HANDLED;
3750 }
3751
3752 // Make sure the fallback event policy sees all keys that will be
3753 // delivered to the view hierarchy.
3754 mFallbackEventHandler.preDispatchKeyEvent(event);
3755 return FORWARD;
3756 }
3757
3758 private int processPointerEvent(QueuedInputEvent q) {
3759 final MotionEvent event = (MotionEvent)q.mEvent;
3760
3761 // Translate the pointer event for compatibility, if needed.
3762 if (mTranslator != null) {
3763 mTranslator.translateEventInScreenToAppWindow(event);
3764 }
3765
3766 // Enter touch mode on down or scroll.
3767 final int action = event.getAction();
3768 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3769 ensureTouchMode(true);
3770 }
3771
3772 // Offset the scroll position.
3773 if (mCurScrollY != 0) {
3774 event.offsetLocation(0, mCurScrollY);
3775 }
3776
3777 // Remember the touch position for possible drag-initiation.
3778 if (event.isTouchEvent()) {
3779 mLastTouchPoint.x = event.getRawX();
3780 mLastTouchPoint.y = event.getRawY();
3781 }
3782 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003783 }
3784 }
3785
Jeff Brownf9e989d2013-04-04 23:04:03 -07003786 /**
3787 * Delivers post-ime input events to a native activity.
3788 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003789 final class NativePostImeInputStage extends AsyncInputStage
3790 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003791 public NativePostImeInputStage(InputStage next, String traceCounter) {
3792 super(next, traceCounter);
3793 }
3794
3795 @Override
3796 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003797 if (mInputQueue != null) {
3798 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3799 return DEFER;
3800 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003801 return FORWARD;
3802 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003803
3804 @Override
3805 public void onFinishedInputEvent(Object token, boolean handled) {
3806 QueuedInputEvent q = (QueuedInputEvent)token;
3807 if (handled) {
3808 finish(q, true);
3809 return;
3810 }
3811 forward(q);
3812 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003813 }
3814
3815 /**
3816 * Delivers post-ime input events to the view hierarchy.
3817 */
3818 final class ViewPostImeInputStage extends InputStage {
3819 public ViewPostImeInputStage(InputStage next) {
3820 super(next);
3821 }
3822
3823 @Override
3824 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003825 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003826 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003827 } else {
Dianne Hackborn021d2432013-10-13 15:20:09 -07003828 // If delivering a new non-key event, make sure the window is
3829 // now allowed to start updating.
3830 handleDispatchDoneAnimating();
Jeff Brown29c0ed22013-01-14 13:50:37 -08003831 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003832 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3833 return processPointerEvent(q);
3834 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3835 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003836 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003837 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003838 }
3839 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003840 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003841
Jeff Brownf9e989d2013-04-04 23:04:03 -07003842 private int processKeyEvent(QueuedInputEvent q) {
3843 final KeyEvent event = (KeyEvent)q.mEvent;
3844
Dianne Hackborn021d2432013-10-13 15:20:09 -07003845 if (event.getAction() != KeyEvent.ACTION_UP) {
3846 // If delivering a new key event, make sure the window is
3847 // now allowed to start updating.
3848 handleDispatchDoneAnimating();
3849 }
3850
Jeff Brownf9e989d2013-04-04 23:04:03 -07003851 // Deliver the key to the view hierarchy.
3852 if (mView.dispatchKeyEvent(event)) {
3853 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003854 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003855
Michael Wright17d28ca2013-10-31 17:47:45 -07003856 if (shouldDropInputEvent(q)) {
3857 return FINISH_NOT_HANDLED;
3858 }
3859
Jeff Brownf9e989d2013-04-04 23:04:03 -07003860 // If the Control modifier is held, try to interpret the key as a shortcut.
3861 if (event.getAction() == KeyEvent.ACTION_DOWN
3862 && event.isCtrlPressed()
3863 && event.getRepeatCount() == 0
3864 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3865 if (mView.dispatchKeyShortcutEvent(event)) {
3866 return FINISH_HANDLED;
3867 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003868 if (shouldDropInputEvent(q)) {
3869 return FINISH_NOT_HANDLED;
3870 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003871 }
3872
3873 // Apply the fallback event policy.
3874 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3875 return FINISH_HANDLED;
3876 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003877 if (shouldDropInputEvent(q)) {
3878 return FINISH_NOT_HANDLED;
3879 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003880
3881 // Handle automatic focus changes.
3882 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3883 int direction = 0;
3884 switch (event.getKeyCode()) {
3885 case KeyEvent.KEYCODE_DPAD_LEFT:
3886 if (event.hasNoModifiers()) {
3887 direction = View.FOCUS_LEFT;
3888 }
3889 break;
3890 case KeyEvent.KEYCODE_DPAD_RIGHT:
3891 if (event.hasNoModifiers()) {
3892 direction = View.FOCUS_RIGHT;
3893 }
3894 break;
3895 case KeyEvent.KEYCODE_DPAD_UP:
3896 if (event.hasNoModifiers()) {
3897 direction = View.FOCUS_UP;
3898 }
3899 break;
3900 case KeyEvent.KEYCODE_DPAD_DOWN:
3901 if (event.hasNoModifiers()) {
3902 direction = View.FOCUS_DOWN;
3903 }
3904 break;
3905 case KeyEvent.KEYCODE_TAB:
3906 if (event.hasNoModifiers()) {
3907 direction = View.FOCUS_FORWARD;
3908 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3909 direction = View.FOCUS_BACKWARD;
3910 }
3911 break;
3912 }
3913 if (direction != 0) {
3914 View focused = mView.findFocus();
3915 if (focused != null) {
3916 View v = focused.focusSearch(direction);
3917 if (v != null && v != focused) {
3918 // do the math the get the interesting rect
3919 // of previous focused into the coord system of
3920 // newly focused view
3921 focused.getFocusedRect(mTempRect);
3922 if (mView instanceof ViewGroup) {
3923 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3924 focused, mTempRect);
3925 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3926 v, mTempRect);
3927 }
3928 if (v.requestFocus(direction, mTempRect)) {
3929 playSoundEffect(SoundEffectConstants
3930 .getContantForFocusDirection(direction));
3931 return FINISH_HANDLED;
3932 }
3933 }
3934
3935 // Give the focused view a last chance to handle the dpad key.
3936 if (mView.dispatchUnhandledMove(focused, direction)) {
3937 return FINISH_HANDLED;
3938 }
3939 } else {
3940 // find the best view to give focus to in this non-touch-mode with no-focus
3941 View v = focusSearch(null, direction);
3942 if (v != null && v.requestFocus(direction)) {
3943 return FINISH_HANDLED;
3944 }
3945 }
3946 }
3947 }
3948 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003949 }
3950
Jeff Brownf9e989d2013-04-04 23:04:03 -07003951 private int processPointerEvent(QueuedInputEvent q) {
3952 final MotionEvent event = (MotionEvent)q.mEvent;
3953
3954 if (mView.dispatchPointerEvent(event)) {
3955 return FINISH_HANDLED;
3956 }
3957 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003958 }
3959
Jeff Brownf9e989d2013-04-04 23:04:03 -07003960 private int processTrackballEvent(QueuedInputEvent q) {
3961 final MotionEvent event = (MotionEvent)q.mEvent;
3962
3963 if (mView.dispatchTrackballEvent(event)) {
3964 return FINISH_HANDLED;
3965 }
3966 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003967 }
3968
Jeff Brownf9e989d2013-04-04 23:04:03 -07003969 private int processGenericMotionEvent(QueuedInputEvent q) {
3970 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003971
Jeff Brownf9e989d2013-04-04 23:04:03 -07003972 // Deliver the event to the view.
3973 if (mView.dispatchGenericMotionEvent(event)) {
3974 return FINISH_HANDLED;
3975 }
3976 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003977 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003978 }
3979
Jeff Brownf9e989d2013-04-04 23:04:03 -07003980 /**
Jeff Brown678a1252013-04-09 17:46:25 -07003981 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07003982 */
3983 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07003984 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
3985 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
3986 private final SyntheticTouchNavigationHandler mTouchNavigation =
3987 new SyntheticTouchNavigationHandler();
Michael Wright4567e402013-08-16 15:08:35 -07003988 private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003989
3990 public SyntheticInputStage() {
3991 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08003992 }
3993
Jeff Brownf9e989d2013-04-04 23:04:03 -07003994 @Override
3995 protected int onProcess(QueuedInputEvent q) {
3996 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
3997 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07003998 final MotionEvent event = (MotionEvent)q.mEvent;
3999 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004000 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004001 mTrackball.process(event);
4002 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004003 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004004 mJoystick.process(event);
4005 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004006 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4007 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004008 mTouchNavigation.process(event);
4009 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004010 }
Michael Wright4567e402013-08-16 15:08:35 -07004011 } else if (q.mEvent instanceof KeyEvent) {
4012 if (mKeys.process((KeyEvent) q.mEvent)) {
4013 return FINISH_HANDLED;
4014 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004015 }
Michael Wright4567e402013-08-16 15:08:35 -07004016
Jeff Brownf9e989d2013-04-04 23:04:03 -07004017 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004018 }
4019
Jeff Brownf9e989d2013-04-04 23:04:03 -07004020 @Override
4021 protected void onDeliverToNext(QueuedInputEvent q) {
4022 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4023 // Cancel related synthetic events if any prior stage has handled the event.
4024 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004025 final MotionEvent event = (MotionEvent)q.mEvent;
4026 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004027 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004028 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004029 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004030 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004031 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4032 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004033 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004034 }
4035 }
4036 }
4037 super.onDeliverToNext(q);
4038 }
Jeff Brown678a1252013-04-09 17:46:25 -07004039 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004040
Jeff Brown678a1252013-04-09 17:46:25 -07004041 /**
4042 * Creates dpad events from unhandled trackball movements.
4043 */
4044 final class SyntheticTrackballHandler {
4045 private final TrackballAxis mX = new TrackballAxis();
4046 private final TrackballAxis mY = new TrackballAxis();
4047 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004048
Jeff Brown678a1252013-04-09 17:46:25 -07004049 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004050 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004051 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004052 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004053 // It has been too long since the last movement,
4054 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004055 mX.reset(0);
4056 mY.reset(0);
4057 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004058 }
4059
4060 final int action = event.getAction();
4061 final int metaState = event.getMetaState();
4062 switch (action) {
4063 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004064 mX.reset(2);
4065 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004066 enqueueInputEvent(new KeyEvent(curTime, curTime,
4067 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4068 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4069 InputDevice.SOURCE_KEYBOARD));
4070 break;
4071 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004072 mX.reset(2);
4073 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004074 enqueueInputEvent(new KeyEvent(curTime, curTime,
4075 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4076 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4077 InputDevice.SOURCE_KEYBOARD));
4078 break;
4079 }
4080
Jeff Brown678a1252013-04-09 17:46:25 -07004081 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4082 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004083 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004084 + " / Y=" + mY.position + " step="
4085 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004086 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004087 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4088 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004089
4090 // Generate DPAD events based on the trackball movement.
4091 // We pick the axis that has moved the most as the direction of
4092 // the DPAD. When we generate DPAD events for one axis, then the
4093 // other axis is reset -- we don't want to perform DPAD jumps due
4094 // to slight movements in the trackball when making major movements
4095 // along the other axis.
4096 int keycode = 0;
4097 int movement = 0;
4098 float accel = 1;
4099 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004100 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004101 if (movement != 0) {
4102 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4103 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004104 accel = mX.acceleration;
4105 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004106 }
4107 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004108 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004109 if (movement != 0) {
4110 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4111 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004112 accel = mY.acceleration;
4113 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004114 }
4115 }
4116
4117 if (keycode != 0) {
4118 if (movement < 0) movement = -movement;
4119 int accelMovement = (int)(movement * accel);
4120 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4121 + " accelMovement=" + accelMovement
4122 + " accel=" + accel);
4123 if (accelMovement > movement) {
4124 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4125 + keycode);
4126 movement--;
4127 int repeatCount = accelMovement - movement;
4128 enqueueInputEvent(new KeyEvent(curTime, curTime,
4129 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4130 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4131 InputDevice.SOURCE_KEYBOARD));
4132 }
4133 while (movement > 0) {
4134 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4135 + keycode);
4136 movement--;
4137 curTime = SystemClock.uptimeMillis();
4138 enqueueInputEvent(new KeyEvent(curTime, curTime,
4139 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4140 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4141 InputDevice.SOURCE_KEYBOARD));
4142 enqueueInputEvent(new KeyEvent(curTime, curTime,
4143 KeyEvent.ACTION_UP, keycode, 0, metaState,
4144 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4145 InputDevice.SOURCE_KEYBOARD));
4146 }
Jeff Brown678a1252013-04-09 17:46:25 -07004147 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004148 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004149 }
4150
Jeff Brown678a1252013-04-09 17:46:25 -07004151 public void cancel(MotionEvent event) {
4152 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004153
Jeff Brownf9e989d2013-04-04 23:04:03 -07004154 // If we reach this, we consumed a trackball event.
4155 // Because we will not translate the trackball event into a key event,
4156 // touch mode will not exit, so we exit touch mode here.
4157 if (mView != null && mAdded) {
4158 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004159 }
4160 }
Jeff Brown678a1252013-04-09 17:46:25 -07004161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162
Jeff Brown678a1252013-04-09 17:46:25 -07004163 /**
4164 * Maintains state information for a single trackball axis, generating
4165 * discrete (DPAD) movements based on raw trackball motion.
4166 */
4167 static final class TrackballAxis {
4168 /**
4169 * The maximum amount of acceleration we will apply.
4170 */
4171 static final float MAX_ACCELERATION = 20;
4172
4173 /**
4174 * The maximum amount of time (in milliseconds) between events in order
4175 * for us to consider the user to be doing fast trackball movements,
4176 * and thus apply an acceleration.
4177 */
4178 static final long FAST_MOVE_TIME = 150;
4179
4180 /**
4181 * Scaling factor to the time (in milliseconds) between events to how
4182 * much to multiple/divide the current acceleration. When movement
4183 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4184 * FAST_MOVE_TIME it divides it.
4185 */
4186 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4187
4188 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4189 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4190 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4191
4192 float position;
4193 float acceleration = 1;
4194 long lastMoveTime = 0;
4195 int step;
4196 int dir;
4197 int nonAccelMovement;
4198
4199 void reset(int _step) {
4200 position = 0;
4201 acceleration = 1;
4202 lastMoveTime = 0;
4203 step = _step;
4204 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004205 }
4206
Jeff Brown678a1252013-04-09 17:46:25 -07004207 /**
4208 * Add trackball movement into the state. If the direction of movement
4209 * has been reversed, the state is reset before adding the
4210 * movement (so that you don't have to compensate for any previously
4211 * collected movement before see the result of the movement in the
4212 * new direction).
4213 *
4214 * @return Returns the absolute value of the amount of movement
4215 * collected so far.
4216 */
4217 float collect(float off, long time, String axis) {
4218 long normTime;
4219 if (off > 0) {
4220 normTime = (long)(off * FAST_MOVE_TIME);
4221 if (dir < 0) {
4222 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4223 position = 0;
4224 step = 0;
4225 acceleration = 1;
4226 lastMoveTime = 0;
4227 }
4228 dir = 1;
4229 } else if (off < 0) {
4230 normTime = (long)((-off) * FAST_MOVE_TIME);
4231 if (dir > 0) {
4232 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4233 position = 0;
4234 step = 0;
4235 acceleration = 1;
4236 lastMoveTime = 0;
4237 }
4238 dir = -1;
4239 } else {
4240 normTime = 0;
4241 }
4242
4243 // The number of milliseconds between each movement that is
4244 // considered "normal" and will not result in any acceleration
4245 // or deceleration, scaled by the offset we have here.
4246 if (normTime > 0) {
4247 long delta = time - lastMoveTime;
4248 lastMoveTime = time;
4249 float acc = acceleration;
4250 if (delta < normTime) {
4251 // The user is scrolling rapidly, so increase acceleration.
4252 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4253 if (scale > 1) acc *= scale;
4254 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4255 + off + " normTime=" + normTime + " delta=" + delta
4256 + " scale=" + scale + " acc=" + acc);
4257 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4258 } else {
4259 // The user is scrolling slowly, so decrease acceleration.
4260 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4261 if (scale > 1) acc /= scale;
4262 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4263 + off + " normTime=" + normTime + " delta=" + delta
4264 + " scale=" + scale + " acc=" + acc);
4265 acceleration = acc > 1 ? acc : 1;
4266 }
4267 }
4268 position += off;
4269 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004270 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004271
Jeff Brown678a1252013-04-09 17:46:25 -07004272 /**
4273 * Generate the number of discrete movement events appropriate for
4274 * the currently collected trackball movement.
4275 *
4276 * @return Returns the number of discrete movements, either positive
4277 * or negative, or 0 if there is not enough trackball movement yet
4278 * for a discrete movement.
4279 */
4280 int generate() {
4281 int movement = 0;
4282 nonAccelMovement = 0;
4283 do {
4284 final int dir = position >= 0 ? 1 : -1;
4285 switch (step) {
4286 // If we are going to execute the first step, then we want
4287 // to do this as soon as possible instead of waiting for
4288 // a full movement, in order to make things look responsive.
4289 case 0:
4290 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4291 return movement;
4292 }
4293 movement += dir;
4294 nonAccelMovement += dir;
4295 step = 1;
4296 break;
4297 // If we have generated the first movement, then we need
4298 // to wait for the second complete trackball motion before
4299 // generating the second discrete movement.
4300 case 1:
4301 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4302 return movement;
4303 }
4304 movement += dir;
4305 nonAccelMovement += dir;
4306 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4307 step = 2;
4308 break;
4309 // After the first two, we generate discrete movements
4310 // consistently with the trackball, applying an acceleration
4311 // if the trackball is moving quickly. This is a simple
4312 // acceleration on top of what we already compute based
4313 // on how quickly the wheel is being turned, to apply
4314 // a longer increasing acceleration to continuous movement
4315 // in one direction.
4316 default:
4317 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4318 return movement;
4319 }
4320 movement += dir;
4321 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4322 float acc = acceleration;
4323 acc *= 1.1f;
4324 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4325 break;
4326 }
4327 } while (true);
4328 }
4329 }
4330
4331 /**
4332 * Creates dpad events from unhandled joystick movements.
4333 */
4334 final class SyntheticJoystickHandler extends Handler {
4335 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4336 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4337
4338 private int mLastXDirection;
4339 private int mLastYDirection;
4340 private int mLastXKeyCode;
4341 private int mLastYKeyCode;
4342
4343 public SyntheticJoystickHandler() {
4344 super(true);
4345 }
4346
4347 @Override
4348 public void handleMessage(Message msg) {
4349 switch (msg.what) {
4350 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4351 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4352 KeyEvent oldEvent = (KeyEvent)msg.obj;
4353 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4354 SystemClock.uptimeMillis(),
4355 oldEvent.getRepeatCount() + 1);
4356 if (mAttachInfo.mHasWindowFocus) {
4357 enqueueInputEvent(e);
4358 Message m = obtainMessage(msg.what, e);
4359 m.setAsynchronous(true);
4360 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4361 }
4362 } break;
4363 }
4364 }
4365
4366 public void process(MotionEvent event) {
4367 update(event, true);
4368 }
4369
4370 public void cancel(MotionEvent event) {
4371 update(event, false);
4372 }
4373
4374 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004375 final long time = event.getEventTime();
4376 final int metaState = event.getMetaState();
4377 final int deviceId = event.getDeviceId();
4378 final int source = event.getSource();
4379
4380 int xDirection = joystickAxisValueToDirection(
4381 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4382 if (xDirection == 0) {
4383 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004384 }
4385
Jeff Brownf9e989d2013-04-04 23:04:03 -07004386 int yDirection = joystickAxisValueToDirection(
4387 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4388 if (yDirection == 0) {
4389 yDirection = joystickAxisValueToDirection(event.getY());
4390 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004391
Jeff Brown678a1252013-04-09 17:46:25 -07004392 if (xDirection != mLastXDirection) {
4393 if (mLastXKeyCode != 0) {
4394 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004395 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004396 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004397 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004398 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004399 }
4400
Jeff Brown678a1252013-04-09 17:46:25 -07004401 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004402
4403 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004404 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004405 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4406 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004407 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004408 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4409 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004410 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004411 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004412 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004413 }
4414 }
4415
Jeff Brown678a1252013-04-09 17:46:25 -07004416 if (yDirection != mLastYDirection) {
4417 if (mLastYKeyCode != 0) {
4418 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004419 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004420 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004421 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004422 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004423 }
4424
Jeff Brown678a1252013-04-09 17:46:25 -07004425 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004426
4427 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004428 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004429 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4430 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004431 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004432 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4433 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004434 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004435 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004436 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004437 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004438 }
4439 }
4440
Jeff Brownf9e989d2013-04-04 23:04:03 -07004441 private int joystickAxisValueToDirection(float value) {
4442 if (value >= 0.5f) {
4443 return 1;
4444 } else if (value <= -0.5f) {
4445 return -1;
4446 } else {
4447 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004448 }
4449 }
Jeff Brown678a1252013-04-09 17:46:25 -07004450 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004451
Jeff Brown678a1252013-04-09 17:46:25 -07004452 /**
4453 * Creates dpad events from unhandled touch navigation movements.
4454 */
4455 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004456 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4457 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004458
Jeff Brown4dac9012013-04-10 01:03:19 -07004459 // Assumed nominal width and height in millimeters of a touch navigation pad,
4460 // if no resolution information is available from the input system.
4461 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4462 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004463
Jeff Brown4dac9012013-04-10 01:03:19 -07004464 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004465
Jeff Brown4dac9012013-04-10 01:03:19 -07004466 // The nominal distance traveled to move by one unit.
4467 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4468
4469 // Minimum and maximum fling velocity in ticks per second.
4470 // The minimum velocity should be set such that we perform enough ticks per
4471 // second that the fling appears to be fluid. For example, if we set the minimum
4472 // to 2 ticks per second, then there may be up to half a second delay between the next
4473 // to last and last ticks which is noticeably discrete and jerky. This value should
4474 // probably not be set to anything less than about 4.
4475 // If fling accuracy is a problem then consider tuning the tick distance instead.
4476 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4477 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4478
4479 // Fling velocity decay factor applied after each new key is emitted.
4480 // This parameter controls the deceleration and overall duration of the fling.
4481 // The fling stops automatically when its velocity drops below the minimum
4482 // fling velocity defined above.
4483 private static final float FLING_TICK_DECAY = 0.8f;
4484
4485 /* The input device that we are tracking. */
4486
4487 private int mCurrentDeviceId = -1;
4488 private int mCurrentSource;
4489 private boolean mCurrentDeviceSupported;
4490
4491 /* Configuration for the current input device. */
4492
Jeff Brown4dac9012013-04-10 01:03:19 -07004493 // The scaled tick distance. A movement of this amount should generally translate
4494 // into a single dpad event in a given direction.
4495 private float mConfigTickDistance;
4496
4497 // The minimum and maximum scaled fling velocity.
4498 private float mConfigMinFlingVelocity;
4499 private float mConfigMaxFlingVelocity;
4500
4501 /* Tracking state. */
4502
4503 // The velocity tracker for detecting flings.
4504 private VelocityTracker mVelocityTracker;
4505
4506 // The active pointer id, or -1 if none.
4507 private int mActivePointerId = -1;
4508
4509 // Time and location where tracking started.
4510 private long mStartTime;
4511 private float mStartX;
4512 private float mStartY;
4513
4514 // Most recently observed position.
4515 private float mLastX;
4516 private float mLastY;
4517
4518 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004519 private float mAccumulatedX;
4520 private float mAccumulatedY;
4521
Jeff Brown4dac9012013-04-10 01:03:19 -07004522 // Set to true if any movement was delivered to the app.
4523 // Implies that tap slop was exceeded.
4524 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004525
Jeff Brown4dac9012013-04-10 01:03:19 -07004526 // The most recently sent key down event.
4527 // The keycode remains set until the direction changes or a fling ends
4528 // so that repeated key events may be generated as required.
4529 private long mPendingKeyDownTime;
4530 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4531 private int mPendingKeyRepeatCount;
4532 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004533
Jeff Brown4dac9012013-04-10 01:03:19 -07004534 // The current fling velocity while a fling is in progress.
4535 private boolean mFlinging;
4536 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004537
Michael Wright25b0c302013-07-10 12:54:06 -07004538 // The last time a confirm key was pressed on the touch nav device
4539 private long mLastConfirmKeyTime = Long.MAX_VALUE;
4540
Jeff Brown678a1252013-04-09 17:46:25 -07004541 public SyntheticTouchNavigationHandler() {
4542 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004543 }
4544
4545 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004546 // Update the current device information.
4547 final long time = event.getEventTime();
4548 final int deviceId = event.getDeviceId();
4549 final int source = event.getSource();
4550 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4551 finishKeys(time);
4552 finishTracking(time);
4553 mCurrentDeviceId = deviceId;
4554 mCurrentSource = source;
4555 mCurrentDeviceSupported = false;
4556 InputDevice device = event.getDevice();
4557 if (device != null) {
4558 // In order to support an input device, we must know certain
4559 // characteristics about it, such as its size and resolution.
4560 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4561 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4562 if (xRange != null && yRange != null) {
4563 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004564
Jeff Brown4dac9012013-04-10 01:03:19 -07004565 // Infer the resolution if it not actually known.
4566 float xRes = xRange.getResolution();
4567 if (xRes <= 0) {
4568 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4569 }
4570 float yRes = yRange.getResolution();
4571 if (yRes <= 0) {
4572 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4573 }
4574 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004575
Jeff Brown4dac9012013-04-10 01:03:19 -07004576 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07004577 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4578 mConfigMinFlingVelocity =
4579 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4580 mConfigMaxFlingVelocity =
4581 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4582
4583 if (LOCAL_DEBUG) {
4584 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4585 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07004586 + ", mConfigTickDistance=" + mConfigTickDistance
4587 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4588 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4589 }
4590 }
4591 }
Jeff Brown678a1252013-04-09 17:46:25 -07004592 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004593 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004594 return;
4595 }
4596
Jeff Brown4dac9012013-04-10 01:03:19 -07004597 // Handle the event.
4598 final int action = event.getActionMasked();
4599 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004600 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004601 boolean caughtFling = mFlinging;
4602 finishKeys(time);
4603 finishTracking(time);
4604 mActivePointerId = event.getPointerId(0);
4605 mVelocityTracker = VelocityTracker.obtain();
4606 mVelocityTracker.addMovement(event);
4607 mStartTime = time;
4608 mStartX = event.getX();
4609 mStartY = event.getY();
4610 mLastX = mStartX;
4611 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004612 mAccumulatedX = 0;
4613 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004614
4615 // If we caught a fling, then pretend that the tap slop has already
4616 // been exceeded to suppress taps whose only purpose is to stop the fling.
4617 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004618 break;
4619 }
4620
Jeff Brown4dac9012013-04-10 01:03:19 -07004621 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004622 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004623 if (mActivePointerId < 0) {
4624 break;
4625 }
4626 final int index = event.findPointerIndex(mActivePointerId);
4627 if (index < 0) {
4628 finishKeys(time);
4629 finishTracking(time);
4630 break;
4631 }
Jeff Brown678a1252013-04-09 17:46:25 -07004632
Jeff Brown4dac9012013-04-10 01:03:19 -07004633 mVelocityTracker.addMovement(event);
4634 final float x = event.getX(index);
4635 final float y = event.getY(index);
4636 mAccumulatedX += x - mLastX;
4637 mAccumulatedY += y - mLastY;
4638 mLastX = x;
4639 mLastY = y;
4640
4641 // Consume any accumulated movement so far.
4642 final int metaState = event.getMetaState();
4643 consumeAccumulatedMovement(time, metaState);
4644
4645 // Detect taps and flings.
4646 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07004647 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004648 // It might be a fling.
4649 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4650 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4651 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4652 if (!startFling(time, vx, vy)) {
4653 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004654 }
4655 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004656 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004657 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004658 break;
4659 }
4660
4661 case MotionEvent.ACTION_CANCEL: {
4662 finishKeys(time);
4663 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004664 break;
4665 }
4666 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004667 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004668
4669 public void cancel(MotionEvent event) {
4670 if (mCurrentDeviceId == event.getDeviceId()
4671 && mCurrentSource == event.getSource()) {
4672 final long time = event.getEventTime();
4673 finishKeys(time);
4674 finishTracking(time);
4675 }
4676 }
4677
4678 private void finishKeys(long time) {
4679 cancelFling();
4680 sendKeyUp(time);
4681 }
4682
4683 private void finishTracking(long time) {
4684 if (mActivePointerId >= 0) {
4685 mActivePointerId = -1;
4686 mVelocityTracker.recycle();
4687 mVelocityTracker = null;
4688 }
4689 }
4690
4691 private void consumeAccumulatedMovement(long time, int metaState) {
4692 final float absX = Math.abs(mAccumulatedX);
4693 final float absY = Math.abs(mAccumulatedY);
4694 if (absX >= absY) {
4695 if (absX >= mConfigTickDistance) {
4696 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4697 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4698 mAccumulatedY = 0;
4699 mConsumedMovement = true;
4700 }
4701 } else {
4702 if (absY >= mConfigTickDistance) {
4703 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4704 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4705 mAccumulatedX = 0;
4706 mConsumedMovement = true;
4707 }
4708 }
4709 }
4710
4711 private float consumeAccumulatedMovement(long time, int metaState,
4712 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4713 while (accumulator <= -mConfigTickDistance) {
4714 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4715 accumulator += mConfigTickDistance;
4716 }
4717 while (accumulator >= mConfigTickDistance) {
4718 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4719 accumulator -= mConfigTickDistance;
4720 }
4721 return accumulator;
4722 }
4723
4724 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4725 if (mPendingKeyCode != keyCode) {
4726 sendKeyUp(time);
4727 mPendingKeyDownTime = time;
4728 mPendingKeyCode = keyCode;
4729 mPendingKeyRepeatCount = 0;
4730 } else {
4731 mPendingKeyRepeatCount += 1;
4732 }
4733 mPendingKeyMetaState = metaState;
4734
4735 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4736 // but it doesn't quite make sense when simulating the events in this way.
4737 if (LOCAL_DEBUG) {
4738 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4739 + ", repeatCount=" + mPendingKeyRepeatCount
4740 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4741 }
4742 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4743 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4744 mPendingKeyMetaState, mCurrentDeviceId,
4745 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4746 }
4747
4748 private void sendKeyUp(long time) {
4749 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4750 if (LOCAL_DEBUG) {
4751 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4752 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4753 }
4754 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4755 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4756 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4757 mCurrentSource));
4758 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4759 }
4760 }
4761
4762 private boolean startFling(long time, float vx, float vy) {
4763 if (LOCAL_DEBUG) {
4764 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4765 + ", min=" + mConfigMinFlingVelocity);
4766 }
4767
4768 // Flings must be oriented in the same direction as the preceding movements.
4769 switch (mPendingKeyCode) {
4770 case KeyEvent.KEYCODE_DPAD_LEFT:
4771 if (-vx >= mConfigMinFlingVelocity
4772 && Math.abs(vy) < mConfigMinFlingVelocity) {
4773 mFlingVelocity = -vx;
4774 break;
4775 }
4776 return false;
4777
4778 case KeyEvent.KEYCODE_DPAD_RIGHT:
4779 if (vx >= mConfigMinFlingVelocity
4780 && Math.abs(vy) < mConfigMinFlingVelocity) {
4781 mFlingVelocity = vx;
4782 break;
4783 }
4784 return false;
4785
4786 case KeyEvent.KEYCODE_DPAD_UP:
4787 if (-vy >= mConfigMinFlingVelocity
4788 && Math.abs(vx) < mConfigMinFlingVelocity) {
4789 mFlingVelocity = -vy;
4790 break;
4791 }
4792 return false;
4793
4794 case KeyEvent.KEYCODE_DPAD_DOWN:
4795 if (vy >= mConfigMinFlingVelocity
4796 && Math.abs(vx) < mConfigMinFlingVelocity) {
4797 mFlingVelocity = vy;
4798 break;
4799 }
4800 return false;
4801 }
4802
4803 // Post the first fling event.
4804 mFlinging = postFling(time);
4805 return mFlinging;
4806 }
4807
4808 private boolean postFling(long time) {
4809 // The idea here is to estimate the time when the pointer would have
4810 // traveled one tick distance unit given the current fling velocity.
4811 // This effect creates continuity of motion.
4812 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4813 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
4814 postAtTime(mFlingRunnable, time + delay);
4815 if (LOCAL_DEBUG) {
4816 Log.d(LOCAL_TAG, "Posted fling: velocity="
4817 + mFlingVelocity + ", delay=" + delay
4818 + ", keyCode=" + mPendingKeyCode);
4819 }
4820 return true;
4821 }
4822 return false;
4823 }
4824
4825 private void cancelFling() {
4826 if (mFlinging) {
4827 removeCallbacks(mFlingRunnable);
4828 mFlinging = false;
4829 }
4830 }
4831
4832 private final Runnable mFlingRunnable = new Runnable() {
4833 @Override
4834 public void run() {
4835 final long time = SystemClock.uptimeMillis();
4836 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
4837 mFlingVelocity *= FLING_TICK_DECAY;
4838 if (!postFling(time)) {
4839 mFlinging = false;
4840 finishKeys(time);
4841 }
4842 }
4843 };
Jeff Browncb1404e2011-01-15 18:14:15 -08004844 }
4845
Michael Wright4567e402013-08-16 15:08:35 -07004846 final class SyntheticKeyHandler {
4847
4848 public boolean process(KeyEvent event) {
4849 // In some locales (like Japan) controllers use B for confirm and A for back, rather
4850 // than vice versa, so we need to special case this here since the input system itself
4851 // is not locale-aware.
4852 int keyCode;
4853 switch(event.getKeyCode()) {
4854 case KeyEvent.KEYCODE_BUTTON_A:
4855 case KeyEvent.KEYCODE_BUTTON_C:
4856 case KeyEvent.KEYCODE_BUTTON_X:
4857 case KeyEvent.KEYCODE_BUTTON_Z:
4858 keyCode = mFlipControllerFallbackKeys ?
4859 KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER;
4860 break;
4861 case KeyEvent.KEYCODE_BUTTON_B:
4862 case KeyEvent.KEYCODE_BUTTON_Y:
4863 keyCode = mFlipControllerFallbackKeys ?
4864 KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK;
4865 break;
4866 case KeyEvent.KEYCODE_BUTTON_THUMBL:
4867 case KeyEvent.KEYCODE_BUTTON_THUMBR:
4868 case KeyEvent.KEYCODE_BUTTON_START:
4869 case KeyEvent.KEYCODE_BUTTON_1:
4870 case KeyEvent.KEYCODE_BUTTON_2:
4871 case KeyEvent.KEYCODE_BUTTON_3:
4872 case KeyEvent.KEYCODE_BUTTON_4:
4873 case KeyEvent.KEYCODE_BUTTON_5:
4874 case KeyEvent.KEYCODE_BUTTON_6:
4875 case KeyEvent.KEYCODE_BUTTON_7:
4876 case KeyEvent.KEYCODE_BUTTON_8:
4877 case KeyEvent.KEYCODE_BUTTON_9:
4878 case KeyEvent.KEYCODE_BUTTON_10:
4879 case KeyEvent.KEYCODE_BUTTON_11:
4880 case KeyEvent.KEYCODE_BUTTON_12:
4881 case KeyEvent.KEYCODE_BUTTON_13:
4882 case KeyEvent.KEYCODE_BUTTON_14:
4883 case KeyEvent.KEYCODE_BUTTON_15:
4884 case KeyEvent.KEYCODE_BUTTON_16:
4885 keyCode = KeyEvent.KEYCODE_DPAD_CENTER;
4886 break;
4887 case KeyEvent.KEYCODE_BUTTON_SELECT:
4888 case KeyEvent.KEYCODE_BUTTON_MODE:
4889 keyCode = KeyEvent.KEYCODE_MENU;
4890 default:
4891 return false;
4892 }
4893
4894 enqueueInputEvent(new KeyEvent(event.getDownTime(), event.getEventTime(),
4895 event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(),
Michael Wrighta9777072013-09-27 14:03:13 -07004896 event.getDeviceId(), event.getScanCode(),
4897 event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource()));
Michael Wright4567e402013-08-16 15:08:35 -07004898 return true;
4899 }
4900
4901 }
4902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004903 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004904 * Returns true if the key is used for keyboard navigation.
4905 * @param keyEvent The key event.
4906 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004907 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004908 private static boolean isNavigationKey(KeyEvent keyEvent) {
4909 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004910 case KeyEvent.KEYCODE_DPAD_LEFT:
4911 case KeyEvent.KEYCODE_DPAD_RIGHT:
4912 case KeyEvent.KEYCODE_DPAD_UP:
4913 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08004914 case KeyEvent.KEYCODE_DPAD_CENTER:
4915 case KeyEvent.KEYCODE_PAGE_UP:
4916 case KeyEvent.KEYCODE_PAGE_DOWN:
4917 case KeyEvent.KEYCODE_MOVE_HOME:
4918 case KeyEvent.KEYCODE_MOVE_END:
4919 case KeyEvent.KEYCODE_TAB:
4920 case KeyEvent.KEYCODE_SPACE:
4921 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004922 return true;
4923 }
4924 return false;
4925 }
4926
4927 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004928 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004929 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08004930 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004931 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004932 private static boolean isTypingKey(KeyEvent keyEvent) {
4933 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004934 }
4935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004936 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004937 * 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 -08004938 * @param event The key event.
4939 * @return Whether this key event should be consumed (meaning the act of
4940 * leaving touch mode alone is considered the event).
4941 */
4942 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004943 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004944 if (!mAttachInfo.mInTouchMode) {
4945 return false;
4946 }
4947
Jeff Brown4e6319b2010-12-13 10:36:51 -08004948 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
4949 final int action = event.getAction();
4950 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004951 return false;
4952 }
4953
Jeff Brown4e6319b2010-12-13 10:36:51 -08004954 // Don't leave touch mode if the IME told us not to.
4955 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
4956 return false;
4957 }
4958
4959 // If the key can be used for keyboard navigation then leave touch mode
4960 // and select a focused view if needed (in ensureTouchMode).
4961 // When a new focused view is selected, we consume the navigation key because
4962 // navigation doesn't make much sense unless a view already has focus so
4963 // the key's purpose is to set focus.
4964 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004965 return ensureTouchMode(false);
4966 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08004967
4968 // If the key can be used for typing then leave touch mode
4969 // and select a focused view if needed (in ensureTouchMode).
4970 // Always allow the view to process the typing key.
4971 if (isTypingKey(event)) {
4972 ensureTouchMode(false);
4973 return false;
4974 }
4975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004976 return false;
4977 }
4978
Christopher Tatea53146c2010-09-07 11:57:52 -07004979 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08004980 void setLocalDragState(Object obj) {
4981 mLocalDragState = obj;
4982 }
4983
Christopher Tatea53146c2010-09-07 11:57:52 -07004984 private void handleDragEvent(DragEvent event) {
4985 // From the root, only drag start/end/location are dispatched. entered/exited
4986 // are determined and dispatched by the viewgroup hierarchy, who then report
4987 // that back here for ultimate reporting back to the framework.
4988 if (mView != null && mAdded) {
4989 final int what = event.mAction;
4990
4991 if (what == DragEvent.ACTION_DRAG_EXITED) {
4992 // A direct EXITED event means that the window manager knows we've just crossed
4993 // a window boundary, so the current drag target within this one must have
4994 // just been exited. Send it the usual notifications and then we're done
4995 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07004996 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004997 } else {
4998 // Cache the drag description when the operation starts, then fill it in
4999 // on subsequent calls as a convenience
5000 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005001 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005002 mDragDescription = event.mClipDescription;
5003 } else {
5004 event.mClipDescription = mDragDescription;
5005 }
5006
5007 // For events with a [screen] location, translate into window coordinates
5008 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5009 mDragPoint.set(event.mX, event.mY);
5010 if (mTranslator != null) {
5011 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5012 }
5013
5014 if (mCurScrollY != 0) {
5015 mDragPoint.offset(0, mCurScrollY);
5016 }
5017
5018 event.mX = mDragPoint.x;
5019 event.mY = mDragPoint.y;
5020 }
5021
5022 // Remember who the current drag target is pre-dispatch
5023 final View prevDragView = mCurrentDragView;
5024
5025 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005026 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005027
5028 // If we changed apparent drag target, tell the OS about it
5029 if (prevDragView != mCurrentDragView) {
5030 try {
5031 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005032 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005033 }
5034 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005035 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005036 }
5037 } catch (RemoteException e) {
5038 Slog.e(TAG, "Unable to note drag target change");
5039 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005040 }
Chris Tated4533f12010-10-19 15:15:08 -07005041
Christopher Tate407b4e92010-11-30 17:14:08 -08005042 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005043 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005044 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005045 try {
5046 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005047 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005048 } catch (RemoteException e) {
5049 Log.e(TAG, "Unable to report drop result");
5050 }
5051 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005052
5053 // When the drag operation ends, release any local state object
5054 // that may have been in use
5055 if (what == DragEvent.ACTION_DRAG_ENDED) {
5056 setLocalDragState(null);
5057 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005058 }
5059 }
5060 event.recycle();
5061 }
5062
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005063 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5064 if (mSeq != args.seq) {
5065 // The sequence has changed, so we need to update our value and make
5066 // sure to do a traversal afterward so the window manager is given our
5067 // most recent data.
5068 mSeq = args.seq;
5069 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005070 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005071 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005072 if (mView == null) return;
5073 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005074 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005075 }
Dianne Hackborncf675782012-05-10 15:07:24 -07005076 if (mAttachInfo != null) {
5077 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5078 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5079 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5080 mView.dispatchSystemUiVisibilityChanged(visibility);
5081 }
5082 }
Joe Onorato664644d2011-01-23 17:53:23 -08005083 }
5084
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005085 public void handleDispatchDoneAnimating() {
5086 if (mWindowsAnimating) {
5087 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07005088 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005089 scheduleTraversals();
5090 }
5091 }
5092 }
5093
Christopher Tate2c095f32010-10-04 14:13:40 -07005094 public void getLastTouchPoint(Point outLocation) {
5095 outLocation.x = (int) mLastTouchPoint.x;
5096 outLocation.y = (int) mLastTouchPoint.y;
5097 }
5098
Chris Tate9d1ab882010-11-02 15:55:39 -07005099 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005100 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005101 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005102 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005103 }
5104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005105 private AudioManager getAudioManager() {
5106 if (mView == null) {
5107 throw new IllegalStateException("getAudioManager called when there is no mView");
5108 }
5109 if (mAudioManager == null) {
5110 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5111 }
5112 return mAudioManager;
5113 }
5114
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005115 public AccessibilityInteractionController getAccessibilityInteractionController() {
5116 if (mView == null) {
5117 throw new IllegalStateException("getAccessibilityInteractionController"
5118 + " called when there is no mView");
5119 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005120 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005121 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005122 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005123 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005124 }
5125
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005126 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5127 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005128
5129 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005130 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005131 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005132 restore = true;
5133 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005134 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005135 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005136 if (params != null) {
5137 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005138 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005139 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005140 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005141 if (params != null && mOrigWindowType != params.type) {
5142 // For compatibility with old apps, don't crash here.
5143 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
5144 Slog.w(TAG, "Window type can not be changed after "
5145 + "the window is added; ignoring change of " + mView);
5146 params.type = mOrigWindowType;
5147 }
5148 }
Jeff Brown98365d72012-08-19 20:30:52 -07005149 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005150 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005151 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5152 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005153 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005154 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005155 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005156 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005157 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005158 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005159 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005160
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005161 if (mTranslator != null) {
5162 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005163 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005164 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5165 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005166 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005167 return relayoutResult;
5168 }
Romain Guy8506ab42009-06-11 17:35:47 -07005169
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005170 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005171 * {@inheritDoc}
5172 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005173 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005174 public void playSoundEffect(int effectId) {
5175 checkThread();
5176
Dan Morrille4d9a012013-03-28 18:10:43 -07005177 if (mMediaDisabled) {
5178 return;
5179 }
5180
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005181 try {
5182 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005184 switch (effectId) {
5185 case SoundEffectConstants.CLICK:
5186 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5187 return;
5188 case SoundEffectConstants.NAVIGATION_DOWN:
5189 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5190 return;
5191 case SoundEffectConstants.NAVIGATION_LEFT:
5192 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5193 return;
5194 case SoundEffectConstants.NAVIGATION_RIGHT:
5195 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5196 return;
5197 case SoundEffectConstants.NAVIGATION_UP:
5198 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5199 return;
5200 default:
5201 throw new IllegalArgumentException("unknown effect id " + effectId +
5202 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5203 }
5204 } catch (IllegalStateException e) {
5205 // Exception thrown by getAudioManager() when mView is null
5206 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5207 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 }
5209 }
5210
5211 /**
5212 * {@inheritDoc}
5213 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005214 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005215 public boolean performHapticFeedback(int effectId, boolean always) {
5216 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005217 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005218 } catch (RemoteException e) {
5219 return false;
5220 }
5221 }
5222
5223 /**
5224 * {@inheritDoc}
5225 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005226 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005227 public View focusSearch(View focused, int direction) {
5228 checkThread();
5229 if (!(mView instanceof ViewGroup)) {
5230 return null;
5231 }
5232 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5233 }
5234
5235 public void debug() {
5236 mView.debug();
5237 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005238
Jeff Brown5182c782013-10-15 20:31:52 -07005239 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5240 String innerPrefix = prefix + " ";
5241 writer.print(prefix); writer.println("ViewRoot:");
5242 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5243 writer.print(" mRemoved="); writer.println(mRemoved);
5244 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5245 writer.println(mConsumeBatchedInputScheduled);
5246 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5247 writer.println(mPendingInputEventCount);
5248 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5249 writer.println(mProcessInputEventsScheduled);
5250 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5251 writer.print(mTraversalScheduled);
5252 if (mTraversalScheduled) {
5253 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5254 } else {
5255 writer.println();
5256 }
5257 mFirstInputStage.dump(innerPrefix, writer);
5258
5259 mChoreographer.dump(prefix, writer);
5260
5261 writer.print(prefix); writer.println("View Hierarchy:");
5262 dumpViewHierarchy(innerPrefix, writer, mView);
5263 }
5264
5265 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5266 writer.print(prefix);
5267 if (view == null) {
5268 writer.println("null");
5269 return;
5270 }
5271 writer.println(view.toString());
5272 if (!(view instanceof ViewGroup)) {
5273 return;
5274 }
5275 ViewGroup grp = (ViewGroup)view;
5276 final int N = grp.getChildCount();
5277 if (N <= 0) {
5278 return;
5279 }
5280 prefix = prefix + " ";
5281 for (int i=0; i<N; i++) {
5282 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5283 }
5284 }
5285
Romain Guy211370f2012-02-01 16:10:55 -08005286 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005287 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005288 if (mView != null) {
5289 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005290 }
5291 }
5292
Romain Guya998dff2012-03-23 18:58:36 -07005293 private static void getGfxInfo(View view, int[] info) {
Romain Guy65b345f2011-07-27 18:51:50 -07005294 DisplayList displayList = view.mDisplayList;
5295 info[0]++;
5296 if (displayList != null) {
5297 info[1] += displayList.getSize();
5298 }
5299
5300 if (view instanceof ViewGroup) {
5301 ViewGroup group = (ViewGroup) view;
5302
5303 int count = group.getChildCount();
5304 for (int i = 0; i < count; i++) {
5305 getGfxInfo(group.getChildAt(i), info);
5306 }
5307 }
5308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309
Craig Mautner8f303ad2013-06-14 11:32:22 -07005310 /**
5311 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5312 * @return True, request has been queued. False, request has been completed.
5313 */
5314 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005315 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5316 // done by dispatchDetachedFromWindow will cause havoc on return.
5317 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005318 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005319 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005320 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005321
5322 if (!mIsDrawing) {
5323 destroyHardwareRenderer();
5324 } else {
5325 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5326 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5327 }
5328 mHandler.sendEmptyMessage(MSG_DIE);
5329 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005330 }
5331
5332 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005333 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005334 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005335 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005336 if (mRemoved) {
5337 return;
5338 }
5339 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005340 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005341 dispatchDetachedFromWindow();
5342 }
5343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005344 if (mAdded && !mFirst) {
Romain Guyfbb93fa2012-12-03 18:50:35 -08005345 invalidateDisplayLists();
Romain Guy29d89972010-09-22 16:10:57 -07005346 destroyHardwareRenderer();
5347
Romain Guyedbca122012-04-04 18:25:53 -07005348 if (mView != null) {
5349 int viewVisibility = mView.getVisibility();
5350 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5351 if (mWindowAttributesChanged || viewVisibilityChanged) {
5352 // If layout params have been changed, first give them
5353 // to the window manager to make sure it has the correct
5354 // animation info.
5355 try {
5356 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005357 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5358 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005359 }
5360 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005363
Romain Guyedbca122012-04-04 18:25:53 -07005364 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005366 }
Romain Guyedbca122012-04-04 18:25:53 -07005367
5368 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005369 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005370 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005371 }
5372
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005373 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005374 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5375 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005376 }
5377
Dianne Hackborna53de062012-05-08 18:53:51 -07005378 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005379 mHandler.post(new Runnable() {
5380 @Override
5381 public void run() {
5382 // Profiling
5383 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5384 profileRendering(mAttachInfo.mHasWindowFocus);
5385
Dan Morrille4d9a012013-03-28 18:10:43 -07005386 // Media (used by sound effects)
5387 mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
5388
Romain Guy5bb3c732012-11-29 17:52:58 -08005389 // Hardware rendering
5390 if (mAttachInfo.mHardwareRenderer != null) {
5391 if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mHolder.getSurface())) {
5392 invalidate();
5393 }
5394 }
5395
5396 // Layout debugging
5397 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5398 if (layout != mAttachInfo.mDebugLayout) {
5399 mAttachInfo.mDebugLayout = layout;
5400 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5401 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5402 }
5403 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005404 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005405 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005406 }
5407
Romain Guy29d89972010-09-22 16:10:57 -07005408 private void destroyHardwareRenderer() {
Romain Guya998dff2012-03-23 18:58:36 -07005409 AttachInfo attachInfo = mAttachInfo;
5410 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
5411
5412 if (hardwareRenderer != null) {
5413 if (mView != null) {
5414 hardwareRenderer.destroyHardwareResources(mView);
5415 }
5416 hardwareRenderer.destroy(true);
5417 hardwareRenderer.setRequested(false);
5418
5419 attachInfo.mHardwareRenderer = null;
5420 attachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005421 }
5422 }
5423
Jeff Browna175a5b2012-02-15 19:18:31 -08005424 public void dispatchFinishInputConnection(InputConnection connection) {
5425 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5426 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005427 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005428
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005429 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08005430 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005431 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5432 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005433 + " visibleInsets=" + visibleInsets.toShortString()
5434 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005435 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005436 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005437 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005438 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005439 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005440 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005441 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005442 SomeArgs args = SomeArgs.obtain();
5443 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5444 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5445 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5446 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5447 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005448 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005449 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005450 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005451 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005452
Craig Mautner5702d4d2012-06-30 14:10:16 -07005453 public void dispatchMoved(int newX, int newY) {
5454 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5455 if (mTranslator != null) {
5456 PointF point = new PointF(newX, newY);
5457 mTranslator.translatePointInScreenToAppWindow(point);
5458 newX = (int) (point.x + 0.5);
5459 newY = (int) (point.y + 0.5);
5460 }
5461 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5462 mHandler.sendMessage(msg);
5463 }
5464
Jeff Brown4952dfd2011-11-30 19:23:22 -08005465 /**
5466 * Represents a pending input event that is waiting in a queue.
5467 *
5468 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005469 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005470 * one input event to the application at a time and waits for the application
5471 * to finish handling it before delivering the next one.
5472 *
5473 * However, because the application or IME can synthesize and inject multiple
5474 * key events at a time without going through the input dispatcher, we end up
5475 * needing a queue on the application's side.
5476 */
5477 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005478 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5479 public static final int FLAG_DEFERRED = 1 << 1;
5480 public static final int FLAG_FINISHED = 1 << 2;
5481 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5482 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005483
5484 public QueuedInputEvent mNext;
5485
5486 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005487 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005488 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005489
5490 public boolean shouldSkipIme() {
5491 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5492 return true;
5493 }
5494 return mEvent instanceof MotionEvent
5495 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5496 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005497 }
5498
5499 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005500 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005501 QueuedInputEvent q = mQueuedInputEventPool;
5502 if (q != null) {
5503 mQueuedInputEventPoolSize -= 1;
5504 mQueuedInputEventPool = q.mNext;
5505 q.mNext = null;
5506 } else {
5507 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005508 }
5509
Jeff Brown4952dfd2011-11-30 19:23:22 -08005510 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005511 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005512 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005513 return q;
5514 }
5515
5516 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5517 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005518 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005519
5520 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5521 mQueuedInputEventPoolSize += 1;
5522 q.mNext = mQueuedInputEventPool;
5523 mQueuedInputEventPool = q;
5524 }
5525 }
5526
Jeff Brownf9261d22012-02-03 13:49:15 -08005527 void enqueueInputEvent(InputEvent event) {
5528 enqueueInputEvent(event, null, 0, false);
5529 }
5530
Jeff Brown4952dfd2011-11-30 19:23:22 -08005531 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005532 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005533 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005534
Jeff Brown4952dfd2011-11-30 19:23:22 -08005535 // Always enqueue the input event in order, regardless of its time stamp.
5536 // We do this because the application or the IME may inject key events
5537 // in response to touch events and we want to ensure that the injected keys
5538 // are processed in the order they were received and we cannot trust that
5539 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005540 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005541 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005542 mPendingInputEventHead = q;
5543 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005544 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005545 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005546 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005547 }
Michael Wright95ae9422013-03-14 10:58:50 -07005548 mPendingInputEventCount += 1;
5549 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5550 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005551
Jeff Brownf9261d22012-02-03 13:49:15 -08005552 if (processImmediately) {
5553 doProcessInputEvents();
5554 } else {
5555 scheduleProcessInputEvents();
5556 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005557 }
5558
5559 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005560 if (!mProcessInputEventsScheduled) {
5561 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005562 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5563 msg.setAsynchronous(true);
5564 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005565 }
5566 }
5567
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005568 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005569 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005570 while (mPendingInputEventHead != null) {
5571 QueuedInputEvent q = mPendingInputEventHead;
5572 mPendingInputEventHead = q.mNext;
5573 if (mPendingInputEventHead == null) {
5574 mPendingInputEventTail = null;
5575 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005576 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005577
Michael Wright95ae9422013-03-14 10:58:50 -07005578 mPendingInputEventCount -= 1;
5579 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5580 mPendingInputEventCount);
5581
Jeff Brownf9e989d2013-04-04 23:04:03 -07005582 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005583 }
5584
5585 // We are done processing all input events that we can process right now
5586 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005587 if (mProcessInputEventsScheduled) {
5588 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005589 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005590 }
5591 }
5592
Jeff Brownf9e989d2013-04-04 23:04:03 -07005593 private void deliverInputEvent(QueuedInputEvent q) {
5594 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
5595 try {
5596 if (mInputEventConsistencyVerifier != null) {
5597 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5598 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005599
Jeff Brownf9e989d2013-04-04 23:04:03 -07005600 InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5601 if (stage != null) {
5602 stage.deliver(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005603 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005604 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005605 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005606 } finally {
5607 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Michael Wrightbf020962013-03-28 17:27:50 -07005608 }
Michael Wrightbf020962013-03-28 17:27:50 -07005609 }
5610
Jeff Brownf9e989d2013-04-04 23:04:03 -07005611 private void finishInputEvent(QueuedInputEvent q) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005612 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005613 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005614 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005615 } else {
5616 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005617 }
5618
5619 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005620 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005621
Jeff Brownf9e989d2013-04-04 23:04:03 -07005622 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005623 if (event instanceof KeyEvent) {
5624 final KeyEvent keyEvent = (KeyEvent)event;
5625 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5626 } else {
5627 final MotionEvent motionEvent = (MotionEvent)event;
5628 final int action = motionEvent.getAction();
5629 return action == MotionEvent.ACTION_UP
5630 || action == MotionEvent.ACTION_CANCEL
5631 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005632 }
5633 }
5634
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005635 void scheduleConsumeBatchedInput() {
5636 if (!mConsumeBatchedInputScheduled) {
5637 mConsumeBatchedInputScheduled = true;
5638 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5639 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005640 }
5641 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005642
5643 void unscheduleConsumeBatchedInput() {
5644 if (mConsumeBatchedInputScheduled) {
5645 mConsumeBatchedInputScheduled = false;
5646 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5647 mConsumedBatchedInputRunnable, null);
5648 }
5649 }
5650
Jeff Brown771526c2012-04-27 15:13:25 -07005651 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005652 if (mConsumeBatchedInputScheduled) {
5653 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005654 if (mInputEventReceiver != null) {
Michael Wright62ce65d2013-10-25 14:50:36 -07005655 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)) {
5656 // If we consumed a batch here, we want to go ahead and schedule the
5657 // consumption of batched input events on the next frame. Otherwise, we would
5658 // wait until we have more input events pending and might get starved by other
5659 // things occurring in the process.
5660 scheduleConsumeBatchedInput();
5661 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005662 }
Jeff Brown330314c2012-04-27 02:20:22 -07005663 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005664 }
5665 }
5666
5667 final class TraversalRunnable implements Runnable {
5668 @Override
5669 public void run() {
5670 doTraversal();
5671 }
5672 }
5673 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005674
Jeff Brown32cbc38552011-12-01 14:01:49 -08005675 final class WindowInputEventReceiver extends InputEventReceiver {
5676 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5677 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005678 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005679
5680 @Override
5681 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005682 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005683 }
Jeff Brown072ec962012-02-07 14:46:57 -08005684
5685 @Override
5686 public void onBatchedInputEventPending() {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005687 scheduleConsumeBatchedInput();
5688 }
5689
5690 @Override
5691 public void dispose() {
5692 unscheduleConsumeBatchedInput();
5693 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005694 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005695 }
5696 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005697
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005698 final class ConsumeBatchedInputRunnable implements Runnable {
5699 @Override
5700 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005701 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005702 }
5703 }
5704 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5705 new ConsumeBatchedInputRunnable();
5706 boolean mConsumeBatchedInputScheduled;
5707
Jeff Brown6cb7b462012-03-05 13:21:17 -08005708 final class InvalidateOnAnimationRunnable implements Runnable {
5709 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005710 private final ArrayList<View> mViews = new ArrayList<View>();
5711 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08005712 new ArrayList<AttachInfo.InvalidateInfo>();
5713 private View[] mTempViews;
5714 private AttachInfo.InvalidateInfo[] mTempViewRects;
5715
5716 public void addView(View view) {
5717 synchronized (this) {
5718 mViews.add(view);
5719 postIfNeededLocked();
5720 }
5721 }
5722
5723 public void addViewRect(AttachInfo.InvalidateInfo info) {
5724 synchronized (this) {
5725 mViewRects.add(info);
5726 postIfNeededLocked();
5727 }
5728 }
5729
5730 public void removeView(View view) {
5731 synchronized (this) {
5732 mViews.remove(view);
5733
5734 for (int i = mViewRects.size(); i-- > 0; ) {
5735 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5736 if (info.target == view) {
5737 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005738 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005739 }
5740 }
5741
5742 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005743 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005744 mPosted = false;
5745 }
5746 }
5747 }
5748
5749 @Override
5750 public void run() {
5751 final int viewCount;
5752 final int viewRectCount;
5753 synchronized (this) {
5754 mPosted = false;
5755
5756 viewCount = mViews.size();
5757 if (viewCount != 0) {
5758 mTempViews = mViews.toArray(mTempViews != null
5759 ? mTempViews : new View[viewCount]);
5760 mViews.clear();
5761 }
5762
5763 viewRectCount = mViewRects.size();
5764 if (viewRectCount != 0) {
5765 mTempViewRects = mViewRects.toArray(mTempViewRects != null
5766 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
5767 mViewRects.clear();
5768 }
5769 }
5770
5771 for (int i = 0; i < viewCount; i++) {
5772 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07005773 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08005774 }
5775
5776 for (int i = 0; i < viewRectCount; i++) {
5777 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
5778 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005779 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005780 }
5781 }
5782
5783 private void postIfNeededLocked() {
5784 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005785 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005786 mPosted = true;
5787 }
5788 }
5789 }
5790 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
5791 new InvalidateOnAnimationRunnable();
5792
Jeff Browna175a5b2012-02-15 19:18:31 -08005793 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
5794 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
5795 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5796 }
5797
Jeff Browna175a5b2012-02-15 19:18:31 -08005798 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
5799 long delayMilliseconds) {
5800 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
5801 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5802 }
5803
Jeff Brown6cb7b462012-03-05 13:21:17 -08005804 public void dispatchInvalidateOnAnimation(View view) {
5805 mInvalidateOnAnimationRunnable.addView(view);
5806 }
5807
5808 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
5809 mInvalidateOnAnimationRunnable.addViewRect(info);
5810 }
5811
Romain Guy2a0f2282012-05-08 14:43:12 -07005812 public void enqueueDisplayList(DisplayList displayList) {
Romain Guy51e4d4d2012-03-15 18:30:47 -07005813 mDisplayLists.add(displayList);
Romain Guy2a0f2282012-05-08 14:43:12 -07005814 }
5815
Jeff Brown6cb7b462012-03-05 13:21:17 -08005816 public void cancelInvalidate(View view) {
5817 mHandler.removeMessages(MSG_INVALIDATE, view);
5818 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
5819 // them to the pool
5820 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
5821 mInvalidateOnAnimationRunnable.removeView(view);
5822 }
5823
keunyoung30f420f2013-08-02 14:23:10 -07005824 public void dispatchInputEvent(InputEvent event) {
5825 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005826 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005827 mHandler.sendMessage(msg);
5828 }
5829
5830 public void dispatchKeyFromIme(KeyEvent event) {
5831 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005832 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005833 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08005834 }
5835
John Reckd6b10982012-04-19 18:01:35 -07005836 public void dispatchUnhandledKey(KeyEvent event) {
5837 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
5838 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5839 final int keyCode = event.getKeyCode();
5840 final int metaState = event.getMetaState();
5841
Jeff Brownfd23e3e2012-05-09 13:34:28 -07005842 // Check for fallback actions specified by the key character map.
5843 KeyCharacterMap.FallbackAction fallbackAction =
5844 kcm.getFallbackAction(keyCode, metaState);
5845 if (fallbackAction != null) {
5846 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5847 KeyEvent fallbackEvent = KeyEvent.obtain(
5848 event.getDownTime(), event.getEventTime(),
5849 event.getAction(), fallbackAction.keyCode,
5850 event.getRepeatCount(), fallbackAction.metaState,
5851 event.getDeviceId(), event.getScanCode(),
5852 flags, event.getSource(), null);
5853 fallbackAction.recycle();
5854
keunyoung30f420f2013-08-02 14:23:10 -07005855 dispatchInputEvent(fallbackEvent);
John Reckd6b10982012-04-19 18:01:35 -07005856 }
5857 }
5858 }
5859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005860 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005861 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005862 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005863 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005864 }
5865
Romain Guybb9908b2012-03-08 11:14:07 -08005866 public void dispatchScreenStateChange(boolean on) {
5867 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
Romain Guy7e4e5612012-03-05 14:37:29 -08005868 msg.arg1 = on ? 1 : 0;
5869 mHandler.sendMessage(msg);
5870 }
5871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005872 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08005873 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
5874 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005875 }
5876
5877 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
5878 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005879 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005880 msg.arg1 = hasFocus ? 1 : 0;
5881 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005882 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005883 }
5884
Dianne Hackbornffa42482009-09-23 22:20:11 -07005885 public void dispatchCloseSystemDialogs(String reason) {
5886 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005887 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07005888 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08005889 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07005890 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005891
5892 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07005893 final int what;
5894 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005895 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
5896 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07005897 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08005898 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07005899 }
Jeff Browna175a5b2012-02-15 19:18:31 -08005900 Message msg = mHandler.obtainMessage(what, event);
5901 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07005902 }
5903
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005904 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
5905 int localValue, int localChanges) {
5906 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
5907 args.seq = seq;
5908 args.globalVisibility = globalVisibility;
5909 args.localValue = localValue;
5910 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08005911 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
5912 }
5913
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005914 public void dispatchDoneAnimating() {
5915 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
5916 }
5917
Jeff Browna175a5b2012-02-15 19:18:31 -08005918 public void dispatchCheckFocus() {
5919 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
5920 // This will result in a call to checkFocus() below.
5921 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
5922 }
Joe Onorato664644d2011-01-23 17:53:23 -08005923 }
5924
svetoslavganov75986cf2009-05-14 22:28:01 -07005925 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005926 * Post a callback to send a
5927 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07005928 * This event is send at most once every
5929 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005930 */
Alan Viverette77e9a282013-09-12 17:16:09 -07005931 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005932 if (mSendWindowContentChangedAccessibilityEvent == null) {
5933 mSendWindowContentChangedAccessibilityEvent =
5934 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005935 }
Alan Viverette77e9a282013-09-12 17:16:09 -07005936 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005937 }
5938
5939 /**
5940 * Remove a posted callback to send a
5941 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
5942 */
5943 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005944 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005945 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005946 }
5947 }
5948
Igor Murashkina86ab6402013-08-30 12:58:36 -07005949 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005950 public boolean showContextMenuForChild(View originalView) {
5951 return false;
5952 }
5953
Igor Murashkina86ab6402013-08-30 12:58:36 -07005954 @Override
Adam Powell6e346362010-07-23 10:18:23 -07005955 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
5956 return null;
5957 }
5958
Igor Murashkina86ab6402013-08-30 12:58:36 -07005959 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005960 public void createContextMenu(ContextMenu menu) {
5961 }
5962
Igor Murashkina86ab6402013-08-30 12:58:36 -07005963 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005964 public void childDrawableStateChanged(View child) {
5965 }
5966
Igor Murashkina86ab6402013-08-30 12:58:36 -07005967 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005968 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
5969 if (mView == null) {
5970 return false;
5971 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005972 // Intercept accessibility focus events fired by virtual nodes to keep
5973 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005974 final int eventType = event.getEventType();
5975 switch (eventType) {
5976 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005977 final long sourceNodeId = event.getSourceNodeId();
5978 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5979 sourceNodeId);
5980 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5981 if (source != null) {
5982 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5983 if (provider != null) {
5984 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
5985 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
5986 setAccessibilityFocus(source, node);
5987 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005988 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005989 } break;
5990 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005991 final long sourceNodeId = event.getSourceNodeId();
5992 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5993 sourceNodeId);
5994 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5995 if (source != null) {
5996 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5997 if (provider != null) {
5998 setAccessibilityFocus(null, null);
5999 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006000 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006001 } break;
6002 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006003 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006004 return true;
6005 }
6006
Svetoslav Ganov42138042012-03-20 11:51:39 -07006007 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006008 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6009 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006010 }
6011
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006012 @Override
6013 public boolean canResolveLayoutDirection() {
6014 return true;
6015 }
6016
6017 @Override
6018 public boolean isLayoutDirectionResolved() {
6019 return true;
6020 }
6021
6022 @Override
6023 public int getLayoutDirection() {
6024 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6025 }
6026
6027 @Override
6028 public boolean canResolveTextDirection() {
6029 return true;
6030 }
6031
6032 @Override
6033 public boolean isTextDirectionResolved() {
6034 return true;
6035 }
6036
6037 @Override
6038 public int getTextDirection() {
6039 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6040 }
6041
6042 @Override
6043 public boolean canResolveTextAlignment() {
6044 return true;
6045 }
6046
6047 @Override
6048 public boolean isTextAlignmentResolved() {
6049 return true;
6050 }
6051
6052 @Override
6053 public int getTextAlignment() {
6054 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6055 }
6056
Svetoslav Ganov42138042012-03-20 11:51:39 -07006057 private View getCommonPredecessor(View first, View second) {
6058 if (mAttachInfo != null) {
6059 if (mTempHashSet == null) {
6060 mTempHashSet = new HashSet<View>();
6061 }
6062 HashSet<View> seen = mTempHashSet;
6063 seen.clear();
6064 View firstCurrent = first;
6065 while (firstCurrent != null) {
6066 seen.add(firstCurrent);
6067 ViewParent firstCurrentParent = firstCurrent.mParent;
6068 if (firstCurrentParent instanceof View) {
6069 firstCurrent = (View) firstCurrentParent;
6070 } else {
6071 firstCurrent = null;
6072 }
6073 }
6074 View secondCurrent = second;
6075 while (secondCurrent != null) {
6076 if (seen.contains(secondCurrent)) {
6077 seen.clear();
6078 return secondCurrent;
6079 }
6080 ViewParent secondCurrentParent = secondCurrent.mParent;
6081 if (secondCurrentParent instanceof View) {
6082 secondCurrent = (View) secondCurrentParent;
6083 } else {
6084 secondCurrent = null;
6085 }
6086 }
6087 seen.clear();
6088 }
6089 return null;
6090 }
6091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006092 void checkThread() {
6093 if (mThread != Thread.currentThread()) {
6094 throw new CalledFromWrongThreadException(
6095 "Only the original thread that created a view hierarchy can touch its views.");
6096 }
6097 }
6098
Igor Murashkina86ab6402013-08-30 12:58:36 -07006099 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006100 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006101 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006102 }
6103
Igor Murashkina86ab6402013-08-30 12:58:36 -07006104 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006105 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
6106 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
6107 if (rectangle != null) {
6108 mTempRect.set(rectangle);
6109 mTempRect.offset(0, -mCurScrollY);
6110 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6111 try {
6112 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
6113 } catch (RemoteException re) {
6114 /* ignore */
6115 }
6116 }
6117 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006118 }
Romain Guy8506ab42009-06-11 17:35:47 -07006119
Igor Murashkina86ab6402013-08-30 12:58:36 -07006120 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006121 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6122 // Do nothing.
6123 }
6124
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006125 void changeCanvasOpacity(boolean opaque) {
6126 // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
6127 Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
6128 }
6129
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006130 class TakenSurfaceHolder extends BaseSurfaceHolder {
6131 @Override
6132 public boolean onAllowLockCanvas() {
6133 return mDrawingAllowed;
6134 }
6135
6136 @Override
6137 public void onRelayoutContainer() {
6138 // Not currently interesting -- from changing between fixed and layout size.
6139 }
6140
Igor Murashkina86ab6402013-08-30 12:58:36 -07006141 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006142 public void setFormat(int format) {
6143 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6144 }
6145
Igor Murashkina86ab6402013-08-30 12:58:36 -07006146 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006147 public void setType(int type) {
6148 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6149 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006150
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006151 @Override
6152 public void onUpdateSurface() {
6153 // We take care of format and type changes on our own.
6154 throw new IllegalStateException("Shouldn't be here");
6155 }
6156
Igor Murashkina86ab6402013-08-30 12:58:36 -07006157 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006158 public boolean isCreating() {
6159 return mIsCreating;
6160 }
6161
6162 @Override
6163 public void setFixedSize(int width, int height) {
6164 throw new UnsupportedOperationException(
6165 "Currently only support sizing from layout");
6166 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006167
6168 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006169 public void setKeepScreenOn(boolean screenOn) {
6170 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6171 }
6172 }
Romain Guy8506ab42009-06-11 17:35:47 -07006173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006174 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006175 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006176 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006177
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006178 W(ViewRootImpl viewAncestor) {
6179 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006180 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006181 }
6182
Igor Murashkina86ab6402013-08-30 12:58:36 -07006183 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006184 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -07006185 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006186 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006187 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006188 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07006189 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006190 }
6191 }
6192
Craig Mautner5702d4d2012-06-30 14:10:16 -07006193 @Override
6194 public void moved(int newX, int newY) {
6195 final ViewRootImpl viewAncestor = mViewAncestor.get();
6196 if (viewAncestor != null) {
6197 viewAncestor.dispatchMoved(newX, newY);
6198 }
6199 }
6200
Igor Murashkina86ab6402013-08-30 12:58:36 -07006201 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006202 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006203 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006204 if (viewAncestor != null) {
6205 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006206 }
6207 }
6208
Igor Murashkina86ab6402013-08-30 12:58:36 -07006209 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08006210 public void dispatchScreenState(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -08006211 final ViewRootImpl viewAncestor = mViewAncestor.get();
6212 if (viewAncestor != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08006213 viewAncestor.dispatchScreenStateChange(on);
Romain Guy7e4e5612012-03-05 14:37:29 -08006214 }
6215 }
Romain Guybb9908b2012-03-08 11:14:07 -08006216
Igor Murashkina86ab6402013-08-30 12:58:36 -07006217 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006218 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006219 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006220 if (viewAncestor != null) {
6221 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006222 }
6223 }
6224
Igor Murashkina86ab6402013-08-30 12:58:36 -07006225 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006226 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006227 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006228 if (viewAncestor != null) {
6229 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006230 }
6231 }
6232
6233 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006234 try {
6235 return ActivityManagerNative.getDefault().checkPermission(
6236 permission, Binder.getCallingPid(), Binder.getCallingUid());
6237 } catch (RemoteException e) {
6238 return PackageManager.PERMISSION_DENIED;
6239 }
6240 }
6241
Igor Murashkina86ab6402013-08-30 12:58:36 -07006242 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006243 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006244 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006245 if (viewAncestor != null) {
6246 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006247 if (view != null) {
6248 if (checkCallingPermission(Manifest.permission.DUMP) !=
6249 PackageManager.PERMISSION_GRANTED) {
6250 throw new SecurityException("Insufficient permissions to invoke"
6251 + " executeCommand() from pid=" + Binder.getCallingPid()
6252 + ", uid=" + Binder.getCallingUid());
6253 }
6254
6255 OutputStream clientStream = null;
6256 try {
6257 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6258 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6259 } catch (IOException e) {
6260 e.printStackTrace();
6261 } finally {
6262 if (clientStream != null) {
6263 try {
6264 clientStream.close();
6265 } catch (IOException e) {
6266 e.printStackTrace();
6267 }
6268 }
6269 }
6270 }
6271 }
6272 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006273
6274 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006275 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006276 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006277 if (viewAncestor != null) {
6278 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006279 }
6280 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006281
6282 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006283 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6284 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006285 if (sync) {
6286 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006287 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006288 } catch (RemoteException e) {
6289 }
6290 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006291 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006292
Igor Murashkina86ab6402013-08-30 12:58:36 -07006293 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07006294 public void dispatchWallpaperCommand(String action, int x, int y,
6295 int z, Bundle extras, boolean sync) {
6296 if (sync) {
6297 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006298 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006299 } catch (RemoteException e) {
6300 }
6301 }
6302 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006303
6304 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006305 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07006306 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006307 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006308 if (viewAncestor != null) {
6309 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006310 }
6311 }
Joe Onorato664644d2011-01-23 17:53:23 -08006312
Igor Murashkina86ab6402013-08-30 12:58:36 -07006313 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006314 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6315 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006316 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006317 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006318 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6319 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006320 }
6321 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006322
Igor Murashkina86ab6402013-08-30 12:58:36 -07006323 @Override
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006324 public void doneAnimating() {
6325 final ViewRootImpl viewAncestor = mViewAncestor.get();
6326 if (viewAncestor != null) {
6327 viewAncestor.dispatchDoneAnimating();
6328 }
6329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006330 }
6331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006332 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6333 public CalledFromWrongThreadException(String msg) {
6334 super(msg);
6335 }
6336 }
6337
Igor Murashkina86ab6402013-08-30 12:58:36 -07006338 private final SurfaceHolder mHolder = new SurfaceHolder() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006339 // we only need a SurfaceHolder for opengl. it would be nice
6340 // to implement everything else though, especially the callback
6341 // support (opengl doesn't make use of it right now, but eventually
6342 // will).
Igor Murashkina86ab6402013-08-30 12:58:36 -07006343 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006344 public Surface getSurface() {
6345 return mSurface;
6346 }
6347
Igor Murashkina86ab6402013-08-30 12:58:36 -07006348 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006349 public boolean isCreating() {
6350 return false;
6351 }
6352
Igor Murashkina86ab6402013-08-30 12:58:36 -07006353 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006354 public void addCallback(Callback callback) {
6355 }
6356
Igor Murashkina86ab6402013-08-30 12:58:36 -07006357 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006358 public void removeCallback(Callback callback) {
6359 }
6360
Igor Murashkina86ab6402013-08-30 12:58:36 -07006361 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006362 public void setFixedSize(int width, int height) {
6363 }
6364
Igor Murashkina86ab6402013-08-30 12:58:36 -07006365 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006366 public void setSizeFromLayout() {
6367 }
6368
Igor Murashkina86ab6402013-08-30 12:58:36 -07006369 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006370 public void setFormat(int format) {
6371 }
6372
Igor Murashkina86ab6402013-08-30 12:58:36 -07006373 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006374 public void setType(int type) {
6375 }
6376
Igor Murashkina86ab6402013-08-30 12:58:36 -07006377 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006378 public void setKeepScreenOn(boolean screenOn) {
6379 }
6380
Igor Murashkina86ab6402013-08-30 12:58:36 -07006381 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006382 public Canvas lockCanvas() {
6383 return null;
6384 }
6385
Igor Murashkina86ab6402013-08-30 12:58:36 -07006386 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006387 public Canvas lockCanvas(Rect dirty) {
6388 return null;
6389 }
6390
Igor Murashkina86ab6402013-08-30 12:58:36 -07006391 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006392 public void unlockCanvasAndPost(Canvas canvas) {
6393 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006394 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006395 public Rect getSurfaceFrame() {
6396 return null;
6397 }
6398 };
6399
6400 static RunQueue getRunQueue() {
6401 RunQueue rq = sRunQueues.get();
6402 if (rq != null) {
6403 return rq;
6404 }
6405 rq = new RunQueue();
6406 sRunQueues.set(rq);
6407 return rq;
6408 }
Romain Guy8506ab42009-06-11 17:35:47 -07006409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006410 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08006411 * The run queue is used to enqueue pending work from Views when no Handler is
6412 * attached. The work is executed during the next call to performTraversals on
6413 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006414 * @hide
6415 */
6416 static final class RunQueue {
6417 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
6418
6419 void post(Runnable action) {
6420 postDelayed(action, 0);
6421 }
6422
6423 void postDelayed(Runnable action, long delayMillis) {
6424 HandlerAction handlerAction = new HandlerAction();
6425 handlerAction.action = action;
6426 handlerAction.delay = delayMillis;
6427
6428 synchronized (mActions) {
6429 mActions.add(handlerAction);
6430 }
6431 }
6432
6433 void removeCallbacks(Runnable action) {
6434 final HandlerAction handlerAction = new HandlerAction();
6435 handlerAction.action = action;
6436
6437 synchronized (mActions) {
6438 final ArrayList<HandlerAction> actions = mActions;
6439
6440 while (actions.remove(handlerAction)) {
6441 // Keep going
6442 }
6443 }
6444 }
6445
6446 void executeActions(Handler handler) {
6447 synchronized (mActions) {
6448 final ArrayList<HandlerAction> actions = mActions;
6449 final int count = actions.size();
6450
6451 for (int i = 0; i < count; i++) {
6452 final HandlerAction handlerAction = actions.get(i);
6453 handler.postDelayed(handlerAction.action, handlerAction.delay);
6454 }
6455
Romain Guy15df6702009-08-17 20:17:30 -07006456 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006457 }
6458 }
6459
6460 private static class HandlerAction {
6461 Runnable action;
6462 long delay;
6463
6464 @Override
6465 public boolean equals(Object o) {
6466 if (this == o) return true;
6467 if (o == null || getClass() != o.getClass()) return false;
6468
6469 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006470 return !(action != null ? !action.equals(that.action) : that.action != null);
6471
6472 }
6473
6474 @Override
6475 public int hashCode() {
6476 int result = action != null ? action.hashCode() : 0;
6477 result = 31 * result + (int) (delay ^ (delay >>> 32));
6478 return result;
6479 }
6480 }
6481 }
6482
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006483 /**
6484 * Class for managing the accessibility interaction connection
6485 * based on the global accessibility state.
6486 */
6487 final class AccessibilityInteractionConnectionManager
6488 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07006489 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006490 public void onAccessibilityStateChanged(boolean enabled) {
6491 if (enabled) {
6492 ensureConnection();
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006493 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6494 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6495 View focusedView = mView.findFocus();
6496 if (focusedView != null && focusedView != mView) {
6497 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6498 }
6499 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006500 } else {
6501 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006502 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006503 }
6504 }
6505
6506 public void ensureConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006507 if (mAttachInfo != null) {
6508 final boolean registered =
6509 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
6510 if (!registered) {
6511 mAttachInfo.mAccessibilityWindowId =
6512 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6513 new AccessibilityInteractionConnection(ViewRootImpl.this));
6514 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006515 }
6516 }
6517
6518 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006519 final boolean registered =
6520 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006521 if (registered) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006522 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006523 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6524 }
6525 }
6526 }
6527
6528 /**
6529 * This class is an interface this ViewAncestor provides to the
6530 * AccessibilityManagerService to the latter can interact with
6531 * the view hierarchy in this ViewAncestor.
6532 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006533 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006534 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006535 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006536
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006537 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6538 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006539 }
6540
Svetoslav Ganov42138042012-03-20 11:51:39 -07006541 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006542 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006543 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006544 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006545 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6546 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006547 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006548 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006549 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6550 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006551 } else {
6552 // We cannot make the call and notify the caller so it does not wait.
6553 try {
6554 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6555 } catch (RemoteException re) {
6556 /* best effort - ignore */
6557 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006558 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006559 }
6560
Svetoslav Ganov42138042012-03-20 11:51:39 -07006561 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006562 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006563 Bundle arguments, int interactionId,
6564 IAccessibilityInteractionConnectionCallback callback, int flags,
6565 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006566 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6567 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006568 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006569 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006570 interactionId, callback, flags, interogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006571 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006572 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006573 try {
6574 callback.setPerformAccessibilityActionResult(false, interactionId);
6575 } catch (RemoteException re) {
6576 /* best effort - ignore */
6577 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006578 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006579 }
6580
Svetoslav Ganov42138042012-03-20 11:51:39 -07006581 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006582 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
6583 String viewId, int interactionId,
6584 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006585 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006586 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6587 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006588 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006589 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
6590 viewId, interactionId, callback, flags, interrogatingPid,
6591 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006592 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006593 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006594 try {
6595 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6596 } catch (RemoteException re) {
6597 /* best effort - ignore */
6598 }
6599 }
6600 }
6601
Svetoslav Ganov42138042012-03-20 11:51:39 -07006602 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006603 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006604 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006605 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006606 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6607 if (viewRootImpl != null && viewRootImpl.mView != null) {
6608 viewRootImpl.getAccessibilityInteractionController()
6609 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006610 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6611 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006612 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006613 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006614 try {
6615 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6616 } catch (RemoteException re) {
6617 /* best effort - ignore */
6618 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006619 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006620 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006621
Svetoslav Ganov42138042012-03-20 11:51:39 -07006622 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006623 public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
Svetoslav Ganov86783472012-06-06 21:12:20 -07006624 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006625 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006626 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6627 if (viewRootImpl != null && viewRootImpl.mView != null) {
6628 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006629 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006630 flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006631 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006632 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006633 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006634 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006635 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006636 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006637 }
6638 }
6639 }
6640
Svetoslav Ganov42138042012-03-20 11:51:39 -07006641 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006642 public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006643 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006644 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006645 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6646 if (viewRootImpl != null && viewRootImpl.mView != null) {
6647 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006648 .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006649 callback, flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006650 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006651 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006652 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006653 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006654 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006655 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006656 }
6657 }
6658 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006659 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006660
Svetoslav Ganova0156172011-06-26 17:55:44 -07006661 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07006662 private int mChangeTypes = 0;
6663
Svetoslav Ganov42138042012-03-20 11:51:39 -07006664 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07006665 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006666
Igor Murashkina86ab6402013-08-30 12:58:36 -07006667 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006668 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07006669 // The accessibility may be turned off while we were waiting so check again.
6670 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6671 mLastEventTimeMillis = SystemClock.uptimeMillis();
6672 AccessibilityEvent event = AccessibilityEvent.obtain();
6673 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07006674 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07006675 mSource.sendAccessibilityEventUnchecked(event);
6676 } else {
6677 mLastEventTimeMillis = 0;
6678 }
6679 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07006680 mSource.resetSubtreeAccessibilityStateChanged();
6681 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07006682 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07006683 }
6684
Alan Viverette77e9a282013-09-12 17:16:09 -07006685 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006686 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006687 // If there is no common predecessor, then mSource points to
6688 // a removed view, hence in this case always prefer the source.
6689 View predecessor = getCommonPredecessor(mSource, source);
6690 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006691 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006692 return;
6693 }
6694 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006695 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006696 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
6697 final long minEventIntevalMillis =
6698 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
6699 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006700 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07006701 run();
6702 } else {
6703 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006704 }
6705 }
6706 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006707}