blob: b0f67ac47c08eab0e6eb615cbb5cf5a7b82cfcb7 [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;
71import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070072
Svetoslav Ganov42138042012-03-20 11:51:39 -070073import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070074import com.android.internal.os.SomeArgs;
Joe Onorato86f67862010-11-05 18:57:34 -070075import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070076import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070077import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import java.io.IOException;
80import java.io.OutputStream;
Romain Guy6b7bd242010-10-06 19:49:23 -070081import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070083import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085/**
86 * The top of a view hierarchy, implementing the needed protocol between View
87 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070088 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 *
90 * {@hide}
91 */
Romain Guy812ccbe2010-06-01 14:07:24 -070092@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -080093public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -080094 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -070095 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -070097 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 /** @noinspection PointlessBooleanExpression*/
99 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
100 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800101 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
103 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
104 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
105 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700106 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700107 private static final boolean DEBUG_FPS = false;
Michael Wrightc8a7e542013-03-20 17:58:33 -0700108 private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
Romain Guy59a12ca2011-06-09 17:48:21 -0700110 /**
111 * Set this system property to true to force the view hierarchy to render
112 * at 60 Hz. This can be used to measure the potential framerate.
113 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700114 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Dan Morrille4d9a012013-03-28 18:10:43 -0700115 private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
Michael Chan53071d62009-05-13 17:29:48 -0700116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 /**
118 * Maximum time we allow the user to roll the trackball enough to generate
119 * a key event, before resetting the counters.
120 */
121 static final int MAX_TRACKBALL_DELAY = 250;
122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
124
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800125 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
126 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700127
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800128 static final ArrayList<ComponentCallbacks> sConfigCallbacks
129 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700130
Jeff Brownf9e989d2013-04-04 23:04:03 -0700131 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700132 final IWindowSession mWindowSession;
133 final Display mDisplay;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800134 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700137
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800138 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 final Thread mThread;
141
142 final WindowLeaked mLocation;
143
144 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
145
146 final W mWindow;
147
Dianne Hackborn180c4842011-09-13 12:39:25 -0700148 final int mTargetSdkVersion;
149
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700150 int mSeq;
151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700153
154 View mAccessibilityFocusedHost;
155 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 int mViewVisibility;
158 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700159 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Dianne Hackbornce418e62011-03-01 14:31:38 -0800161 // Set to true if the owner of this window is in the stopped state,
162 // so the window should no longer be active.
163 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700164
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700165 boolean mLastInCompatMode = false;
166
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700167 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700168 BaseSurfaceHolder mSurfaceHolder;
169 boolean mIsCreating;
170 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 final Region mTransparentRegion;
173 final Region mPreviousTransparentRegion;
174
175 int mWidth;
176 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800177 Rect mDirty;
178 final Rect mCurrentDirty = new Rect();
Romain Guybb93d552009-03-24 21:04:15 -0700179 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700180
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700181 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
183 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700184 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700185 InputQueue.Callback mInputQueueCallback;
186 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700187 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800188 Choreographer mChoreographer;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 final Rect mTempRect; // used in the transaction to not thrash the heap.
191 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
193 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800194 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700196 /** Set to true while in performTraversals for detecting when die(true) is called from internal
197 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
198 boolean mIsInTraversal;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700199 boolean mFitSystemWindowsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 boolean mLayoutRequested;
201 boolean mFirst;
202 boolean mReportNextDraw;
203 boolean mFullRedrawNeeded;
204 boolean mNewSurfaceNeeded;
205 boolean mHasHadWindowFocus;
206 boolean mLastWasImTarget;
Dianne Hackborn12d3a942012-04-27 14:16:30 -0700207 boolean mWindowsAnimating;
Michael Jurkaf42d90102013-05-08 18:00:04 +0200208 boolean mDrawDuringWindowsAnimating;
Romain Guy1f59e5c2012-05-06 14:11:16 -0700209 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700210 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700211 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800212 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800213
214 // Pool of queued input events.
215 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
216 private QueuedInputEvent mQueuedInputEventPool;
217 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800218
Michael Wrightc8a7e542013-03-20 17:58:33 -0700219 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700220 * Pending input events are input events waiting to be delivered to the input stages
221 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700222 */
223 QueuedInputEvent mPendingInputEventHead;
224 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700225 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800226 boolean mProcessInputEventsScheduled;
Michael Wright95ae9422013-03-14 10:58:50 -0700227 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700228
229 InputStage mFirstInputStage;
230 InputStage mFirstPostImeInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231
232 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700233 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234
235 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700236 // Surface can never be reassigned or cleared (use Surface.clear()).
237 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 boolean mAdded;
240 boolean mAddedTouchMode;
241
Craig Mautner48d0d182013-06-11 07:53:06 -0700242 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 // These are accessed by multiple threads.
245 final Rect mWinFrame; // frame given by window manager.
246
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800247 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 final Rect mPendingVisibleInsets = new Rect();
249 final Rect mPendingContentInsets = new Rect();
250 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
251 = new ViewTreeObserver.InternalInsetsInfo();
252
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700253 final Rect mFitSystemWindowsInsets = new Rect();
254
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700255 final Configuration mLastConfiguration = new Configuration();
256 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 boolean mScrollMayChange;
259 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800260 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 int mScrollY;
262 int mCurScrollY;
263 Scroller mScroller;
Romain Guy7d70fbf2011-05-24 17:40:25 -0700264 HardwareLayer mResizeBuffer;
265 long mResizeBufferStartTime;
266 int mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800267 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700268 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700269
Romain Guy8506ab42009-06-11 17:35:47 -0700270 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271
Christopher Tatea53146c2010-09-07 11:57:52 -0700272 /* Drag/drop */
273 ClipDescription mDragDescription;
274 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800275 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700276 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700277 final PointF mLastTouchPoint = new PointF();
Romain Guy59a12ca2011-06-09 17:48:21 -0700278
279 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800280 private Choreographer.FrameCallback mRenderProfiler;
281 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700282
Dan Morrille4d9a012013-03-28 18:10:43 -0700283 private boolean mMediaDisabled;
284
Chet Haase2f2022a2011-10-11 06:41:59 -0700285 // Variables to track frames per second, enabled via DEBUG_FPS flag
286 private long mFpsStartTime = -1;
287 private long mFpsPrevTime = -1;
288 private int mFpsNumFrames;
289
Romain Guyfbb93fa2012-12-03 18:50:35 -0800290 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
Romain Guy51e4d4d2012-03-15 18:30:47 -0700291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 /**
293 * see {@link #playSoundEffect(int)}
294 */
295 AudioManager mAudioManager;
296
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700297 final AccessibilityManager mAccessibilityManager;
298
Gilles Debunne5ac84422011-10-19 09:35:58 -0700299 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700300
301 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
302
Svetoslav Ganova0156172011-06-26 17:55:44 -0700303 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700304
Svetoslav Ganov42138042012-03-20 11:51:39 -0700305 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800306
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700307 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700308 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700309
Chet Haase97140572012-09-13 14:56:47 -0700310 private boolean mInLayout = false;
311 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
312 boolean mHandlingLayoutInLayoutRequest = false;
313
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700314 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700315
Craig Mautner8f303ad2013-06-14 11:32:22 -0700316 /** Set to true once doDie() has been called. */
317 private boolean mRemoved;
318
Jeff Brown21bc5c92011-02-28 18:27:14 -0800319 /**
320 * Consistency verifier for debugging purposes.
321 */
322 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
323 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
324 new InputEventConsistencyVerifier(this, 0) : null;
325
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700326 static final class SystemUiVisibilityInfo {
327 int seq;
328 int globalVisibility;
329 int localValue;
330 int localChanges;
331 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700332
Jeff Brown98365d72012-08-19 20:30:52 -0700333 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700334 mContext = context;
335 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700336 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800337 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700338
Craig Mautner48d0d182013-06-11 07:53:06 -0700339 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 mThread = Thread.currentThread();
342 mLocation = new WindowLeaked(null);
343 mLocation.fillInStackTrace();
344 mWidth = -1;
345 mHeight = -1;
346 mDirty = new Rect();
347 mTempRect = new Rect();
348 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700350 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700351 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 mViewVisibility = View.GONE;
353 mTransparentRegion = new Region();
354 mPreviousTransparentRegion = new Region();
355 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700357 mAccessibilityManager = AccessibilityManager.getInstance(context);
358 mAccessibilityInteractionConnectionManager =
359 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800360 mAccessibilityManager.addAccessibilityStateChangeListener(
361 mAccessibilityInteractionConnectionManager);
Jeff Brown98365d72012-08-19 20:30:52 -0700362 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700364 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700365 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700366 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800367 mChoreographer = Choreographer.getInstance();
Romain Guy7e4e5612012-03-05 14:37:29 -0800368
369 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
370 mAttachInfo.mScreenOn = powerManager.isScreenOn();
Dianne Hackborna53de062012-05-08 18:53:51 -0700371 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
373
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800374 public static void addFirstDrawHandler(Runnable callback) {
375 synchronized (sFirstDrawHandlers) {
376 if (!sFirstDrawComplete) {
377 sFirstDrawHandlers.add(callback);
378 }
379 }
380 }
381
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800382 public static void addConfigCallback(ComponentCallbacks callback) {
383 synchronized (sConfigCallbacks) {
384 sConfigCallbacks.add(callback);
385 }
386 }
387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 // FIXME for perf testing only
389 private boolean mProfile = false;
390
391 /**
392 * Call this to profile the next traversal call.
393 * FIXME for perf testing only. Remove eventually
394 */
395 public void profile() {
396 mProfile = true;
397 }
398
399 /**
400 * Indicates whether we are in touch mode. Calling this method triggers an IPC
401 * call and should be avoided whenever possible.
402 *
403 * @return True, if the device is in touch mode, false otherwise.
404 *
405 * @hide
406 */
407 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700408 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
409 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700411 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 } catch (RemoteException e) {
413 }
414 }
415 return false;
416 }
417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 /**
419 * We have one child
420 */
Romain Guye4d01122010-06-16 18:44:05 -0700421 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 synchronized (this) {
423 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700424 mView = view;
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700425 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700426 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700427 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800428 if (mWindowAttributes.packageName == null) {
429 mWindowAttributes.packageName = mBasePackageName;
430 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700431 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700432 // Keep track of the actual window flags supplied by the client.
433 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700434
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700435 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700436
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700437 if (view instanceof RootViewSurfaceTaker) {
438 mSurfaceHolderCallback =
439 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
440 if (mSurfaceHolderCallback != null) {
441 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700442 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700443 }
444 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800445
Craig Mautner48d0d182013-06-11 07:53:06 -0700446 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700447 mTranslator = compatibilityInfo.getTranslator();
Craig Mautner48d0d182013-06-11 07:53:06 -0700448 mDisplayAdjustments.setActivityToken(attrs.token);
Romain Guy856d4e12011-10-14 15:47:55 -0700449
Romain Guy1aec9a22011-01-05 09:37:12 -0800450 // If the application owns the surface, don't enable hardware acceleration
451 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700452 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800453 }
454
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700455 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700456 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700457 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700458 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700459 attrs.backup();
460 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700461 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700462 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
463
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700464 if (!compatibilityInfo.supportsScreen()) {
465 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700466 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700467 }
468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 mSoftInputMode = attrs.softInputMode;
470 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700471 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700473 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700474 mAttachInfo.mApplicationScale =
475 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 if (panelParentView != null) {
477 mAttachInfo.mPanelParentWindowToken
478 = panelParentView.getApplicationWindowToken();
479 }
480 mAdded = true;
481 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 // Schedule the first layout -before- adding to the window
484 // manager, to make sure we do the relayout before receiving
485 // any other events from the system.
486 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700487 if ((mWindowAttributes.inputFeatures
488 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
489 mInputChannel = new InputChannel();
490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700492 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700493 mAttachInfo.mRecomputeGlobalAttributes = true;
494 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700495 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
496 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700497 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 } catch (RemoteException e) {
499 mAdded = false;
500 mView = null;
501 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700502 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700503 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700505 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700507 } finally {
508 if (restore) {
509 attrs.restore();
510 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700512
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700513 if (mTranslator != null) {
514 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700515 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800516 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 mPendingContentInsets.set(mAttachInfo.mContentInsets);
518 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800519 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700520 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 mAttachInfo.mRootView = null;
522 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700523 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700525 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700527 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
528 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
529 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 "Unable to add window -- token " + attrs.token
531 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700532 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
533 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 "Unable to add window -- token " + attrs.token
535 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700536 case WindowManagerGlobal.ADD_APP_EXITING:
537 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 "Unable to add window -- app for token " + attrs.token
539 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700540 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
541 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 "Unable to add window -- window " + mWindow
543 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700544 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 // Silently ignore -- we would have just removed it
546 // right away, anyway.
547 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700548 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
549 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 "Unable to add window " + mWindow +
551 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700552 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
553 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 "Unable to add window " + mWindow +
555 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700556 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
557 throw new WindowManager.InvalidDisplayException(
558 "Unable to add window " + mWindow +
559 " -- the specified display can not be found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 }
561 throw new RuntimeException(
562 "Unable to add window -- unknown error code " + res);
563 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700564
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700565 if (view instanceof RootViewSurfaceTaker) {
566 mInputQueueCallback =
567 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
568 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700569 if (mInputChannel != null) {
570 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700571 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700572 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700573 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700574 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
575 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700576 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700579 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
580 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700581
582 if (mAccessibilityManager.isEnabled()) {
583 mAccessibilityInteractionConnectionManager.ensureConnection();
584 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700585
586 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
587 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
588 }
Michael Wright95ae9422013-03-14 10:58:50 -0700589
Jeff Brownf9e989d2013-04-04 23:04:03 -0700590 // Set up the input pipeline.
591 CharSequence counterSuffix = attrs.getTitle();
592 InputStage syntheticStage = new SyntheticInputStage();
593 InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticStage);
594 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
595 "aq:native-post-ime:" + counterSuffix);
596 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
597 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
598 "aq:ime:" + counterSuffix);
599 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
600 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
601 "aq:native-pre-ime:" + counterSuffix);
602
603 mFirstInputStage = nativePreImeStage;
604 mFirstPostImeInputStage = earlyPostImeStage;
605 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 }
607 }
608 }
609
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800610 void destroyHardwareResources() {
Romain Guy65b345f2011-07-27 18:51:50 -0700611 if (mAttachInfo.mHardwareRenderer != null) {
612 if (mAttachInfo.mHardwareRenderer.isEnabled()) {
613 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
614 }
615 mAttachInfo.mHardwareRenderer.destroy(false);
Romain Guy6d7475d2011-07-27 16:28:21 -0700616 }
Romain Guy65b345f2011-07-27 18:51:50 -0700617 }
618
Romain Guy31f2c2e2011-11-21 10:55:41 -0800619 void terminateHardwareResources() {
620 if (mAttachInfo.mHardwareRenderer != null) {
621 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
622 mAttachInfo.mHardwareRenderer.destroy(false);
623 }
624 }
625
Romain Guy65b345f2011-07-27 18:51:50 -0700626 void destroyHardwareLayers() {
627 if (mThread != Thread.currentThread()) {
628 if (mAttachInfo.mHardwareRenderer != null &&
629 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700630 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700631 }
632 } else {
633 if (mAttachInfo.mHardwareRenderer != null &&
634 mAttachInfo.mHardwareRenderer.isEnabled()) {
635 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
636 }
637 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700638 }
639
Romain Guy11cb6422012-09-21 00:39:43 -0700640 void pushHardwareLayerUpdate(HardwareLayer layer) {
641 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
642 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
643 }
644 }
645
Romain Guy40543602013-06-12 15:31:28 -0700646 void flushHardwareLayerUpdates() {
647 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
648 mAttachInfo.mHardwareRenderer.validate()) {
649 mAttachInfo.mHardwareRenderer.flushLayerUpdates();
650 }
651 }
652
653 void dispatchFlushHardwareLayerUpdates() {
654 mHandler.removeMessages(MSG_FLUSH_LAYER_UPDATES);
655 mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
656 }
657
Chris Craik41ee4652012-05-31 15:05:57 -0700658 public boolean attachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700659 //noinspection SimplifiableIfStatement
Romain Guyba6be8a2012-04-23 18:22:09 -0700660 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Chris Craik41ee4652012-05-31 15:05:57 -0700661 return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700662 }
Chris Craik41ee4652012-05-31 15:05:57 -0700663 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -0700664 }
665
666 public void detachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700667 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700668 mAttachInfo.mHardwareRenderer.detachFunctor(functor);
669 }
670 }
671
Romain Guy3b748a42013-04-17 18:54:38 -0700672 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800673 mAttachInfo.mHardwareAccelerated = false;
674 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800675
Romain Guy856d4e12011-10-14 15:47:55 -0700676 // Don't enable hardware acceleration when the application is in compatibility mode
677 if (mTranslator != null) return;
678
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800679 // Try to enable hardware acceleration if requested
Jim Miller1b365922011-03-09 19:38:07 -0800680 final boolean hardwareAccelerated =
681 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
682
Romain Guy566c3312011-03-21 18:21:28 -0700683 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700684 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700685 return;
686 }
687
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700688 // Persistent processes (including the system) should not do
689 // accelerated rendering on low-end devices. In that case,
690 // sRendererDisabled will be set. In addition, the system process
691 // itself should never do accelerated rendering. In that case, both
692 // sRendererDisabled and sSystemRendererDisabled are set. When
693 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
694 // can be used by code on the system process to escape that and enable
695 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800696
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700697 final boolean fakeHwAccelerated = (attrs.privateFlags &
698 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
699 final boolean forceHwAccelerated = (attrs.privateFlags &
700 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800701
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700702 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
703 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800704 // Don't enable hardware acceleration when we're not on the main thread
Romain Guy211370f2012-02-01 16:10:55 -0800705 if (!HardwareRenderer.sSystemRendererDisabled &&
706 Looper.getMainLooper() != Looper.myLooper()) {
707 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800708 + "acceleration outside of the main thread, aborting");
709 return;
710 }
711
Romain Guyb051e892010-09-28 19:09:36 -0700712 if (mAttachInfo.mHardwareRenderer != null) {
713 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy211370f2012-02-01 16:10:55 -0800714 }
715
716 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700717 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700718 if (mAttachInfo.mHardwareRenderer != null) {
719 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
720 mAttachInfo.mHardwareAccelerated =
721 mAttachInfo.mHardwareAccelerationRequested = true;
722 }
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700723 } else if (fakeHwAccelerated) {
724 // The window had wanted to use hardware acceleration, but this
725 // is not allowed in its process. By setting this flag, it can
726 // still render as if it was accelerated. This is basically for
727 // the preview windows the window manager shows for launching
728 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700729 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700730 }
731 }
732 }
733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 public View getView() {
735 return mView;
736 }
737
738 final WindowLeaked getLocation() {
739 return mLocation;
740 }
741
742 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
743 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700744 int oldSoftInputMode = mWindowAttributes.softInputMode;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700745 // Keep track of the actual window flags supplied by the client.
746 mClientWindowLayoutFlags = attrs.flags;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700747 // preserve compatible window flag if exists.
748 int compatibleWindowFlag =
749 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Craig Mautner3fe38c02012-05-03 17:28:09 -0700750 // transfer over system UI visibility values as they carry current state.
751 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
752 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Romain Guyf21c9b02011-09-06 16:56:54 -0700753 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800754 if (mWindowAttributes.packageName == null) {
755 mWindowAttributes.packageName = mBasePackageName;
756 }
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700757 mWindowAttributes.flags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700758
759 applyKeepScreenOnFlag(mWindowAttributes);
760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 if (newView) {
762 mSoftInputMode = attrs.softInputMode;
763 requestLayout();
764 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700765 // Don't lose the mode we last auto-computed.
766 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
767 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
768 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
769 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
770 | (oldSoftInputMode
771 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 mWindowAttributesChanged = true;
774 scheduleTraversals();
775 }
776 }
777
778 void handleAppVisibility(boolean visible) {
779 if (mAppVisible != visible) {
780 mAppVisible = visible;
781 scheduleTraversals();
782 }
783 }
784
785 void handleGetNewSurface() {
786 mNewSurfaceNeeded = true;
787 mFullRedrawNeeded = true;
788 scheduleTraversals();
789 }
790
Romain Guybb9908b2012-03-08 11:14:07 -0800791 void handleScreenStateChange(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -0800792 if (on != mAttachInfo.mScreenOn) {
793 mAttachInfo.mScreenOn = on;
Romain Guybb9908b2012-03-08 11:14:07 -0800794 if (mView != null) {
795 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
796 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800797 if (on) {
798 mFullRedrawNeeded = true;
799 scheduleTraversals();
800 }
801 }
802 }
803
Craig Mautner6018aee2012-10-23 14:27:49 -0700804 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700805 public void requestFitSystemWindows() {
806 checkThread();
807 mFitSystemWindowsRequested = true;
808 scheduleTraversals();
809 }
810
Craig Mautner6018aee2012-10-23 14:27:49 -0700811 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800813 if (!mHandlingLayoutInLayoutRequest) {
814 checkThread();
815 mLayoutRequested = true;
816 scheduleTraversals();
817 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 }
819
Craig Mautner6018aee2012-10-23 14:27:49 -0700820 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 public boolean isLayoutRequested() {
822 return mLayoutRequested;
823 }
824
Romain Guycfef1232012-02-23 13:50:37 -0800825 void invalidate() {
826 mDirty.set(0, 0, mWidth, mHeight);
827 scheduleTraversals();
828 }
829
Dianne Hackborna53de062012-05-08 18:53:51 -0700830 void invalidateWorld(View view) {
831 view.invalidate();
832 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700833 ViewGroup parent = (ViewGroup) view;
834 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700835 invalidateWorld(parent.getChildAt(i));
836 }
837 }
838 }
839
Craig Mautner6018aee2012-10-23 14:27:49 -0700840 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800842 invalidateChildInParent(null, dirty);
843 }
844
Craig Mautner8f303ad2013-06-14 11:32:22 -0700845 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800846 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700848 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800849
Chet Haase70d4ba12010-10-06 09:46:45 -0700850 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700851 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800852 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700853 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700854 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700855 }
Romain Guycfef1232012-02-23 13:50:37 -0800856
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700857 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700859 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700860 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800861 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700862 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700863 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700864 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700865 }
Romain Guy1e095972009-07-07 11:22:45 -0700866 if (mAttachInfo.mScalingRequired) {
867 dirty.inset(-1, -1);
868 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 }
Romain Guycfef1232012-02-23 13:50:37 -0800870
871 final Rect localDirty = mDirty;
872 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700873 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800874 mAttachInfo.mIgnoreDirtyState = true;
875 }
Romain Guycfef1232012-02-23 13:50:37 -0800876
877 // Add the new dirty rect to the current one
878 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
879 // Intersect with the bounds of the window to skip
880 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700881 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700882 final boolean intersected = localDirty.intersect(0, 0,
883 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
884 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700885 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 }
Chet Haase3561d062012-10-23 12:54:51 -0700887 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
888 scheduleTraversals();
889 }
Romain Guycfef1232012-02-23 13:50:37 -0800890
891 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893
Dianne Hackbornce418e62011-03-01 14:31:38 -0800894 void setStopped(boolean stopped) {
895 if (mStopped != stopped) {
896 mStopped = stopped;
897 if (!stopped) {
898 scheduleTraversals();
899 }
900 }
901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902
Craig Mautner8f303ad2013-06-14 11:32:22 -0700903 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800904 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 return null;
906 }
907
Craig Mautner8f303ad2013-06-14 11:32:22 -0700908 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700909 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 if (child != mView) {
911 throw new RuntimeException("child is not mine, honest!");
912 }
913 // Note: don't apply scroll offset, because we want to know its
914 // visibility in the virtual canvas being given to the view hierarchy.
915 return r.intersect(0, 0, mWidth, mHeight);
916 }
917
918 public void bringChildToFront(View child) {
919 }
920
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 int getHostVisibility() {
922 return mAppVisible ? mView.getVisibility() : View.GONE;
923 }
Romain Guy8506ab42009-06-11 17:35:47 -0700924
Romain Guy7d70fbf2011-05-24 17:40:25 -0700925 void disposeResizeBuffer() {
Romain Guy27e0bf62013-06-21 14:07:07 -0700926 if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) {
927 mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
928 @Override
929 public void run() {
930 mResizeBuffer.destroy();
931 mResizeBuffer = null;
932 }
933 });
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800934 }
935 }
936
Chet Haasecca2c982011-05-20 14:34:18 -0700937 /**
938 * Add LayoutTransition to the list of transitions to be started in the next traversal.
939 * This list will be cleared after the transitions on the list are start()'ed. These
940 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
941 * happens during the layout phase of traversal, which we want to complete before any of the
942 * animations are started (because those animations may side-effect properties that layout
943 * depends upon, like the bounding rectangles of the affected views). So we add the transition
944 * to the list and it is started just prior to starting the drawing phase of traversal.
945 *
946 * @param transition The LayoutTransition to be started on the next traversal.
947 *
948 * @hide
949 */
950 public void requestTransitionStart(LayoutTransition transition) {
951 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
952 if (mPendingTransitions == null) {
953 mPendingTransitions = new ArrayList<LayoutTransition>();
954 }
955 mPendingTransitions.add(transition);
956 }
957 }
958
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700959 void scheduleTraversals() {
960 if (!mTraversalScheduled) {
961 mTraversalScheduled = true;
962 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
963 mChoreographer.postCallback(
964 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Jeff Brown330314c2012-04-27 02:20:22 -0700965 scheduleConsumeBatchedInput();
Jeff Brown96e942d2011-11-30 19:55:01 -0800966 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700967 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800968
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700969 void unscheduleTraversals() {
970 if (mTraversalScheduled) {
971 mTraversalScheduled = false;
972 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
973 mChoreographer.removeCallbacks(
974 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
975 }
976 }
977
978 void doTraversal() {
979 if (mTraversalScheduled) {
980 mTraversalScheduled = false;
981 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
982
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700983 if (mProfile) {
984 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -0800985 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800986
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700987 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
988 try {
989 performTraversals();
990 } finally {
991 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
992 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800993
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700994 if (mProfile) {
995 Debug.stopMethodTracing();
996 mProfile = false;
997 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800998 }
999 }
1000
Dianne Hackborn9d090892012-06-11 18:35:41 -07001001 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1002 // Update window's global keep screen on flag: if a view has requested
1003 // that the screen be kept on, then it is always set; otherwise, it is
1004 // set to whatever the client last requested for the global state.
1005 if (mAttachInfo.mKeepScreenOn) {
1006 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1007 } else {
1008 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1009 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1010 }
1011 }
1012
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001013 private boolean collectViewAttributes() {
1014 final View.AttachInfo attachInfo = mAttachInfo;
1015 if (attachInfo.mRecomputeGlobalAttributes) {
1016 //Log.i(TAG, "Computing view hierarchy attributes!");
1017 attachInfo.mRecomputeGlobalAttributes = false;
1018 boolean oldScreenOn = attachInfo.mKeepScreenOn;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001019 attachInfo.mKeepScreenOn = false;
1020 attachInfo.mSystemUiVisibility = 0;
1021 attachInfo.mHasSystemUiListeners = false;
1022 mView.dispatchCollectViewAttributes(attachInfo, 0);
Dianne Hackborn139e5aa2012-05-05 20:36:38 -07001023 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001024 WindowManager.LayoutParams params = mWindowAttributes;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001025 if (attachInfo.mKeepScreenOn != oldScreenOn
Craig Mautner7eac0f52012-09-13 13:14:14 -07001026 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1027 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001028 applyKeepScreenOnFlag(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001029 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1030 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1031 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1032 return true;
1033 }
1034 }
1035 return false;
1036 }
1037
1038 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1039 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1040 int childWidthMeasureSpec;
1041 int childHeightMeasureSpec;
1042 boolean windowSizeMayChange = false;
1043
1044 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1045 "Measuring " + host + " in display " + desiredWindowWidth
1046 + "x" + desiredWindowHeight + "...");
1047
1048 boolean goodMeasure = false;
1049 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1050 // On large screens, we don't want to allow dialogs to just
1051 // stretch to fill the entire width of the screen to display
1052 // one line of text. First try doing the layout at a smaller
1053 // size to see if it will fit.
1054 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1055 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1056 int baseSize = 0;
1057 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1058 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1059 }
1060 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1061 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1062 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1063 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001064 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001065 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1066 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1067 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1068 goodMeasure = true;
1069 } else {
1070 // Didn't fit in that size... try expanding a bit.
1071 baseSize = (baseSize+desiredWindowWidth)/2;
1072 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1073 + baseSize);
1074 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001075 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001076 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1077 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1078 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1079 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1080 goodMeasure = true;
1081 }
1082 }
1083 }
1084 }
1085
1086 if (!goodMeasure) {
1087 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1088 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001089 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001090 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1091 windowSizeMayChange = true;
1092 }
1093 }
1094
1095 if (DBG) {
1096 System.out.println("======================================");
1097 System.out.println("performTraversals -- after measure");
1098 host.debug();
1099 }
1100
1101 return windowSizeMayChange;
1102 }
1103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 private void performTraversals() {
1105 // cache mView since it is used so much below...
1106 final View host = mView;
1107
1108 if (DBG) {
1109 System.out.println("======================================");
1110 System.out.println("performTraversals");
1111 host.debug();
1112 }
1113
1114 if (host == null || !mAdded)
1115 return;
1116
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001117 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001119 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001121 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 WindowManager.LayoutParams lp = mWindowAttributes;
1123
1124 int desiredWindowWidth;
1125 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126
1127 final View.AttachInfo attachInfo = mAttachInfo;
1128
1129 final int viewVisibility = getHostVisibility();
1130 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1131 || mNewSurfaceNeeded;
1132
1133 WindowManager.LayoutParams params = null;
1134 if (mWindowAttributesChanged) {
1135 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001136 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 params = lp;
1138 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001139 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001140 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1141 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001142 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001143 mLayoutRequested = true;
1144 if (mLastInCompatMode) {
1145 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1146 mLastInCompatMode = false;
1147 } else {
1148 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1149 mLastInCompatMode = true;
1150 }
1151 }
Romain Guyf21c9b02011-09-06 16:56:54 -07001152
1153 mWindowAttributesChangesFlag = 0;
1154
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001155 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001157 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 mLayoutRequested = true;
1159
Dianne Hackborna239c842011-06-01 12:28:20 -07001160 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1161 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001162 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001163 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001164 desiredWindowWidth = size.x;
1165 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001166 } else {
1167 DisplayMetrics packageMetrics =
1168 mView.getContext().getResources().getDisplayMetrics();
1169 desiredWindowWidth = packageMetrics.widthPixels;
1170 desiredWindowHeight = packageMetrics.heightPixels;
1171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172
1173 // For the very first time, tell the view hierarchy that it
1174 // is attached to the window. Note that at this point the surface
1175 // object is not initialized to its backing store, but soon it
1176 // will be (assuming the window is visible).
1177 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -08001178 // We used to use the following condition to choose 32 bits drawing caches:
1179 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1180 // However, windows are now always 32 bits by default, so choose 32 bits
1181 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 attachInfo.mHasWindowFocus = false;
1183 attachInfo.mWindowVisibility = viewVisibility;
1184 attachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001186 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001187 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001188 // Set the layout direction if it has not been set before (inherit is the default)
1189 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1190 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 host.dispatchAttachedToWindow(attachInfo, 0);
Dianne Hackborn961cae92013-03-20 14:59:43 -07001193 attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001194 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1195 host.fitSystemWindows(mFitSystemWindowsInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001199 desiredWindowWidth = frame.width();
1200 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001202 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001203 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001204 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001206 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 }
1208 }
1209
1210 if (viewVisibilityChanged) {
1211 attachInfo.mWindowVisibility = viewVisibility;
1212 host.dispatchWindowVisibilityChanged(viewVisibility);
1213 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001214 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216 if (viewVisibility == View.GONE) {
1217 // After making a window gone, we will count it as being
1218 // shown for the first time the next time it gets focus.
1219 mHasHadWindowFocus = false;
1220 }
1221 }
1222
Chet Haaseb78c2842012-04-19 13:39:50 -07001223 // Execute enqueued actions on every traversal in case a detached view enqueued an action
1224 getRunQueue().executeActions(attachInfo.mHandler);
1225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001227
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001228 boolean layoutRequested = mLayoutRequested && !mStopped;
1229 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001230
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001231 final Resources res = mView.getContext().getResources();
1232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 // make sure touch mode code executes by setting cached value
1235 // to opposite of the added touch mode.
1236 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001237 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001239 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1240 insetsChanged = true;
1241 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001242 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001245 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1247 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1248 + mAttachInfo.mVisibleInsets);
1249 }
1250 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1251 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001252 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253
Dianne Hackborna239c842011-06-01 12:28:20 -07001254 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1255 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001256 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001257 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001258 desiredWindowWidth = size.x;
1259 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001260 } else {
1261 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1262 desiredWindowWidth = packageMetrics.widthPixels;
1263 desiredWindowHeight = packageMetrics.heightPixels;
1264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
1266 }
1267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001269 windowSizeMayChange |= measureHierarchy(host, lp, res,
1270 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 }
1272
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001273 if (collectViewAttributes()) {
1274 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001276 if (attachInfo.mForceReportNewAttributes) {
1277 attachInfo.mForceReportNewAttributes = false;
1278 params = lp;
1279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280
1281 if (mFirst || attachInfo.mViewVisibilityChanged) {
1282 attachInfo.mViewVisibilityChanged = false;
1283 int resizeMode = mSoftInputMode &
1284 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1285 // If we are in auto resize mode, then we need to determine
1286 // what mode to use now.
1287 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1288 final int N = attachInfo.mScrollContainers.size();
1289 for (int i=0; i<N; i++) {
1290 if (attachInfo.mScrollContainers.get(i).isShown()) {
1291 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1292 }
1293 }
1294 if (resizeMode == 0) {
1295 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1296 }
1297 if ((lp.softInputMode &
1298 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1299 lp.softInputMode = (lp.softInputMode &
1300 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1301 resizeMode;
1302 params = lp;
1303 }
1304 }
1305 }
Romain Guy8506ab42009-06-11 17:35:47 -07001306
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001307 if (params != null) {
1308 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1309 if (!PixelFormat.formatHasAlpha(params.format)) {
1310 params.format = PixelFormat.TRANSLUCENT;
1311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001313 mAttachInfo.mOverscanRequested = (params.flags
1314 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 }
1316
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001317 if (mFitSystemWindowsRequested) {
1318 mFitSystemWindowsRequested = false;
1319 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001320 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001321 host.fitSystemWindows(mFitSystemWindowsInsets);
1322 if (mLayoutRequested) {
1323 // Short-circuit catching a new layout request here, so
1324 // we don't need to go through two layout passes when things
1325 // change due to fitting system windows, which can happen a lot.
1326 windowSizeMayChange |= measureHierarchy(host, lp,
1327 mView.getContext().getResources(),
1328 desiredWindowWidth, desiredWindowHeight);
1329 }
1330 }
1331
1332 if (layoutRequested) {
1333 // Clear this now, so that if anything requests a layout in the
1334 // rest of this function we will catch it and re-run a full
1335 // layout pass.
1336 mLayoutRequested = false;
1337 }
1338
1339 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001340 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001341 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1342 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1343 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1344 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345
1346 final boolean computesInternalInsets =
1347 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
Romain Guy812ccbe2010-06-01 14:07:24 -07001348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 boolean insetsPending = false;
1350 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001351
1352 if (mFirst || windowShouldResize || insetsChanged ||
1353 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354
1355 if (viewVisibility == View.VISIBLE) {
1356 // If this window is giving internal insets to the window
1357 // manager, and it is being added or changing its visibility,
1358 // then we want to first give the window manager "fake"
1359 // insets to cause it to effectively ignore the content of
1360 // the window during layout. This avoids it briefly causing
1361 // other windows to resize/move based on the raw frame of the
1362 // window, waiting until we can finish laying out this window
1363 // and get back to the window manager with the ultimately
1364 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001365 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 }
1367
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001368 if (mSurfaceHolder != null) {
1369 mSurfaceHolder.mSurfaceLock.lock();
1370 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001371 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001372
Romain Guyc361da82010-10-25 15:29:10 -07001373 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001375 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001378 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001379 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1380 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001381 }
Romain Guy2a83f002011-01-18 18:28:21 -08001382
1383 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001384 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
Michael Jurkaf42d90102013-05-08 18:00:04 +02001385 if (!mDrawDuringWindowsAnimating) {
1386 mWindowsAnimating |=
1387 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0;
1388 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001391 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 + " content=" + mPendingContentInsets.toShortString()
1393 + " visible=" + mPendingVisibleInsets.toShortString()
1394 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001395
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001396 if (mPendingConfiguration.seq != 0) {
1397 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1398 + mPendingConfiguration);
1399 updateConfiguration(mPendingConfiguration, !mFirst);
1400 mPendingConfiguration.seq = 0;
1401 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001402
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001403 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1404 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 contentInsetsChanged = !mPendingContentInsets.equals(
1406 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001407 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mAttachInfo.mVisibleInsets);
1409 if (contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001410 if (mWidth > 0 && mHeight > 0 && lp != null &&
1411 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1412 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001413 mSurface != null && mSurface.isValid() &&
1414 !mAttachInfo.mTurnOffWindowResizeAnim &&
1415 mAttachInfo.mHardwareRenderer != null &&
1416 mAttachInfo.mHardwareRenderer.isEnabled() &&
1417 mAttachInfo.mHardwareRenderer.validate() &&
1418 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1419
1420 disposeResizeBuffer();
1421
1422 boolean completed = false;
Romain Guyc89b14b2012-08-08 14:53:48 -07001423 HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
Chet Haase08837c22011-11-28 11:53:21 -08001424 HardwareCanvas layerCanvas = null;
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001425 try {
1426 if (mResizeBuffer == null) {
1427 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1428 mWidth, mHeight, false);
1429 } else if (mResizeBuffer.getWidth() != mWidth ||
1430 mResizeBuffer.getHeight() != mHeight) {
1431 mResizeBuffer.resize(mWidth, mHeight);
1432 }
Chet Haase603f6de2012-09-14 15:31:25 -07001433 // TODO: should handle create/resize failure
Romain Guyc89b14b2012-08-08 14:53:48 -07001434 layerCanvas = mResizeBuffer.start(hwRendererCanvas);
Chet Haase08837c22011-11-28 11:53:21 -08001435 final int restoreCount = layerCanvas.save();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001436
1437 int yoff;
1438 final boolean scrolling = mScroller != null
1439 && mScroller.computeScrollOffset();
1440 if (scrolling) {
1441 yoff = mScroller.getCurrY();
1442 mScroller.abortAnimation();
1443 } else {
1444 yoff = mScrollY;
1445 }
1446
Chet Haase08837c22011-11-28 11:53:21 -08001447 layerCanvas.translate(0, -yoff);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001448 if (mTranslator != null) {
Chet Haase08837c22011-11-28 11:53:21 -08001449 mTranslator.translateCanvas(layerCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001450 }
1451
Romain Guy3a2d6aa2012-10-23 13:25:13 -07001452 DisplayList displayList = mView.mDisplayList;
1453 if (displayList != null) {
1454 layerCanvas.drawDisplayList(displayList, null,
1455 DisplayList.FLAG_CLIP_CHILDREN);
1456 } else {
1457 mView.draw(layerCanvas);
1458 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001459
Svetoslav Ganov42138042012-03-20 11:51:39 -07001460 drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1461
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001462 mResizeBufferStartTime = SystemClock.uptimeMillis();
1463 mResizeBufferDuration = mView.getResources().getInteger(
1464 com.android.internal.R.integer.config_mediumAnimTime);
1465 completed = true;
1466
Chet Haase08837c22011-11-28 11:53:21 -08001467 layerCanvas.restoreToCount(restoreCount);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001468 } catch (OutOfMemoryError e) {
1469 Log.w(TAG, "Not enough memory for content change anim buffer", e);
1470 } finally {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001471 if (mResizeBuffer != null) {
Romain Guyc89b14b2012-08-08 14:53:48 -07001472 mResizeBuffer.end(hwRendererCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001473 if (!completed) {
Romain Guy27e0bf62013-06-21 14:07:07 -07001474 disposeResizeBuffer();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001475 }
1476 }
1477 }
1478 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1481 + mAttachInfo.mContentInsets);
1482 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001483 if (overscanInsetsChanged) {
1484 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1485 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1486 + mAttachInfo.mOverscanInsets);
1487 // Need to relayout with content insets.
1488 contentInsetsChanged = true;
1489 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001490 if (contentInsetsChanged || mLastSystemUiVisibility !=
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001491 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
1492 || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001493 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001494 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001495 mFitSystemWindowsRequested = false;
1496 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1497 host.fitSystemWindows(mFitSystemWindowsInsets);
1498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 if (visibleInsetsChanged) {
1500 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1501 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1502 + mAttachInfo.mVisibleInsets);
1503 }
1504
1505 if (!hadSurface) {
1506 if (mSurface.isValid()) {
1507 // If we are creating a new surface, then we need to
1508 // completely redraw it. Also, when we get to the
1509 // point of drawing it we will hold off and schedule
1510 // a new traversal instead. This is so we can tell the
1511 // window manager about all of the windows being displayed
1512 // before actually drawing them, so it can display then
1513 // all at once.
1514 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001515 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001516 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001517
Romain Guyb051e892010-09-28 19:09:36 -07001518 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001519 try {
Romain Guy786fc932012-07-24 16:24:56 -07001520 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
1521 mHolder.getSurface());
Dianne Hackborn64825172011-03-02 21:32:58 -08001522 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001523 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001524 return;
1525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 }
1527 }
1528 } else if (!mSurface.isValid()) {
1529 // If the surface has been removed, then reset the scroll
1530 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001531 if (mLastScrolledFocus != null) {
1532 mLastScrolledFocus.clear();
1533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 mScrollY = mCurScrollY = 0;
1535 if (mScroller != null) {
1536 mScroller.abortAnimation();
1537 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001538 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001539 // Our surface is gone
1540 if (mAttachInfo.mHardwareRenderer != null &&
1541 mAttachInfo.mHardwareRenderer.isEnabled()) {
1542 mAttachInfo.mHardwareRenderer.destroy(true);
1543 }
Romain Guy2a83f002011-01-18 18:28:21 -08001544 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1545 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001546 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001547 try {
Romain Guy786fc932012-07-24 16:24:56 -07001548 mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
Dianne Hackborn64825172011-03-02 21:32:58 -08001549 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001550 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001551 return;
1552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 }
1554 } catch (RemoteException e) {
1555 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001558 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559
1560 attachInfo.mWindowLeft = frame.left;
1561 attachInfo.mWindowTop = frame.top;
1562
1563 // !!FIXME!! This next section handles the case where we did not get the
1564 // window size we asked for. We should avoid this by getting a maximum size from
1565 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001566 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001567 mWidth = frame.width();
1568 mHeight = frame.height();
1569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001571 if (mSurfaceHolder != null) {
1572 // The app owns the surface; tell it about what is going on.
1573 if (mSurface.isValid()) {
1574 // XXX .copyFrom() doesn't work!
1575 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1576 mSurfaceHolder.mSurface = mSurface;
1577 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001578 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001579 mSurfaceHolder.mSurfaceLock.unlock();
1580 if (mSurface.isValid()) {
1581 if (!hadSurface) {
1582 mSurfaceHolder.ungetCallbacks();
1583
1584 mIsCreating = true;
1585 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1586 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1587 if (callbacks != null) {
1588 for (SurfaceHolder.Callback c : callbacks) {
1589 c.surfaceCreated(mSurfaceHolder);
1590 }
1591 }
1592 surfaceChanged = true;
1593 }
1594 if (surfaceChanged) {
1595 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1596 lp.format, mWidth, mHeight);
1597 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1598 if (callbacks != null) {
1599 for (SurfaceHolder.Callback c : callbacks) {
1600 c.surfaceChanged(mSurfaceHolder, lp.format,
1601 mWidth, mHeight);
1602 }
1603 }
1604 }
1605 mIsCreating = false;
1606 } else if (hadSurface) {
1607 mSurfaceHolder.ungetCallbacks();
1608 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1609 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1610 if (callbacks != null) {
1611 for (SurfaceHolder.Callback c : callbacks) {
1612 c.surfaceDestroyed(mSurfaceHolder);
1613 }
1614 }
1615 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001616 try {
1617 mSurfaceHolder.mSurface = new Surface();
1618 } finally {
1619 mSurfaceHolder.mSurfaceLock.unlock();
1620 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001621 }
1622 }
Romain Guy53389bd2010-09-07 17:16:32 -07001623
Chet Haase40e03832011-10-06 08:34:13 -07001624 if (mAttachInfo.mHardwareRenderer != null &&
1625 mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guy370ab062013-05-21 12:15:07 -07001626 if (hwInitialized ||
Chet Haase40e03832011-10-06 08:34:13 -07001627 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1628 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1629 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1630 if (!hwInitialized) {
Romain Guy786fc932012-07-24 16:24:56 -07001631 mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
Chet Haase391fef02012-09-27 15:26:36 -07001632 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001633 }
Romain Guy03985752011-07-11 15:33:51 -07001634 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 }
1636
Dianne Hackbornce418e62011-03-01 14:31:38 -08001637 if (!mStopped) {
1638 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001639 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001640 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1641 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001642 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1643 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001644
1645 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1646 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1647 + " mHeight=" + mHeight
1648 + " measuredHeight=" + host.getMeasuredHeight()
1649 + " coveredInsetsChanged=" + contentInsetsChanged);
1650
1651 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001652 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001653
1654 // Implementation of weights from WindowManager.LayoutParams
1655 // We just grow the dimensions as needed and re-measure if
1656 // needs be
1657 int width = host.getMeasuredWidth();
1658 int height = host.getMeasuredHeight();
1659 boolean measureAgain = false;
1660
1661 if (lp.horizontalWeight > 0.0f) {
1662 width += (int) ((mWidth - width) * lp.horizontalWeight);
1663 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1664 MeasureSpec.EXACTLY);
1665 measureAgain = true;
1666 }
1667 if (lp.verticalWeight > 0.0f) {
1668 height += (int) ((mHeight - height) * lp.verticalWeight);
1669 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1670 MeasureSpec.EXACTLY);
1671 measureAgain = true;
1672 }
1673
1674 if (measureAgain) {
1675 if (DEBUG_LAYOUT) Log.v(TAG,
1676 "And hey let's measure once more: width=" + width
1677 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001678 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001679 }
1680
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001681 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001684 } else {
1685 // Not the first pass and no window/insets/visibility change but the window
1686 // may have moved and we need check that and if so to update the left and right
1687 // in the attach info. We translate only the window frame since on window move
1688 // the window manager tells us only for the new frame but the insets are the
1689 // same and we do not want to translate them more than once.
1690
1691 // TODO: Well, we are checking whether the frame has changed similarly
1692 // to how this is done for the insets. This is however incorrect since
1693 // the insets and the frame are translated. For example, the old frame
1694 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1695 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1696 // true since we are comparing a not translated value to a translated one.
1697 // This scenario is rare but we may want to fix that.
1698
1699 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1700 || attachInfo.mWindowTop != frame.top);
1701 if (windowMoved) {
1702 if (mTranslator != null) {
1703 mTranslator.translateRectInScreenToAppWinFrame(frame);
1704 }
1705 attachInfo.mWindowLeft = frame.left;
1706 attachInfo.mWindowTop = frame.top;
1707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 }
1709
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001710 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 boolean triggerGlobalLayoutListener = didLayout
1712 || attachInfo.mRecomputeGlobalAttributes;
1713 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001714 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001716 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 // We can compute the transparent area
1718
Dianne Hackborn4702a852012-08-17 15:18:29 -07001719 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 // start out transparent
1721 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1722 host.getLocationInWindow(mTmpLocation);
1723 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1724 mTmpLocation[0] + host.mRight - host.mLeft,
1725 mTmpLocation[1] + host.mBottom - host.mTop);
1726
1727 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001728 if (mTranslator != null) {
1729 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1730 }
1731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1733 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001734 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 // reconfigure window manager
1736 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001737 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 } catch (RemoteException e) {
1739 }
1740 }
1741 }
1742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 if (DBG) {
1744 System.out.println("======================================");
1745 System.out.println("performTraversals -- after setFrame");
1746 host.debug();
1747 }
1748 }
1749
1750 if (triggerGlobalLayoutListener) {
1751 attachInfo.mRecomputeGlobalAttributes = false;
1752 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1753 }
1754
1755 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001756 // Clear the original insets.
1757 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1758 insets.reset();
1759
1760 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001762
1763 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1765 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001766
1767 // Translate insets to screen coordinates if needed.
1768 final Rect contentInsets;
1769 final Rect visibleInsets;
1770 final Region touchableRegion;
1771 if (mTranslator != null) {
1772 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1773 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1774 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1775 } else {
1776 contentInsets = insets.contentInsets;
1777 visibleInsets = insets.visibleInsets;
1778 touchableRegion = insets.touchableRegion;
1779 }
1780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001782 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001783 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 } catch (RemoteException e) {
1785 }
1786 }
1787 }
Romain Guy8506ab42009-06-11 17:35:47 -07001788
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001789 boolean skipDraw = false;
1790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 if (mFirst) {
1792 // handle first focus request
1793 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1794 + mView.hasFocus());
1795 if (mView != null) {
1796 if (!mView.hasFocus()) {
1797 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001799 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001802 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 }
1804 }
Jeff Brown98365d72012-08-19 20:30:52 -07001805 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001806 // The first time we relayout the window, if the system is
1807 // doing window animations, we want to hold of on any future
1808 // draws until the animation is done.
1809 mWindowsAnimating = true;
1810 }
1811 } else if (mWindowsAnimating) {
1812 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 }
1814
1815 mFirst = false;
1816 mWillDrawSoon = false;
1817 mNewSurfaceNeeded = false;
1818 mViewVisibility = viewVisibility;
1819
1820 if (mAttachInfo.mHasWindowFocus) {
1821 final boolean imTarget = WindowManager.LayoutParams
1822 .mayUseInputMethod(mWindowAttributes.flags);
1823 if (imTarget != mLastWasImTarget) {
1824 mLastWasImTarget = imTarget;
1825 InputMethodManager imm = InputMethodManager.peekInstance();
1826 if (imm != null && imTarget) {
1827 imm.startGettingWindowFocus(mView);
1828 imm.onWindowFocus(mView, mView.findFocus(),
1829 mWindowAttributes.softInputMode,
1830 !mHasHadWindowFocus, mWindowAttributes.flags);
1831 }
1832 }
1833 }
Romain Guy8506ab42009-06-11 17:35:47 -07001834
Jeff Brown96e942d2011-11-30 19:55:01 -08001835 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001836 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001837 mReportNextDraw = true;
1838 }
1839
Romain Guyea835032011-07-28 19:24:37 -07001840 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1841 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842
Chet Haase61158c62011-09-06 22:19:45 -07001843 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001844 if (!skipDraw || mReportNextDraw) {
1845 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1846 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1847 mPendingTransitions.get(i).startChangingAnimations();
1848 }
1849 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001850 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001851
1852 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001855 if (viewVisibility == View.VISIBLE) {
1856 // Try again
1857 scheduleTraversals();
1858 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001859 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1860 mPendingTransitions.get(i).endChangingAnimations();
1861 }
1862 mPendingTransitions.clear();
1863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001865
1866 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 }
1868
Romain Guy3696779b2013-01-28 14:04:07 -08001869 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
1870 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1871 try {
1872 if (!mWindowSession.outOfMemory(mWindow) &&
1873 Process.myUid() != Process.SYSTEM_UID) {
1874 Slog.w(TAG, "No processes killed for memory; killing self");
1875 Process.killProcess(Process.myPid());
1876 }
1877 } catch (RemoteException ex) {
1878 }
1879 mLayoutRequested = true; // ask wm for a new surface next time.
1880 }
1881
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001882 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1883 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1884 try {
1885 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1886 } finally {
1887 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1888 }
1889 }
1890
Chet Haase97140572012-09-13 14:56:47 -07001891 /**
1892 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
1893 * is currently undergoing a layout pass.
1894 *
1895 * @return whether the view hierarchy is currently undergoing a layout pass
1896 */
1897 boolean isInLayout() {
1898 return mInLayout;
1899 }
1900
1901 /**
Chet Haasecc699b42012-12-13 09:06:55 -08001902 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
1903 * undergoing a layout pass. requestLayout() should not generally be called during layout,
1904 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
1905 * all children in that container hierarchy are measured and laid out at the end of the layout
1906 * pass for that container). If requestLayout() is called anyway, we handle it correctly
1907 * by registering all requesters during a frame as it proceeds. At the end of the frame,
1908 * we check all of those views to see if any still have pending layout requests, which
1909 * indicates that they were not correctly handled by their container hierarchy. If that is
1910 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
1911 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07001912 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08001913 * requests to the next frame to avoid possible infinite loops.
1914 *
1915 * <p>The return value from this method indicates whether the request should proceed
1916 * (if it is a request during the first layout pass) or should be skipped and posted to the
1917 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07001918 *
1919 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08001920 *
1921 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07001922 */
Chet Haasecc699b42012-12-13 09:06:55 -08001923 boolean requestLayoutDuringLayout(final View view) {
1924 if (view.mParent == null || view.mAttachInfo == null) {
1925 // Would not normally trigger another layout, so just let it pass through as usual
1926 return true;
1927 }
Chet Haase107a4822013-03-13 06:46:50 -07001928 if (!mLayoutRequesters.contains(view)) {
1929 mLayoutRequesters.add(view);
1930 }
Chet Haase97140572012-09-13 14:56:47 -07001931 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07001932 // Let the request proceed normally; it will be processed in a second layout pass
1933 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08001934 return true;
Chet Haase97140572012-09-13 14:56:47 -07001935 } else {
Chet Haase107a4822013-03-13 06:46:50 -07001936 // Don't let the request proceed during the second layout pass.
1937 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08001938 return false;
Chet Haase97140572012-09-13 14:56:47 -07001939 }
1940 }
1941
Chet Haase3efa7b52012-12-03 08:33:17 -08001942 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
1943 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001944 mLayoutRequested = false;
1945 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07001946 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001947
1948 final View host = mView;
1949 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1950 Log.v(TAG, "Laying out " + host + " to (" +
1951 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
1952 }
1953
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001954 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
1955 try {
1956 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08001957
Chet Haased5a83522012-11-21 16:24:44 -08001958 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07001959 int numViewsRequestingLayout = mLayoutRequesters.size();
1960 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08001961 // requestLayout() was called during layout.
1962 // If no layout-request flags are set on the requesting views, there is no problem.
1963 // If some requests are still pending, then we need to clear those flags and do
1964 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07001965 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
1966 false);
1967 if (validLayoutRequesters != null) {
1968 // Set this flag to indicate that any further requests are happening during
1969 // the second pass, which may result in posting those requests to the next
1970 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08001971 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07001972
1973 // Process fresh layout requests, then measure and layout
1974 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08001975 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07001976 final View view = validLayoutRequesters.get(i);
1977 Log.w("View", "requestLayout() improperly called by " + view +
1978 " during layout: running second layout pass");
1979 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08001980 }
1981 measureHierarchy(host, lp, mView.getContext().getResources(),
1982 desiredWindowWidth, desiredWindowHeight);
1983 mInLayout = true;
1984 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07001985
Chet Haasecc699b42012-12-13 09:06:55 -08001986 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07001987
1988 // Check the valid requests again, this time without checking/clearing the
1989 // layout flags, since requests happening during the second pass get noop'd
1990 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
1991 if (validLayoutRequesters != null) {
1992 final ArrayList<View> finalRequesters = validLayoutRequesters;
1993 // Post second-pass requests to the next frame
1994 getRunQueue().post(new Runnable() {
1995 @Override
1996 public void run() {
1997 int numValidRequests = finalRequesters.size();
1998 for (int i = 0; i < numValidRequests; ++i) {
1999 final View view = finalRequesters.get(i);
2000 Log.w("View", "requestLayout() improperly called by " + view +
2001 " during second layout pass: posting in next frame");
2002 view.requestLayout();
2003 }
2004 }
2005 });
2006 }
Chet Haasecc699b42012-12-13 09:06:55 -08002007 }
Chet Haase107a4822013-03-13 06:46:50 -07002008
Chet Haase97140572012-09-13 14:56:47 -07002009 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002010 } finally {
2011 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2012 }
Chet Haase97140572012-09-13 14:56:47 -07002013 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002014 }
2015
Chet Haase107a4822013-03-13 06:46:50 -07002016 /**
2017 * This method is called during layout when there have been calls to requestLayout() during
2018 * layout. It walks through the list of views that requested layout to determine which ones
2019 * still need it, based on visibility in the hierarchy and whether they have already been
2020 * handled (as is usually the case with ListView children).
2021 *
2022 * @param layoutRequesters The list of views that requested layout during layout
2023 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2024 * If so, the FORCE_LAYOUT flag was not set on requesters.
2025 * @return A list of the actual views that still need to be laid out.
2026 */
2027 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2028 boolean secondLayoutRequests) {
2029
2030 int numViewsRequestingLayout = layoutRequesters.size();
2031 ArrayList<View> validLayoutRequesters = null;
2032 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2033 View view = layoutRequesters.get(i);
2034 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2035 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2036 View.PFLAG_FORCE_LAYOUT)) {
2037 boolean gone = false;
2038 View parent = view;
2039 // Only trigger new requests for views in a non-GONE hierarchy
2040 while (parent != null) {
2041 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2042 gone = true;
2043 break;
2044 }
2045 if (parent.mParent instanceof View) {
2046 parent = (View) parent.mParent;
2047 } else {
2048 parent = null;
2049 }
2050 }
2051 if (!gone) {
2052 if (validLayoutRequesters == null) {
2053 validLayoutRequesters = new ArrayList<View>();
2054 }
2055 validLayoutRequesters.add(view);
2056 }
2057 }
2058 }
2059 if (!secondLayoutRequests) {
2060 // If we're checking the layout flags, then we need to clean them up also
2061 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2062 View view = layoutRequesters.get(i);
2063 while (view != null &&
2064 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2065 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2066 if (view.mParent instanceof View) {
2067 view = (View) view.mParent;
2068 } else {
2069 view = null;
2070 }
2071 }
2072 }
2073 }
2074 layoutRequesters.clear();
2075 return validLayoutRequesters;
2076 }
2077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 public void requestTransparentRegion(View child) {
2079 // the test below should not fail unless someone is messing with us
2080 checkThread();
2081 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002082 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 // Need to make sure we re-evaluate the window attributes next
2084 // time around, to ensure the window has the correct format.
2085 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002086 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002087 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 }
2089 }
2090
2091 /**
2092 * Figures out the measure spec for the root view in a window based on it's
2093 * layout params.
2094 *
2095 * @param windowSize
2096 * The available width or height of the window
2097 *
2098 * @param rootDimension
2099 * The layout params for one dimension (width or height) of the
2100 * window.
2101 *
2102 * @return The measure spec to use to measure the root view.
2103 */
Romain Guya998dff2012-03-23 18:58:36 -07002104 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 int measureSpec;
2106 switch (rootDimension) {
2107
Romain Guy980a9382010-01-08 15:06:28 -08002108 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 // Window can't resize. Force root view to be windowSize.
2110 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2111 break;
2112 case ViewGroup.LayoutParams.WRAP_CONTENT:
2113 // Window can resize. Set max size for root view.
2114 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2115 break;
2116 default:
2117 // Window wants to be an exact size. Force root view to be that size.
2118 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2119 break;
2120 }
2121 return measureSpec;
2122 }
2123
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002124 int mHardwareYOffset;
2125 int mResizeAlpha;
2126 final Paint mResizePaint = new Paint();
2127
Romain Guy7d70fbf2011-05-24 17:40:25 -07002128 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002129 canvas.translate(0, -mHardwareYOffset);
2130 }
2131
Romain Guy7d70fbf2011-05-24 17:40:25 -07002132 public void onHardwarePostDraw(HardwareCanvas canvas) {
2133 if (mResizeBuffer != null) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002134 mResizePaint.setAlpha(mResizeAlpha);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002135 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002136 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002137 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002138 }
2139
Chet Haaseed30fd82011-04-22 16:18:45 -07002140 /**
2141 * @hide
2142 */
2143 void outputDisplayList(View view) {
2144 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
Chet Haaseed30fd82011-04-22 16:18:45 -07002145 DisplayList displayList = view.getDisplayList();
2146 if (displayList != null) {
Romain Guy59a12ca2011-06-09 17:48:21 -07002147 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
2148 }
2149 }
2150 }
2151
2152 /**
2153 * @see #PROPERTY_PROFILE_RENDERING
2154 */
2155 private void profileRendering(boolean enabled) {
2156 if (mProfileRendering) {
2157 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002158
2159 if (mRenderProfiler != null) {
2160 mChoreographer.removeFrameCallback(mRenderProfiler);
2161 }
2162 if (mRenderProfilingEnabled) {
2163 if (mRenderProfiler == null) {
2164 mRenderProfiler = new Choreographer.FrameCallback() {
2165 @Override
2166 public void doFrame(long frameTimeNanos) {
2167 mDirty.set(0, 0, mWidth, mHeight);
2168 scheduleTraversals();
2169 if (mRenderProfilingEnabled) {
2170 mChoreographer.postFrameCallback(mRenderProfiler);
2171 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002172 }
Chris Craikae4f32042013-02-07 12:57:10 -08002173 };
2174 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002175 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002176 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002177 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002178 }
2179 }
2180 }
2181
Chet Haase2f2022a2011-10-11 06:41:59 -07002182 /**
2183 * Called from draw() when DEBUG_FPS is enabled
2184 */
2185 private void trackFPS() {
2186 // Tracks frames per second drawn. First value in a series of draws may be bogus
2187 // because it down not account for the intervening idle time
2188 long nowTime = System.currentTimeMillis();
2189 if (mFpsStartTime < 0) {
2190 mFpsStartTime = mFpsPrevTime = nowTime;
2191 mFpsNumFrames = 0;
2192 } else {
2193 ++mFpsNumFrames;
2194 String thisHash = Integer.toHexString(System.identityHashCode(this));
2195 long frameTime = nowTime - mFpsPrevTime;
2196 long totalTime = nowTime - mFpsStartTime;
2197 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2198 mFpsPrevTime = nowTime;
2199 if (totalTime > 1000) {
2200 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2201 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2202 mFpsStartTime = nowTime;
2203 mFpsNumFrames = 0;
2204 }
2205 }
2206 }
2207
Jeff Brown96e942d2011-11-30 19:55:01 -08002208 private void performDraw() {
Craig Mautner006f0e42012-03-21 11:00:32 -07002209 if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2210 return;
2211 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002212
Jeff Brown96e942d2011-11-30 19:55:01 -08002213 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2214 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002215
Romain Guy1f59e5c2012-05-06 14:11:16 -07002216 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002217 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2218 try {
2219 draw(fullRedrawNeeded);
2220 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002221 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002222 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2223 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002224
Jeff Brown96e942d2011-11-30 19:55:01 -08002225 if (mReportNextDraw) {
2226 mReportNextDraw = false;
2227
2228 if (LOCAL_LOGV) {
2229 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2230 }
2231 if (mSurfaceHolder != null && mSurface.isValid()) {
2232 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2233 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2234 if (callbacks != null) {
2235 for (SurfaceHolder.Callback c : callbacks) {
2236 if (c instanceof SurfaceHolder.Callback2) {
2237 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2238 mSurfaceHolder);
2239 }
2240 }
2241 }
2242 }
2243 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002244 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002245 } catch (RemoteException e) {
2246 }
2247 }
2248 }
2249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 private void draw(boolean fullRedrawNeeded) {
2251 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002252 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 return;
2254 }
2255
Chet Haase2f2022a2011-10-11 06:41:59 -07002256 if (DEBUG_FPS) {
2257 trackFPS();
2258 }
2259
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002260 if (!sFirstDrawComplete) {
2261 synchronized (sFirstDrawHandlers) {
2262 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002263 final int count = sFirstDrawHandlers.size();
2264 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002265 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002266 }
2267 }
2268 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 scrollToRectOrFocus(null, false);
2271
Romain Guy25eba5c2012-04-04 17:29:03 -07002272 final AttachInfo attachInfo = mAttachInfo;
2273 if (attachInfo.mViewScrollChanged) {
2274 attachInfo.mViewScrollChanged = false;
2275 attachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 }
Romain Guy8506ab42009-06-11 17:35:47 -07002277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002279 boolean animating = mScroller != null && mScroller.computeScrollOffset();
2280 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281 yoff = mScroller.getCurrY();
2282 } else {
2283 yoff = mScrollY;
2284 }
2285 if (mCurScrollY != yoff) {
2286 mCurScrollY = yoff;
2287 fullRedrawNeeded = true;
2288 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002289
Romain Guy25eba5c2012-04-04 17:29:03 -07002290 final float appScale = attachInfo.mApplicationScale;
2291 final boolean scalingRequired = attachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002293 int resizeAlpha = 0;
Romain Guy7d70fbf2011-05-24 17:40:25 -07002294 if (mResizeBuffer != null) {
2295 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2296 if (deltaTime < mResizeBufferDuration) {
2297 float amt = deltaTime/(float) mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002298 amt = mResizeInterpolator.getInterpolation(amt);
2299 animating = true;
2300 resizeAlpha = 255 - (int)(amt*255);
2301 } else {
Romain Guy7d70fbf2011-05-24 17:40:25 -07002302 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002303 }
2304 }
2305
Jeff Brown96e942d2011-11-30 19:55:01 -08002306 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002307 if (mSurfaceHolder != null) {
2308 // The app owns the surface, we won't draw.
2309 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002310 if (animating) {
2311 if (mScroller != null) {
2312 mScroller.abortAnimation();
2313 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07002314 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002315 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002316 return;
2317 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002318
2319 if (fullRedrawNeeded) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002320 attachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002321 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002322 }
Chet Haasead4f7032011-06-22 09:18:31 -07002323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002325 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 + mWindowAttributes.getTitle()
2327 + ": dirty={" + dirty.left + "," + dirty.top
2328 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002329 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2330 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 }
2332
Romain Guyfbb93fa2012-12-03 18:50:35 -08002333 invalidateDisplayLists();
2334
Romain Guy25eba5c2012-04-04 17:29:03 -07002335 attachInfo.mTreeObserver.dispatchOnDraw();
2336
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002337 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002338 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002339 // Draw with hardware renderer.
2340 mIsAnimating = false;
2341 mHardwareYOffset = yoff;
2342 mResizeAlpha = resizeAlpha;
Romain Guyfea12b82011-01-27 15:36:40 -08002343
Jeff Brown96e942d2011-11-30 19:55:01 -08002344 mCurrentDirty.set(dirty);
Jeff Brown96e942d2011-11-30 19:55:01 -08002345 dirty.setEmpty();
2346
Romain Guye55945e2013-04-04 15:26:04 -07002347 attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
2348 animating ? null : mCurrentDirty);
Romain Guy3696779b2013-01-28 14:04:07 -08002349 } else {
2350 // If we get here with a disabled & requested hardware renderer, something went
2351 // wrong (an invalidate posted right before we destroyed the hardware surface
2352 // for instance) so we should just bail out. Locking the surface with software
2353 // rendering at this point would lock it forever and prevent hardware renderer
2354 // from doing its job when it comes back.
2355 // Before we request a new frame we must however attempt to reinitiliaze the
2356 // hardware renderer if it's in requested state. This would happen after an
2357 // eglTerminate() for instance.
2358 if (attachInfo.mHardwareRenderer != null &&
2359 !attachInfo.mHardwareRenderer.isEnabled() &&
2360 attachInfo.mHardwareRenderer.isRequested()) {
2361
2362 try {
2363 attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
2364 mHolder.getSurface());
2365 } catch (Surface.OutOfResourcesException e) {
2366 handleOutOfResourcesException(e);
2367 return;
2368 }
2369
2370 mFullRedrawNeeded = true;
2371 scheduleTraversals();
2372 return;
2373 }
2374
2375 if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2376 return;
2377 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002379 }
Romain Guy8506ab42009-06-11 17:35:47 -07002380
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002381 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002382 mFullRedrawNeeded = true;
2383 scheduleTraversals();
2384 }
2385 }
2386
Romain Guy25eba5c2012-04-04 17:29:03 -07002387 /**
Romain Guyedbca122012-04-04 18:25:53 -07002388 * @return true if drawing was succesfull, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002389 */
2390 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2391 boolean scalingRequired, Rect dirty) {
2392
2393 // Draw with software renderer.
2394 Canvas canvas;
2395 try {
2396 int left = dirty.left;
2397 int top = dirty.top;
2398 int right = dirty.right;
2399 int bottom = dirty.bottom;
2400
Romain Guy25eba5c2012-04-04 17:29:03 -07002401 canvas = mSurface.lockCanvas(dirty);
2402
Romain Guye55945e2013-04-04 15:26:04 -07002403 // The dirty rectangle can be modified by Surface.lockCanvas()
2404 //noinspection ConstantConditions
Romain Guy25eba5c2012-04-04 17:29:03 -07002405 if (left != dirty.left || top != dirty.top || right != dirty.right ||
2406 bottom != dirty.bottom) {
2407 attachInfo.mIgnoreDirtyState = true;
2408 }
2409
2410 // TODO: Do this in native
2411 canvas.setDensity(mDensity);
2412 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002413 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002414 return false;
2415 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002416 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002417 // Don't assume this is due to out of memory, it could be
2418 // something else, and if it is something else then we could
2419 // kill stuff (or ourself) for no reason.
2420 mLayoutRequested = true; // ask wm for a new surface next time.
2421 return false;
2422 }
2423
2424 try {
2425 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2426 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2427 + canvas.getWidth() + ", h=" + canvas.getHeight());
2428 //canvas.drawARGB(255, 255, 0, 0);
2429 }
2430
Romain Guy25eba5c2012-04-04 17:29:03 -07002431 // If this bitmap's format includes an alpha channel, we
2432 // need to clear it before drawing so that the child will
2433 // properly re-composite its drawing on a transparent
2434 // background. This automatically respects the clip/dirty region
2435 // or
2436 // If we are applying an offset, we need to clear the area
2437 // where the offset doesn't appear to avoid having garbage
2438 // left in the blank areas.
2439 if (!canvas.isOpaque() || yoff != 0) {
2440 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2441 }
2442
2443 dirty.setEmpty();
2444 mIsAnimating = false;
2445 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002446 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002447
2448 if (DEBUG_DRAW) {
2449 Context cxt = mView.getContext();
2450 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2451 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2452 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2453 }
2454 try {
2455 canvas.translate(0, -yoff);
2456 if (mTranslator != null) {
2457 mTranslator.translateCanvas(canvas);
2458 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002459 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002460 attachInfo.mSetIgnoreDirtyState = false;
2461
Romain Guy25eba5c2012-04-04 17:29:03 -07002462 mView.draw(canvas);
2463
Svetoslav Ganov42138042012-03-20 11:51:39 -07002464 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002465 } finally {
2466 if (!attachInfo.mSetIgnoreDirtyState) {
2467 // Only clear the flag if it was not set during the mView.draw() call
2468 attachInfo.mIgnoreDirtyState = false;
2469 }
2470 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002471 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002472 try {
2473 surface.unlockCanvasAndPost(canvas);
2474 } catch (IllegalArgumentException e) {
2475 Log.e(TAG, "Could not unlock surface", e);
2476 mLayoutRequested = true; // ask wm for a new surface next time.
2477 //noinspection ReturnInsideFinallyBlock
2478 return false;
2479 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002480
Romain Guy25eba5c2012-04-04 17:29:03 -07002481 if (LOCAL_LOGV) {
2482 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2483 }
2484 }
2485 return true;
2486 }
2487
Svetoslav Ganov42138042012-03-20 11:51:39 -07002488 /**
2489 * We want to draw a highlight around the current accessibility focused.
2490 * Since adding a style for all possible view is not a viable option we
2491 * have this specialized drawing method.
2492 *
2493 * Note: We are doing this here to be able to draw the highlight for
2494 * virtual views in addition to real ones.
2495 *
2496 * @param canvas The canvas on which to draw.
2497 */
2498 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
Svetoslav Ganov07b726c2012-04-30 12:24:57 -07002499 AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2500 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002501 return;
2502 }
2503 if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
2504 return;
2505 }
2506 Drawable drawable = getAccessibilityFocusedDrawable();
2507 if (drawable == null) {
2508 return;
2509 }
2510 AccessibilityNodeProvider provider =
2511 mAccessibilityFocusedHost.getAccessibilityNodeProvider();
2512 Rect bounds = mView.mAttachInfo.mTmpInvalRect;
2513 if (provider == null) {
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002514 mAccessibilityFocusedHost.getBoundsOnScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002515 } else {
2516 if (mAccessibilityFocusedVirtualView == null) {
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07002517 return;
2518 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002519 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002520 }
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002521 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Svetoslav Ganova94c3192012-10-31 18:28:49 -07002522 bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002523 drawable.setBounds(bounds);
2524 drawable.draw(canvas);
2525 }
2526
2527 private Drawable getAccessibilityFocusedDrawable() {
2528 if (mAttachInfo != null) {
2529 // Lazily load the accessibility focus drawable.
2530 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2531 TypedValue value = new TypedValue();
2532 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2533 R.attr.accessibilityFocusedDrawable, value, true);
2534 if (resolved) {
2535 mAttachInfo.mAccessibilityFocusDrawable =
2536 mView.mContext.getResources().getDrawable(value.resourceId);
2537 }
2538 }
2539 return mAttachInfo.mAccessibilityFocusDrawable;
2540 }
2541 return null;
2542 }
2543
Romain Guy51e4d4d2012-03-15 18:30:47 -07002544 void invalidateDisplayLists() {
2545 final ArrayList<DisplayList> displayLists = mDisplayLists;
2546 final int count = displayLists.size();
2547
2548 for (int i = 0; i < count; i++) {
Romain Guy38c2ece2012-05-24 14:20:56 -07002549 final DisplayList displayList = displayLists.get(i);
Romain Guyfbb93fa2012-12-03 18:50:35 -08002550 if (displayList.isDirty()) {
Romain Guyfbb93fa2012-12-03 18:50:35 -08002551 displayList.clear();
Romain Guyfbb93fa2012-12-03 18:50:35 -08002552 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07002553 }
2554
2555 displayLists.clear();
2556 }
2557
Michael Jurkaf42d90102013-05-08 18:00:04 +02002558 /**
2559 * @hide
2560 */
2561 public void setDrawDuringWindowsAnimating(boolean value) {
2562 mDrawDuringWindowsAnimating = value;
2563 if (value) {
2564 handleDispatchDoneAnimating();
2565 }
2566 }
2567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002568 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2569 final View.AttachInfo attachInfo = mAttachInfo;
2570 final Rect ci = attachInfo.mContentInsets;
2571 final Rect vi = attachInfo.mVisibleInsets;
2572 int scrollY = 0;
2573 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002575 if (vi.left > ci.left || vi.top > ci.top
2576 || vi.right > ci.right || vi.bottom > ci.bottom) {
2577 // We'll assume that we aren't going to change the scroll
2578 // offset, since we want to avoid that unless it is actually
2579 // going to make the focus visible... otherwise we scroll
2580 // all over the place.
2581 scrollY = mScrollY;
2582 // We can be called for two different situations: during a draw,
2583 // to update the scroll position if the focus has changed (in which
2584 // case 'rectangle' is null), or in response to a
2585 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2586 // is non-null and we just want to scroll to whatever that
2587 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002588 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002589 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002590 return false;
2591 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002592 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002593 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002594 // If the focus has changed, then ignore any requests to scroll
2595 // to a rectangle; first we want to make sure the entire focus
2596 // view is visible.
2597 rectangle = null;
2598 }
2599 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2600 + " rectangle=" + rectangle + " ci=" + ci
2601 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002602 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603 // Optimization: if the focus hasn't changed since last
2604 // time, and no layout has happened, then just leave things
2605 // as they are.
2606 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2607 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002608 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 // We need to determine if the currently focused view is
2610 // within the visible part of the window and, if not, apply
2611 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002612 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 mScrollMayChange = false;
2614 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2615 // Try to find the rectangle from the focus view.
2616 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2617 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2618 + mView.getWidth() + " h=" + mView.getHeight()
2619 + " ci=" + ci.toShortString()
2620 + " vi=" + vi.toShortString());
2621 if (rectangle == null) {
2622 focus.getFocusedRect(mTempRect);
2623 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2624 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002625 if (mView instanceof ViewGroup) {
2626 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2627 focus, mTempRect);
2628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2630 "Focus in window: focusRect="
2631 + mTempRect.toShortString()
2632 + " visRect=" + mVisRect.toShortString());
2633 } else {
2634 mTempRect.set(rectangle);
2635 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2636 "Request scroll to rect: "
2637 + mTempRect.toShortString()
2638 + " visRect=" + mVisRect.toShortString());
2639 }
2640 if (mTempRect.intersect(mVisRect)) {
2641 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2642 "Focus window visible rect: "
2643 + mTempRect.toShortString());
2644 if (mTempRect.height() >
2645 (mView.getHeight()-vi.top-vi.bottom)) {
2646 // If the focus simply is not going to fit, then
2647 // best is probably just to leave things as-is.
2648 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2649 "Too tall; leaving scrollY=" + scrollY);
2650 } else if ((mTempRect.top-scrollY) < vi.top) {
2651 scrollY -= vi.top - (mTempRect.top-scrollY);
2652 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2653 "Top covered; scrollY=" + scrollY);
2654 } else if ((mTempRect.bottom-scrollY)
2655 > (mView.getHeight()-vi.bottom)) {
2656 scrollY += (mTempRect.bottom-scrollY)
2657 - (mView.getHeight()-vi.bottom);
2658 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2659 "Bottom covered; scrollY=" + scrollY);
2660 }
2661 handled = true;
2662 }
2663 }
2664 }
2665 }
Romain Guy8506ab42009-06-11 17:35:47 -07002666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 if (scrollY != mScrollY) {
2668 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2669 + mScrollY + " , new=" + scrollY);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002670 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 if (mScroller == null) {
2672 mScroller = new Scroller(mView.getContext());
2673 }
2674 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2675 } else if (mScroller != null) {
2676 mScroller.abortAnimation();
2677 }
2678 mScrollY = scrollY;
2679 }
Romain Guy8506ab42009-06-11 17:35:47 -07002680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 return handled;
2682 }
Romain Guy8506ab42009-06-11 17:35:47 -07002683
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002684 /**
2685 * @hide
2686 */
2687 public View getAccessibilityFocusedHost() {
2688 return mAccessibilityFocusedHost;
2689 }
2690
2691 /**
2692 * @hide
2693 */
2694 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2695 return mAccessibilityFocusedVirtualView;
2696 }
2697
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002698 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002699 // If we have a virtual view with accessibility focus we need
2700 // to clear the focus and invalidate the virtual view bounds.
2701 if (mAccessibilityFocusedVirtualView != null) {
2702
2703 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2704 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002705
2706 // Wipe the state of the current accessibility focus since
2707 // the call into the provider to clear accessibility focus
2708 // will fire an accessibility event which will end up calling
2709 // this method and we want to have clean state when this
2710 // invocation happens.
2711 mAccessibilityFocusedHost = null;
2712 mAccessibilityFocusedVirtualView = null;
2713
Alan Viverette239a0c02013-05-07 17:17:35 -07002714 // Clear accessibility focus on the host after clearing state since
2715 // this method may be reentrant.
2716 focusHost.clearAccessibilityFocusNoCallbacks();
2717
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002718 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2719 if (provider != null) {
2720 // Invalidate the area of the cleared accessibility focus.
2721 focusNode.getBoundsInParent(mTempRect);
2722 focusHost.invalidate(mTempRect);
2723 // Clear accessibility focus in the virtual node.
2724 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2725 focusNode.getSourceNodeId());
2726 provider.performAction(virtualNodeId,
2727 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2728 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002729 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002730 }
2731 if (mAccessibilityFocusedHost != null) {
2732 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002733 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2734 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002735
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002736 // Set the new focus host and node.
2737 mAccessibilityFocusedHost = view;
2738 mAccessibilityFocusedVirtualView = node;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002739 }
2740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002742 if (DEBUG_INPUT_RESIZE) {
2743 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002745 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002746 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002747 }
2748
2749 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002750 if (DEBUG_INPUT_RESIZE) {
2751 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002752 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002753 checkThread();
2754 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002755 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002756
Svetoslav Ganov42138042012-03-20 11:51:39 -07002757 @Override
2758 public ViewParent getParentForAccessibility() {
2759 return null;
2760 }
2761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002762 public void focusableViewAvailable(View v) {
2763 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002764 if (mView != null) {
2765 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002767 } else {
2768 // the one case where will transfer focus away from the current one
2769 // is if the current view is a view group that prefers to give focus
2770 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002771 View focused = mView.findFocus();
2772 if (focused instanceof ViewGroup) {
2773 ViewGroup group = (ViewGroup) focused;
2774 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2775 && isViewDescendantOf(v, focused)) {
2776 v.requestFocus();
2777 }
Romain Guy1c90f032011-05-24 14:59:50 -07002778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 }
2780 }
2781 }
2782
2783 public void recomputeViewAttributes(View child) {
2784 checkThread();
2785 if (mView == child) {
2786 mAttachInfo.mRecomputeGlobalAttributes = true;
2787 if (!mWillDrawSoon) {
2788 scheduleTraversals();
2789 }
2790 }
2791 }
2792
2793 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002794 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002795 if (mAttachInfo.mHardwareRenderer != null &&
2796 mAttachInfo.mHardwareRenderer.isEnabled()) {
2797 mAttachInfo.mHardwareRenderer.validate();
2798 }
Dianne Hackborn961cae92013-03-20 14:59:43 -07002799 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002800 mView.dispatchDetachedFromWindow();
2801 }
2802
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002803 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2804 mAccessibilityManager.removeAccessibilityStateChangeListener(
2805 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002806 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002807
Romain Guya998dff2012-03-23 18:58:36 -07002808 destroyHardwareRenderer();
2809
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002810 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002811
Craig Mautner8f303ad2013-06-14 11:32:22 -07002812 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002813 mView = null;
2814 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07002815 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002816
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002817 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002818
Jeff Browncc4f7db2011-08-30 20:34:48 -07002819 if (mInputQueueCallback != null && mInputQueue != null) {
2820 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002821 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002822 mInputQueueCallback = null;
2823 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002824 }
2825 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002826 mInputEventReceiver.dispose();
2827 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002828 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002830 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 } catch (RemoteException e) {
2832 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07002833
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002834 // Dispose the input channel after removing the window so the Window Manager
2835 // doesn't interpret the input channel being closed as an abnormal termination.
2836 if (mInputChannel != null) {
2837 mInputChannel.dispose();
2838 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002839 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002840
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002841 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002842 }
Romain Guy8506ab42009-06-11 17:35:47 -07002843
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002844 void updateConfiguration(Configuration config, boolean force) {
2845 if (DEBUG_CONFIGURATION) Log.v(TAG,
2846 "Applying new config to window "
2847 + mWindowAttributes.getTitle()
2848 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002849
Craig Mautner48d0d182013-06-11 07:53:06 -07002850 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
2851 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002852 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002853 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002854 }
2855
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002856 synchronized (sConfigCallbacks) {
2857 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2858 sConfigCallbacks.get(i).onConfigurationChanged(config);
2859 }
2860 }
2861 if (mView != null) {
2862 // At this point the resources have been updated to
2863 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002864 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002865 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002866 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002867 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2868 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002869 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07002870 if (lastLayoutDirection != currentLayoutDirection &&
2871 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002872 mView.setLayoutDirection(currentLayoutDirection);
2873 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002874 mView.dispatchConfigurationChanged(config);
2875 }
2876 }
2877 }
2878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 /**
2880 * Return true if child is an ancestor of parent, (or equal to the parent).
2881 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002882 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 if (child == parent) {
2884 return true;
2885 }
2886
2887 final ViewParent theParent = child.getParent();
2888 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2889 }
2890
Romain Guycdb86672010-03-18 18:54:50 -07002891 private static void forceLayout(View view) {
2892 view.forceLayout();
2893 if (view instanceof ViewGroup) {
2894 ViewGroup group = (ViewGroup) view;
2895 final int count = group.getChildCount();
2896 for (int i = 0; i < count; i++) {
2897 forceLayout(group.getChildAt(i));
2898 }
2899 }
2900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002901
Jeff Browna175a5b2012-02-15 19:18:31 -08002902 private final static int MSG_INVALIDATE = 1;
2903 private final static int MSG_INVALIDATE_RECT = 2;
2904 private final static int MSG_DIE = 3;
2905 private final static int MSG_RESIZED = 4;
2906 private final static int MSG_RESIZED_REPORT = 5;
2907 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
2908 private final static int MSG_DISPATCH_KEY = 7;
2909 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2910 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08002911 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2912 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2913 private final static int MSG_CHECK_FOCUS = 13;
2914 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2915 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2916 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2917 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2918 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002919 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2920 private final static int MSG_DISPATCH_SCREEN_STATE = 20;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002921 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
2922 private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
2923 private final static int MSG_INVALIDATE_WORLD = 23;
2924 private final static int MSG_WINDOW_MOVED = 24;
Romain Guy40543602013-06-12 15:31:28 -07002925 private final static int MSG_FLUSH_LAYER_UPDATES = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926
Jeff Browna175a5b2012-02-15 19:18:31 -08002927 final class ViewRootHandler extends Handler {
2928 @Override
2929 public String getMessageName(Message message) {
2930 switch (message.what) {
2931 case MSG_INVALIDATE:
2932 return "MSG_INVALIDATE";
2933 case MSG_INVALIDATE_RECT:
2934 return "MSG_INVALIDATE_RECT";
2935 case MSG_DIE:
2936 return "MSG_DIE";
2937 case MSG_RESIZED:
2938 return "MSG_RESIZED";
2939 case MSG_RESIZED_REPORT:
2940 return "MSG_RESIZED_REPORT";
2941 case MSG_WINDOW_FOCUS_CHANGED:
2942 return "MSG_WINDOW_FOCUS_CHANGED";
2943 case MSG_DISPATCH_KEY:
2944 return "MSG_DISPATCH_KEY";
2945 case MSG_DISPATCH_APP_VISIBILITY:
2946 return "MSG_DISPATCH_APP_VISIBILITY";
2947 case MSG_DISPATCH_GET_NEW_SURFACE:
2948 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08002949 case MSG_DISPATCH_KEY_FROM_IME:
2950 return "MSG_DISPATCH_KEY_FROM_IME";
2951 case MSG_FINISH_INPUT_CONNECTION:
2952 return "MSG_FINISH_INPUT_CONNECTION";
2953 case MSG_CHECK_FOCUS:
2954 return "MSG_CHECK_FOCUS";
2955 case MSG_CLOSE_SYSTEM_DIALOGS:
2956 return "MSG_CLOSE_SYSTEM_DIALOGS";
2957 case MSG_DISPATCH_DRAG_EVENT:
2958 return "MSG_DISPATCH_DRAG_EVENT";
2959 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
2960 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
2961 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
2962 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
2963 case MSG_UPDATE_CONFIGURATION:
2964 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08002965 case MSG_PROCESS_INPUT_EVENTS:
2966 return "MSG_PROCESS_INPUT_EVENTS";
Romain Guy51e4d4d2012-03-15 18:30:47 -07002967 case MSG_DISPATCH_SCREEN_STATE:
2968 return "MSG_DISPATCH_SCREEN_STATE";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07002969 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
2970 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07002971 case MSG_DISPATCH_DONE_ANIMATING:
2972 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07002973 case MSG_WINDOW_MOVED:
2974 return "MSG_WINDOW_MOVED";
Romain Guy40543602013-06-12 15:31:28 -07002975 case MSG_FLUSH_LAYER_UPDATES:
2976 return "MSG_FLUSH_LAYER_UPDATES";
Jeff Browna175a5b2012-02-15 19:18:31 -08002977 }
2978 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07002979 }
Romain Guyf9284692011-07-13 18:46:21 -07002980
Jeff Browna175a5b2012-02-15 19:18:31 -08002981 @Override
2982 public void handleMessage(Message msg) {
2983 switch (msg.what) {
2984 case MSG_INVALIDATE:
2985 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08002987 case MSG_INVALIDATE_RECT:
2988 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
2989 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08002990 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08002991 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08002992 case MSG_PROCESS_INPUT_EVENTS:
2993 mProcessInputEventsScheduled = false;
2994 doProcessInputEvents();
2995 break;
2996 case MSG_DISPATCH_APP_VISIBILITY:
2997 handleAppVisibility(msg.arg1 != 0);
2998 break;
2999 case MSG_DISPATCH_GET_NEW_SURFACE:
3000 handleGetNewSurface();
3001 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003002 case MSG_RESIZED: {
3003 // Recycled in the fall through...
3004 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003005 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003006 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003007 && mPendingContentInsets.equals(args.arg2)
3008 && mPendingVisibleInsets.equals(args.arg3)
3009 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003010 break;
Romain Guycdb86672010-03-18 18:54:50 -07003011 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003012 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003013 case MSG_RESIZED_REPORT:
3014 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003015 SomeArgs args = (SomeArgs) msg.obj;
3016
3017 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003018 if (config != null) {
3019 updateConfiguration(config, false);
3020 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003021
3022 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003023 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003024 mPendingContentInsets.set((Rect) args.arg2);
3025 mPendingVisibleInsets.set((Rect) args.arg3);
3026
3027 args.recycle();
3028
Jeff Browna175a5b2012-02-15 19:18:31 -08003029 if (msg.what == MSG_RESIZED_REPORT) {
3030 mReportNextDraw = true;
3031 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003032
Jeff Browna175a5b2012-02-15 19:18:31 -08003033 if (mView != null) {
3034 forceLayout(mView);
3035 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003036
Jeff Browna175a5b2012-02-15 19:18:31 -08003037 requestLayout();
3038 }
3039 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003040 case MSG_WINDOW_MOVED:
3041 if (mAdded) {
3042 final int w = mWinFrame.width();
3043 final int h = mWinFrame.height();
3044 final int l = msg.arg1;
3045 final int t = msg.arg2;
3046 mWinFrame.left = l;
3047 mWinFrame.right = l + w;
3048 mWinFrame.top = t;
3049 mWinFrame.bottom = t + h;
3050
3051 if (mView != null) {
3052 forceLayout(mView);
3053 }
3054 requestLayout();
3055 }
3056 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003057 case MSG_WINDOW_FOCUS_CHANGED: {
3058 if (mAdded) {
3059 boolean hasWindowFocus = msg.arg1 != 0;
3060 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061
Jeff Browna175a5b2012-02-15 19:18:31 -08003062 profileRendering(hasWindowFocus);
3063
3064 if (hasWindowFocus) {
3065 boolean inTouchMode = msg.arg2 != 0;
3066 ensureTouchModeLocally(inTouchMode);
3067
Romain Guye55945e2013-04-04 15:26:04 -07003068 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003069 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003070 try {
Romain Guy3696779b2013-01-28 14:04:07 -08003071 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
3072 mWidth, mHeight, mHolder.getSurface());
Jeff Browna175a5b2012-02-15 19:18:31 -08003073 } catch (Surface.OutOfResourcesException e) {
3074 Log.e(TAG, "OutOfResourcesException locking surface", e);
3075 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003076 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003077 Slog.w(TAG, "No processes killed for memory; killing self");
3078 Process.killProcess(Process.myPid());
3079 }
3080 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003081 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003082 // Retry in a bit.
3083 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3084 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003085 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003087 }
Romain Guy8506ab42009-06-11 17:35:47 -07003088
Jeff Browna175a5b2012-02-15 19:18:31 -08003089 mLastWasImTarget = WindowManager.LayoutParams
3090 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003091
Jeff Browna175a5b2012-02-15 19:18:31 -08003092 InputMethodManager imm = InputMethodManager.peekInstance();
3093 if (mView != null) {
3094 if (hasWindowFocus && imm != null && mLastWasImTarget) {
3095 imm.startGettingWindowFocus(mView);
3096 }
3097 mAttachInfo.mKeyDispatchState.reset();
3098 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003099 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003101
Jeff Browna175a5b2012-02-15 19:18:31 -08003102 // Note: must be done after the focus change callbacks,
3103 // so all of the view state is set up correctly.
3104 if (hasWindowFocus) {
3105 if (imm != null && mLastWasImTarget) {
3106 imm.onWindowFocus(mView, mView.findFocus(),
3107 mWindowAttributes.softInputMode,
3108 !mHasHadWindowFocus, mWindowAttributes.flags);
3109 }
3110 // Clear the forward bit. We can just do this directly, since
3111 // the window manager doesn't care about it.
3112 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003114 ((WindowManager.LayoutParams)mView.getLayoutParams())
3115 .softInputMode &=
3116 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3117 mHasHadWindowFocus = true;
3118 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003119
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003120 setAccessibilityFocus(null, null);
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07003121
Svetoslav Ganov42138042012-03-20 11:51:39 -07003122 if (mView != null && mAccessibilityManager.isEnabled()) {
3123 if (hasWindowFocus) {
3124 mView.sendAccessibilityEvent(
3125 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003126 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003127 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003128 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003129 } break;
3130 case MSG_DIE:
3131 doDie();
3132 break;
3133 case MSG_DISPATCH_KEY: {
3134 KeyEvent event = (KeyEvent)msg.obj;
3135 enqueueInputEvent(event, null, 0, true);
3136 } break;
3137 case MSG_DISPATCH_KEY_FROM_IME: {
3138 if (LOCAL_LOGV) Log.v(
3139 TAG, "Dispatching key "
3140 + msg.obj + " from IME to " + mView);
3141 KeyEvent event = (KeyEvent)msg.obj;
3142 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3143 // The IME is trying to say this event is from the
3144 // system! Bad bad bad!
3145 //noinspection UnusedAssignment
3146 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
3147 }
3148 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3149 } break;
3150 case MSG_FINISH_INPUT_CONNECTION: {
3151 InputMethodManager imm = InputMethodManager.peekInstance();
3152 if (imm != null) {
3153 imm.reportFinishInputConnection((InputConnection)msg.obj);
3154 }
3155 } break;
3156 case MSG_CHECK_FOCUS: {
3157 InputMethodManager imm = InputMethodManager.peekInstance();
3158 if (imm != null) {
3159 imm.checkFocus();
3160 }
3161 } break;
3162 case MSG_CLOSE_SYSTEM_DIALOGS: {
3163 if (mView != null) {
3164 mView.onCloseSystemDialogs((String)msg.obj);
3165 }
3166 } break;
3167 case MSG_DISPATCH_DRAG_EVENT:
3168 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3169 DragEvent event = (DragEvent)msg.obj;
3170 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3171 handleDragEvent(event);
3172 } break;
3173 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003174 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003175 } break;
3176 case MSG_UPDATE_CONFIGURATION: {
3177 Configuration config = (Configuration)msg.obj;
3178 if (config.isOtherSeqNewer(mLastConfiguration)) {
3179 config = mLastConfiguration;
3180 }
3181 updateConfiguration(config, false);
3182 } break;
Romain Guybb9908b2012-03-08 11:14:07 -08003183 case MSG_DISPATCH_SCREEN_STATE: {
Romain Guy7e4e5612012-03-05 14:37:29 -08003184 if (mView != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08003185 handleScreenStateChange(msg.arg1 == 1);
Romain Guy7e4e5612012-03-05 14:37:29 -08003186 }
3187 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003188 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003189 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003190 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003191 case MSG_DISPATCH_DONE_ANIMATING: {
3192 handleDispatchDoneAnimating();
3193 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003194 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003195 if (mView != null) {
3196 invalidateWorld(mView);
3197 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003198 } break;
Romain Guy40543602013-06-12 15:31:28 -07003199 case MSG_FLUSH_LAYER_UPDATES: {
3200 flushHardwareLayerUpdates();
3201 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 }
3204 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003205
Jeff Browna175a5b2012-02-15 19:18:31 -08003206 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 /**
3209 * Something in the current window tells us we need to change the touch mode. For
3210 * example, we are not in touch mode, and the user touches the screen.
3211 *
3212 * If the touch mode has changed, tell the window manager, and handle it locally.
3213 *
3214 * @param inTouchMode Whether we want to be in touch mode.
3215 * @return True if the touch mode changed and focus changed was changed as a result
3216 */
3217 boolean ensureTouchMode(boolean inTouchMode) {
3218 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3219 + "touch mode is " + mAttachInfo.mInTouchMode);
3220 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3221
3222 // tell the window manager
3223 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003224 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 } catch (RemoteException e) {
3226 throw new RuntimeException(e);
3227 }
3228
3229 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003230 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 }
3232
3233 /**
3234 * Ensure that the touch mode for this window is set, and if it is changing,
3235 * take the appropriate action.
3236 * @param inTouchMode Whether we want to be in touch mode.
3237 * @return True if the touch mode changed and focus changed was changed as a result
3238 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003239 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3241 + "touch mode is " + mAttachInfo.mInTouchMode);
3242
3243 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3244
3245 mAttachInfo.mInTouchMode = inTouchMode;
3246 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3247
Romain Guy2d4cff62010-04-09 15:39:00 -07003248 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003249 }
3250
3251 private boolean enterTouchMode() {
3252 if (mView != null) {
3253 if (mView.hasFocus()) {
3254 // note: not relying on mFocusedView here because this could
3255 // be when the window is first being added, and mFocused isn't
3256 // set yet.
3257 final View focused = mView.findFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003258 if (focused != null && !focused.isFocusableInTouchMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003259 final ViewGroup ancestorToTakeFocus =
3260 findAncestorToTakeFocusInTouchMode(focused);
3261 if (ancestorToTakeFocus != null) {
3262 // there is an ancestor that wants focus after its descendants that
3263 // is focusable in touch mode.. give it focus
3264 return ancestorToTakeFocus.requestFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003265 } else {
3266 // nothing appropriate to have focus in touch mode, clear it out
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003267 focused.unFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003268 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 }
3270 }
3271 }
3272 }
3273 return false;
3274 }
3275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003276 /**
3277 * Find an ancestor of focused that wants focus after its descendants and is
3278 * focusable in touch mode.
3279 * @param focused The currently focused view.
3280 * @return An appropriate view, or null if no such view exists.
3281 */
Romain Guya998dff2012-03-23 18:58:36 -07003282 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 ViewParent parent = focused.getParent();
3284 while (parent instanceof ViewGroup) {
3285 final ViewGroup vgParent = (ViewGroup) parent;
3286 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3287 && vgParent.isFocusableInTouchMode()) {
3288 return vgParent;
3289 }
3290 if (vgParent.isRootNamespace()) {
3291 return null;
3292 } else {
3293 parent = vgParent.getParent();
3294 }
3295 }
3296 return null;
3297 }
3298
3299 private boolean leaveTouchMode() {
3300 if (mView != null) {
3301 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003302 View focusedView = mView.findFocus();
3303 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003305 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003306 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3308 // some view group has focus, and doesn't prefer its children
3309 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003310 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003311 }
3312 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003313
3314 // find the best view to give focus to in this brave new non-touch-mode
3315 // world
3316 final View focused = focusSearch(null, View.FOCUS_DOWN);
3317 if (focused != null) {
3318 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 }
3320 }
3321 return false;
3322 }
3323
Jeff Brownf9e989d2013-04-04 23:04:03 -07003324 /**
3325 * Base class for implementing a stage in the chain of responsibility
3326 * for processing input events.
3327 * <p>
3328 * Events are delivered to the stage by the {@link #deliver} method. The stage
3329 * then has the choice of finishing the event or forwarding it to the next stage.
3330 * </p>
3331 */
3332 abstract class InputStage {
3333 private final InputStage mNext;
3334
3335 protected static final int FORWARD = 0;
3336 protected static final int FINISH_HANDLED = 1;
3337 protected static final int FINISH_NOT_HANDLED = 2;
3338
3339 /**
3340 * Creates an input stage.
3341 * @param next The next stage to which events should be forwarded.
3342 */
3343 public InputStage(InputStage next) {
3344 mNext = next;
3345 }
3346
3347 /**
3348 * Delivers an event to be processed.
3349 */
3350 public final void deliver(QueuedInputEvent q) {
3351 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3352 forward(q);
3353 } else if (mView == null || !mAdded) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003354 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3355 finish(q, false);
3356 } else if (!mAttachInfo.mHasWindowFocus &&
3357 !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
3358 !isTerminalInputEvent(q.mEvent)) {
3359 // If this is a focused event and the window doesn't currently have input focus,
3360 // then drop this event. This could be an event that came back from the previous
3361 // stage but the window has lost focus in the meantime.
3362 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003363 finish(q, false);
3364 } else {
3365 apply(q, onProcess(q));
3366 }
3367 }
3368
3369 /**
3370 * Marks the the input event as finished then forwards it to the next stage.
3371 */
3372 protected void finish(QueuedInputEvent q, boolean handled) {
3373 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3374 if (handled) {
3375 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3376 }
3377 forward(q);
3378 }
3379
3380 /**
3381 * Forwards the event to the next stage.
3382 */
3383 protected void forward(QueuedInputEvent q) {
3384 onDeliverToNext(q);
3385 }
3386
3387 /**
3388 * Applies a result code from {@link #onProcess} to the specified event.
3389 */
3390 protected void apply(QueuedInputEvent q, int result) {
3391 if (result == FORWARD) {
3392 forward(q);
3393 } else if (result == FINISH_HANDLED) {
3394 finish(q, true);
3395 } else if (result == FINISH_NOT_HANDLED) {
3396 finish(q, false);
3397 } else {
3398 throw new IllegalArgumentException("Invalid result: " + result);
3399 }
3400 }
3401
3402 /**
3403 * Called when an event is ready to be processed.
3404 * @return A result code indicating how the event was handled.
3405 */
3406 protected int onProcess(QueuedInputEvent q) {
3407 return FORWARD;
3408 }
3409
3410 /**
3411 * Called when an event is being delivered to the next stage.
3412 */
3413 protected void onDeliverToNext(QueuedInputEvent q) {
3414 if (mNext != null) {
3415 mNext.deliver(q);
3416 } else {
3417 finishInputEvent(q);
3418 }
3419 }
3420 }
3421
3422 /**
3423 * Base class for implementing an input pipeline stage that supports
3424 * asynchronous and out-of-order processing of input events.
3425 * <p>
3426 * In addition to what a normal input stage can do, an asynchronous
3427 * input stage may also defer an input event that has been delivered to it
3428 * and finish or forward it later.
3429 * </p>
3430 */
3431 abstract class AsyncInputStage extends InputStage {
3432 private final String mTraceCounter;
3433
3434 private QueuedInputEvent mQueueHead;
3435 private QueuedInputEvent mQueueTail;
3436 private int mQueueLength;
3437
3438 protected static final int DEFER = 3;
3439
3440 /**
3441 * Creates an asynchronous input stage.
3442 * @param next The next stage to which events should be forwarded.
3443 * @param traceCounter The name of a counter to record the size of
3444 * the queue of pending events.
3445 */
3446 public AsyncInputStage(InputStage next, String traceCounter) {
3447 super(next);
3448 mTraceCounter = traceCounter;
3449 }
3450
3451 /**
3452 * Marks the event as deferred, which is to say that it will be handled
3453 * asynchronously. The caller is responsible for calling {@link #forward}
3454 * or {@link #finish} later when it is done handling the event.
3455 */
3456 protected void defer(QueuedInputEvent q) {
3457 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3458 enqueue(q);
3459 }
3460
3461 @Override
3462 protected void forward(QueuedInputEvent q) {
3463 // Clear the deferred flag.
3464 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3465
3466 // Fast path if the queue is empty.
3467 QueuedInputEvent curr = mQueueHead;
3468 if (curr == null) {
3469 super.forward(q);
3470 return;
3471 }
3472
3473 // Determine whether the event must be serialized behind any others
3474 // before it can be delivered to the next stage. This is done because
3475 // deferred events might be handled out of order by the stage.
3476 final int deviceId = q.mEvent.getDeviceId();
3477 QueuedInputEvent prev = null;
3478 boolean blocked = false;
3479 while (curr != null && curr != q) {
3480 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3481 blocked = true;
3482 }
3483 prev = curr;
3484 curr = curr.mNext;
3485 }
3486
3487 // If the event is blocked, then leave it in the queue to be delivered later.
3488 // Note that the event might not yet be in the queue if it was not previously
3489 // deferred so we will enqueue it if needed.
3490 if (blocked) {
3491 if (curr == null) {
3492 enqueue(q);
3493 }
3494 return;
3495 }
3496
3497 // The event is not blocked. Deliver it immediately.
3498 if (curr != null) {
3499 curr = curr.mNext;
3500 dequeue(q, prev);
3501 }
3502 super.forward(q);
3503
3504 // Dequeuing this event may have unblocked successors. Deliver them.
3505 while (curr != null) {
3506 if (deviceId == curr.mEvent.getDeviceId()) {
3507 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3508 break;
3509 }
3510 QueuedInputEvent next = curr.mNext;
3511 dequeue(curr, prev);
3512 super.forward(curr);
3513 curr = next;
3514 } else {
3515 prev = curr;
3516 curr = curr.mNext;
3517 }
3518 }
3519 }
3520
3521 @Override
3522 protected void apply(QueuedInputEvent q, int result) {
3523 if (result == DEFER) {
3524 defer(q);
3525 } else {
3526 super.apply(q, result);
3527 }
3528 }
3529
3530 private void enqueue(QueuedInputEvent q) {
3531 if (mQueueTail == null) {
3532 mQueueHead = q;
3533 mQueueTail = q;
3534 } else {
3535 mQueueTail.mNext = q;
3536 mQueueTail = q;
3537 }
3538
3539 mQueueLength += 1;
3540 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3541 }
3542
3543 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3544 if (prev == null) {
3545 mQueueHead = q.mNext;
3546 } else {
3547 prev.mNext = q.mNext;
3548 }
3549 if (mQueueTail == q) {
3550 mQueueTail = prev;
3551 }
3552 q.mNext = null;
3553
3554 mQueueLength -= 1;
3555 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3556 }
3557 }
3558
3559 /**
3560 * Delivers pre-ime input events to a native activity.
3561 * Does not support pointer events.
3562 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003563 final class NativePreImeInputStage extends AsyncInputStage
3564 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003565 public NativePreImeInputStage(InputStage next, String traceCounter) {
3566 super(next, traceCounter);
3567 }
3568
3569 @Override
3570 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003571 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3572 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3573 return DEFER;
3574 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003575 return FORWARD;
3576 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003577
3578 @Override
3579 public void onFinishedInputEvent(Object token, boolean handled) {
3580 QueuedInputEvent q = (QueuedInputEvent)token;
3581 if (handled) {
3582 finish(q, true);
3583 return;
3584 }
3585 forward(q);
3586 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003587 }
3588
3589 /**
3590 * Delivers pre-ime input events to the view hierarchy.
3591 * Does not support pointer events.
3592 */
3593 final class ViewPreImeInputStage extends InputStage {
3594 public ViewPreImeInputStage(InputStage next) {
3595 super(next);
3596 }
3597
3598 @Override
3599 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003600 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003601 return processKeyEvent(q);
3602 }
3603 return FORWARD;
3604 }
3605
3606 private int processKeyEvent(QueuedInputEvent q) {
3607 final KeyEvent event = (KeyEvent)q.mEvent;
3608 if (mView.dispatchKeyEventPreIme(event)) {
3609 return FINISH_HANDLED;
3610 }
3611 return FORWARD;
3612 }
3613 }
3614
3615 /**
3616 * Delivers input events to the ime.
3617 * Does not support pointer events.
3618 */
3619 final class ImeInputStage extends AsyncInputStage
3620 implements InputMethodManager.FinishedInputEventCallback {
3621 public ImeInputStage(InputStage next, String traceCounter) {
3622 super(next, traceCounter);
3623 }
3624
3625 @Override
3626 protected int onProcess(QueuedInputEvent q) {
3627 if (mLastWasImTarget) {
3628 InputMethodManager imm = InputMethodManager.peekInstance();
3629 if (imm != null) {
3630 final InputEvent event = q.mEvent;
3631 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3632 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3633 if (result == InputMethodManager.DISPATCH_HANDLED) {
3634 return FINISH_HANDLED;
3635 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
3636 return FINISH_NOT_HANDLED;
3637 } else {
3638 return DEFER; // callback will be invoked later
3639 }
3640 }
3641 }
3642 return FORWARD;
3643 }
3644
3645 @Override
3646 public void onFinishedInputEvent(Object token, boolean handled) {
3647 QueuedInputEvent q = (QueuedInputEvent)token;
3648 if (handled) {
3649 finish(q, true);
3650 return;
3651 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003652 forward(q);
3653 }
3654 }
3655
3656 /**
3657 * Performs early processing of post-ime input events.
3658 */
3659 final class EarlyPostImeInputStage extends InputStage {
3660 public EarlyPostImeInputStage(InputStage next) {
3661 super(next);
3662 }
3663
3664 @Override
3665 protected int onProcess(QueuedInputEvent q) {
3666 if (q.mEvent instanceof KeyEvent) {
3667 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003668 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003669 final int source = q.mEvent.getSource();
3670 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003671 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003672 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003673 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003674 return FORWARD;
3675 }
3676
3677 private int processKeyEvent(QueuedInputEvent q) {
3678 final KeyEvent event = (KeyEvent)q.mEvent;
3679
3680 // If the key's purpose is to exit touch mode then we consume it
3681 // and consider it handled.
3682 if (checkForLeavingTouchModeAndConsume(event)) {
3683 return FINISH_HANDLED;
3684 }
3685
3686 // Make sure the fallback event policy sees all keys that will be
3687 // delivered to the view hierarchy.
3688 mFallbackEventHandler.preDispatchKeyEvent(event);
3689 return FORWARD;
3690 }
3691
3692 private int processPointerEvent(QueuedInputEvent q) {
3693 final MotionEvent event = (MotionEvent)q.mEvent;
3694
3695 // Translate the pointer event for compatibility, if needed.
3696 if (mTranslator != null) {
3697 mTranslator.translateEventInScreenToAppWindow(event);
3698 }
3699
3700 // Enter touch mode on down or scroll.
3701 final int action = event.getAction();
3702 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3703 ensureTouchMode(true);
3704 }
3705
3706 // Offset the scroll position.
3707 if (mCurScrollY != 0) {
3708 event.offsetLocation(0, mCurScrollY);
3709 }
3710
3711 // Remember the touch position for possible drag-initiation.
3712 if (event.isTouchEvent()) {
3713 mLastTouchPoint.x = event.getRawX();
3714 mLastTouchPoint.y = event.getRawY();
3715 }
3716 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003717 }
3718 }
3719
Jeff Brownf9e989d2013-04-04 23:04:03 -07003720 /**
3721 * Delivers post-ime input events to a native activity.
3722 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003723 final class NativePostImeInputStage extends AsyncInputStage
3724 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003725 public NativePostImeInputStage(InputStage next, String traceCounter) {
3726 super(next, traceCounter);
3727 }
3728
3729 @Override
3730 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003731 if (mInputQueue != null) {
3732 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3733 return DEFER;
3734 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003735 return FORWARD;
3736 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003737
3738 @Override
3739 public void onFinishedInputEvent(Object token, boolean handled) {
3740 QueuedInputEvent q = (QueuedInputEvent)token;
3741 if (handled) {
3742 finish(q, true);
3743 return;
3744 }
3745 forward(q);
3746 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003747 }
3748
3749 /**
3750 * Delivers post-ime input events to the view hierarchy.
3751 */
3752 final class ViewPostImeInputStage extends InputStage {
3753 public ViewPostImeInputStage(InputStage next) {
3754 super(next);
3755 }
3756
3757 @Override
3758 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003759 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003760 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003761 } else {
3762 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003763 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3764 return processPointerEvent(q);
3765 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3766 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003767 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003768 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003769 }
3770 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003771 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003772
Jeff Brownf9e989d2013-04-04 23:04:03 -07003773 private int processKeyEvent(QueuedInputEvent q) {
3774 final KeyEvent event = (KeyEvent)q.mEvent;
3775
3776 // Deliver the key to the view hierarchy.
3777 if (mView.dispatchKeyEvent(event)) {
3778 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003779 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003780
3781 // If the Control modifier is held, try to interpret the key as a shortcut.
3782 if (event.getAction() == KeyEvent.ACTION_DOWN
3783 && event.isCtrlPressed()
3784 && event.getRepeatCount() == 0
3785 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3786 if (mView.dispatchKeyShortcutEvent(event)) {
3787 return FINISH_HANDLED;
3788 }
3789 }
3790
3791 // Apply the fallback event policy.
3792 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3793 return FINISH_HANDLED;
3794 }
3795
3796 // Handle automatic focus changes.
3797 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3798 int direction = 0;
3799 switch (event.getKeyCode()) {
3800 case KeyEvent.KEYCODE_DPAD_LEFT:
3801 if (event.hasNoModifiers()) {
3802 direction = View.FOCUS_LEFT;
3803 }
3804 break;
3805 case KeyEvent.KEYCODE_DPAD_RIGHT:
3806 if (event.hasNoModifiers()) {
3807 direction = View.FOCUS_RIGHT;
3808 }
3809 break;
3810 case KeyEvent.KEYCODE_DPAD_UP:
3811 if (event.hasNoModifiers()) {
3812 direction = View.FOCUS_UP;
3813 }
3814 break;
3815 case KeyEvent.KEYCODE_DPAD_DOWN:
3816 if (event.hasNoModifiers()) {
3817 direction = View.FOCUS_DOWN;
3818 }
3819 break;
3820 case KeyEvent.KEYCODE_TAB:
3821 if (event.hasNoModifiers()) {
3822 direction = View.FOCUS_FORWARD;
3823 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3824 direction = View.FOCUS_BACKWARD;
3825 }
3826 break;
3827 }
3828 if (direction != 0) {
3829 View focused = mView.findFocus();
3830 if (focused != null) {
3831 View v = focused.focusSearch(direction);
3832 if (v != null && v != focused) {
3833 // do the math the get the interesting rect
3834 // of previous focused into the coord system of
3835 // newly focused view
3836 focused.getFocusedRect(mTempRect);
3837 if (mView instanceof ViewGroup) {
3838 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3839 focused, mTempRect);
3840 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3841 v, mTempRect);
3842 }
3843 if (v.requestFocus(direction, mTempRect)) {
3844 playSoundEffect(SoundEffectConstants
3845 .getContantForFocusDirection(direction));
3846 return FINISH_HANDLED;
3847 }
3848 }
3849
3850 // Give the focused view a last chance to handle the dpad key.
3851 if (mView.dispatchUnhandledMove(focused, direction)) {
3852 return FINISH_HANDLED;
3853 }
3854 } else {
3855 // find the best view to give focus to in this non-touch-mode with no-focus
3856 View v = focusSearch(null, direction);
3857 if (v != null && v.requestFocus(direction)) {
3858 return FINISH_HANDLED;
3859 }
3860 }
3861 }
3862 }
3863 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003864 }
3865
Jeff Brownf9e989d2013-04-04 23:04:03 -07003866 private int processPointerEvent(QueuedInputEvent q) {
3867 final MotionEvent event = (MotionEvent)q.mEvent;
3868
3869 if (mView.dispatchPointerEvent(event)) {
3870 return FINISH_HANDLED;
3871 }
3872 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003873 }
3874
Jeff Brownf9e989d2013-04-04 23:04:03 -07003875 private int processTrackballEvent(QueuedInputEvent q) {
3876 final MotionEvent event = (MotionEvent)q.mEvent;
3877
3878 if (mView.dispatchTrackballEvent(event)) {
3879 return FINISH_HANDLED;
3880 }
3881 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 }
3883
Jeff Brownf9e989d2013-04-04 23:04:03 -07003884 private int processGenericMotionEvent(QueuedInputEvent q) {
3885 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003886
Jeff Brownf9e989d2013-04-04 23:04:03 -07003887 // Deliver the event to the view.
3888 if (mView.dispatchGenericMotionEvent(event)) {
3889 return FINISH_HANDLED;
3890 }
3891 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003892 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003893 }
3894
Jeff Brownf9e989d2013-04-04 23:04:03 -07003895 /**
Jeff Brown678a1252013-04-09 17:46:25 -07003896 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07003897 */
3898 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07003899 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
3900 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
3901 private final SyntheticTouchNavigationHandler mTouchNavigation =
3902 new SyntheticTouchNavigationHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003903
3904 public SyntheticInputStage() {
3905 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08003906 }
3907
Jeff Brownf9e989d2013-04-04 23:04:03 -07003908 @Override
3909 protected int onProcess(QueuedInputEvent q) {
3910 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
3911 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07003912 final MotionEvent event = (MotionEvent)q.mEvent;
3913 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003914 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003915 mTrackball.process(event);
3916 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003917 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003918 mJoystick.process(event);
3919 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003920 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
3921 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07003922 mTouchNavigation.process(event);
3923 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003924 }
3925 }
3926 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003927 }
3928
Jeff Brownf9e989d2013-04-04 23:04:03 -07003929 @Override
3930 protected void onDeliverToNext(QueuedInputEvent q) {
3931 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
3932 // Cancel related synthetic events if any prior stage has handled the event.
3933 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07003934 final MotionEvent event = (MotionEvent)q.mEvent;
3935 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003936 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003937 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003938 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003939 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003940 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
3941 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07003942 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003943 }
3944 }
3945 }
3946 super.onDeliverToNext(q);
3947 }
Jeff Brown678a1252013-04-09 17:46:25 -07003948 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003949
Jeff Brown678a1252013-04-09 17:46:25 -07003950 /**
3951 * Creates dpad events from unhandled trackball movements.
3952 */
3953 final class SyntheticTrackballHandler {
3954 private final TrackballAxis mX = new TrackballAxis();
3955 private final TrackballAxis mY = new TrackballAxis();
3956 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003957
Jeff Brown678a1252013-04-09 17:46:25 -07003958 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003959 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07003960 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07003961 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003962 // It has been too long since the last movement,
3963 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07003964 mX.reset(0);
3965 mY.reset(0);
3966 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003967 }
3968
3969 final int action = event.getAction();
3970 final int metaState = event.getMetaState();
3971 switch (action) {
3972 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07003973 mX.reset(2);
3974 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003975 enqueueInputEvent(new KeyEvent(curTime, curTime,
3976 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3977 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3978 InputDevice.SOURCE_KEYBOARD));
3979 break;
3980 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07003981 mX.reset(2);
3982 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003983 enqueueInputEvent(new KeyEvent(curTime, curTime,
3984 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3985 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3986 InputDevice.SOURCE_KEYBOARD));
3987 break;
3988 }
3989
Jeff Brown678a1252013-04-09 17:46:25 -07003990 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
3991 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07003992 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07003993 + " / Y=" + mY.position + " step="
3994 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07003995 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07003996 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
3997 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07003998
3999 // Generate DPAD events based on the trackball movement.
4000 // We pick the axis that has moved the most as the direction of
4001 // the DPAD. When we generate DPAD events for one axis, then the
4002 // other axis is reset -- we don't want to perform DPAD jumps due
4003 // to slight movements in the trackball when making major movements
4004 // along the other axis.
4005 int keycode = 0;
4006 int movement = 0;
4007 float accel = 1;
4008 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004009 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004010 if (movement != 0) {
4011 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4012 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004013 accel = mX.acceleration;
4014 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004015 }
4016 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004017 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004018 if (movement != 0) {
4019 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4020 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004021 accel = mY.acceleration;
4022 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004023 }
4024 }
4025
4026 if (keycode != 0) {
4027 if (movement < 0) movement = -movement;
4028 int accelMovement = (int)(movement * accel);
4029 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4030 + " accelMovement=" + accelMovement
4031 + " accel=" + accel);
4032 if (accelMovement > movement) {
4033 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4034 + keycode);
4035 movement--;
4036 int repeatCount = accelMovement - movement;
4037 enqueueInputEvent(new KeyEvent(curTime, curTime,
4038 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4039 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4040 InputDevice.SOURCE_KEYBOARD));
4041 }
4042 while (movement > 0) {
4043 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4044 + keycode);
4045 movement--;
4046 curTime = SystemClock.uptimeMillis();
4047 enqueueInputEvent(new KeyEvent(curTime, curTime,
4048 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4049 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4050 InputDevice.SOURCE_KEYBOARD));
4051 enqueueInputEvent(new KeyEvent(curTime, curTime,
4052 KeyEvent.ACTION_UP, keycode, 0, metaState,
4053 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4054 InputDevice.SOURCE_KEYBOARD));
4055 }
Jeff Brown678a1252013-04-09 17:46:25 -07004056 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004057 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004058 }
4059
Jeff Brown678a1252013-04-09 17:46:25 -07004060 public void cancel(MotionEvent event) {
4061 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004062
Jeff Brownf9e989d2013-04-04 23:04:03 -07004063 // If we reach this, we consumed a trackball event.
4064 // Because we will not translate the trackball event into a key event,
4065 // touch mode will not exit, so we exit touch mode here.
4066 if (mView != null && mAdded) {
4067 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004068 }
4069 }
Jeff Brown678a1252013-04-09 17:46:25 -07004070 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004071
Jeff Brown678a1252013-04-09 17:46:25 -07004072 /**
4073 * Maintains state information for a single trackball axis, generating
4074 * discrete (DPAD) movements based on raw trackball motion.
4075 */
4076 static final class TrackballAxis {
4077 /**
4078 * The maximum amount of acceleration we will apply.
4079 */
4080 static final float MAX_ACCELERATION = 20;
4081
4082 /**
4083 * The maximum amount of time (in milliseconds) between events in order
4084 * for us to consider the user to be doing fast trackball movements,
4085 * and thus apply an acceleration.
4086 */
4087 static final long FAST_MOVE_TIME = 150;
4088
4089 /**
4090 * Scaling factor to the time (in milliseconds) between events to how
4091 * much to multiple/divide the current acceleration. When movement
4092 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4093 * FAST_MOVE_TIME it divides it.
4094 */
4095 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4096
4097 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4098 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4099 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4100
4101 float position;
4102 float acceleration = 1;
4103 long lastMoveTime = 0;
4104 int step;
4105 int dir;
4106 int nonAccelMovement;
4107
4108 void reset(int _step) {
4109 position = 0;
4110 acceleration = 1;
4111 lastMoveTime = 0;
4112 step = _step;
4113 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004114 }
4115
Jeff Brown678a1252013-04-09 17:46:25 -07004116 /**
4117 * Add trackball movement into the state. If the direction of movement
4118 * has been reversed, the state is reset before adding the
4119 * movement (so that you don't have to compensate for any previously
4120 * collected movement before see the result of the movement in the
4121 * new direction).
4122 *
4123 * @return Returns the absolute value of the amount of movement
4124 * collected so far.
4125 */
4126 float collect(float off, long time, String axis) {
4127 long normTime;
4128 if (off > 0) {
4129 normTime = (long)(off * FAST_MOVE_TIME);
4130 if (dir < 0) {
4131 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4132 position = 0;
4133 step = 0;
4134 acceleration = 1;
4135 lastMoveTime = 0;
4136 }
4137 dir = 1;
4138 } else if (off < 0) {
4139 normTime = (long)((-off) * FAST_MOVE_TIME);
4140 if (dir > 0) {
4141 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4142 position = 0;
4143 step = 0;
4144 acceleration = 1;
4145 lastMoveTime = 0;
4146 }
4147 dir = -1;
4148 } else {
4149 normTime = 0;
4150 }
4151
4152 // The number of milliseconds between each movement that is
4153 // considered "normal" and will not result in any acceleration
4154 // or deceleration, scaled by the offset we have here.
4155 if (normTime > 0) {
4156 long delta = time - lastMoveTime;
4157 lastMoveTime = time;
4158 float acc = acceleration;
4159 if (delta < normTime) {
4160 // The user is scrolling rapidly, so increase acceleration.
4161 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4162 if (scale > 1) acc *= scale;
4163 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4164 + off + " normTime=" + normTime + " delta=" + delta
4165 + " scale=" + scale + " acc=" + acc);
4166 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4167 } else {
4168 // The user is scrolling slowly, so decrease acceleration.
4169 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4170 if (scale > 1) acc /= scale;
4171 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4172 + off + " normTime=" + normTime + " delta=" + delta
4173 + " scale=" + scale + " acc=" + acc);
4174 acceleration = acc > 1 ? acc : 1;
4175 }
4176 }
4177 position += off;
4178 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004179 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004180
Jeff Brown678a1252013-04-09 17:46:25 -07004181 /**
4182 * Generate the number of discrete movement events appropriate for
4183 * the currently collected trackball movement.
4184 *
4185 * @return Returns the number of discrete movements, either positive
4186 * or negative, or 0 if there is not enough trackball movement yet
4187 * for a discrete movement.
4188 */
4189 int generate() {
4190 int movement = 0;
4191 nonAccelMovement = 0;
4192 do {
4193 final int dir = position >= 0 ? 1 : -1;
4194 switch (step) {
4195 // If we are going to execute the first step, then we want
4196 // to do this as soon as possible instead of waiting for
4197 // a full movement, in order to make things look responsive.
4198 case 0:
4199 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4200 return movement;
4201 }
4202 movement += dir;
4203 nonAccelMovement += dir;
4204 step = 1;
4205 break;
4206 // If we have generated the first movement, then we need
4207 // to wait for the second complete trackball motion before
4208 // generating the second discrete movement.
4209 case 1:
4210 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4211 return movement;
4212 }
4213 movement += dir;
4214 nonAccelMovement += dir;
4215 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4216 step = 2;
4217 break;
4218 // After the first two, we generate discrete movements
4219 // consistently with the trackball, applying an acceleration
4220 // if the trackball is moving quickly. This is a simple
4221 // acceleration on top of what we already compute based
4222 // on how quickly the wheel is being turned, to apply
4223 // a longer increasing acceleration to continuous movement
4224 // in one direction.
4225 default:
4226 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4227 return movement;
4228 }
4229 movement += dir;
4230 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4231 float acc = acceleration;
4232 acc *= 1.1f;
4233 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4234 break;
4235 }
4236 } while (true);
4237 }
4238 }
4239
4240 /**
4241 * Creates dpad events from unhandled joystick movements.
4242 */
4243 final class SyntheticJoystickHandler extends Handler {
4244 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4245 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4246
4247 private int mLastXDirection;
4248 private int mLastYDirection;
4249 private int mLastXKeyCode;
4250 private int mLastYKeyCode;
4251
4252 public SyntheticJoystickHandler() {
4253 super(true);
4254 }
4255
4256 @Override
4257 public void handleMessage(Message msg) {
4258 switch (msg.what) {
4259 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4260 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4261 KeyEvent oldEvent = (KeyEvent)msg.obj;
4262 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4263 SystemClock.uptimeMillis(),
4264 oldEvent.getRepeatCount() + 1);
4265 if (mAttachInfo.mHasWindowFocus) {
4266 enqueueInputEvent(e);
4267 Message m = obtainMessage(msg.what, e);
4268 m.setAsynchronous(true);
4269 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4270 }
4271 } break;
4272 }
4273 }
4274
4275 public void process(MotionEvent event) {
4276 update(event, true);
4277 }
4278
4279 public void cancel(MotionEvent event) {
4280 update(event, false);
4281 }
4282
4283 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004284 final long time = event.getEventTime();
4285 final int metaState = event.getMetaState();
4286 final int deviceId = event.getDeviceId();
4287 final int source = event.getSource();
4288
4289 int xDirection = joystickAxisValueToDirection(
4290 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4291 if (xDirection == 0) {
4292 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004293 }
4294
Jeff Brownf9e989d2013-04-04 23:04:03 -07004295 int yDirection = joystickAxisValueToDirection(
4296 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4297 if (yDirection == 0) {
4298 yDirection = joystickAxisValueToDirection(event.getY());
4299 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004300
Jeff Brown678a1252013-04-09 17:46:25 -07004301 if (xDirection != mLastXDirection) {
4302 if (mLastXKeyCode != 0) {
4303 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004304 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004305 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004306 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004307 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004308 }
4309
Jeff Brown678a1252013-04-09 17:46:25 -07004310 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004311
4312 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004313 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004314 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4315 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004316 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004317 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4318 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004319 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004320 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004321 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004322 }
4323 }
4324
Jeff Brown678a1252013-04-09 17:46:25 -07004325 if (yDirection != mLastYDirection) {
4326 if (mLastYKeyCode != 0) {
4327 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004328 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004329 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004330 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004331 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004332 }
4333
Jeff Brown678a1252013-04-09 17:46:25 -07004334 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004335
4336 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004337 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004338 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4339 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004340 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004341 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4342 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004343 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004344 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004345 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004346 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004347 }
4348 }
4349
Jeff Brownf9e989d2013-04-04 23:04:03 -07004350 private int joystickAxisValueToDirection(float value) {
4351 if (value >= 0.5f) {
4352 return 1;
4353 } else if (value <= -0.5f) {
4354 return -1;
4355 } else {
4356 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004357 }
4358 }
Jeff Brown678a1252013-04-09 17:46:25 -07004359 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004360
Jeff Brown678a1252013-04-09 17:46:25 -07004361 /**
4362 * Creates dpad events from unhandled touch navigation movements.
4363 */
4364 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004365 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4366 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004367
Jeff Brown4dac9012013-04-10 01:03:19 -07004368 // Assumed nominal width and height in millimeters of a touch navigation pad,
4369 // if no resolution information is available from the input system.
4370 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4371 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004372
Jeff Brown4dac9012013-04-10 01:03:19 -07004373 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004374
Jeff Brown4dac9012013-04-10 01:03:19 -07004375 // Tap timeout in milliseconds.
4376 private static final int TAP_TIMEOUT = 250;
Jeff Brown678a1252013-04-09 17:46:25 -07004377
Jeff Brown4dac9012013-04-10 01:03:19 -07004378 // The maximum distance traveled for a gesture to be considered a tap in millimeters.
4379 private static final int TAP_SLOP_MILLIMETERS = 5;
Jeff Brown678a1252013-04-09 17:46:25 -07004380
Jeff Brown4dac9012013-04-10 01:03:19 -07004381 // The nominal distance traveled to move by one unit.
4382 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4383
4384 // Minimum and maximum fling velocity in ticks per second.
4385 // The minimum velocity should be set such that we perform enough ticks per
4386 // second that the fling appears to be fluid. For example, if we set the minimum
4387 // to 2 ticks per second, then there may be up to half a second delay between the next
4388 // to last and last ticks which is noticeably discrete and jerky. This value should
4389 // probably not be set to anything less than about 4.
4390 // If fling accuracy is a problem then consider tuning the tick distance instead.
4391 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4392 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4393
4394 // Fling velocity decay factor applied after each new key is emitted.
4395 // This parameter controls the deceleration and overall duration of the fling.
4396 // The fling stops automatically when its velocity drops below the minimum
4397 // fling velocity defined above.
4398 private static final float FLING_TICK_DECAY = 0.8f;
4399
4400 /* The input device that we are tracking. */
4401
4402 private int mCurrentDeviceId = -1;
4403 private int mCurrentSource;
4404 private boolean mCurrentDeviceSupported;
4405
4406 /* Configuration for the current input device. */
4407
4408 // The tap timeout and scaled slop.
4409 private int mConfigTapTimeout;
4410 private float mConfigTapSlop;
4411
4412 // The scaled tick distance. A movement of this amount should generally translate
4413 // into a single dpad event in a given direction.
4414 private float mConfigTickDistance;
4415
4416 // The minimum and maximum scaled fling velocity.
4417 private float mConfigMinFlingVelocity;
4418 private float mConfigMaxFlingVelocity;
4419
4420 /* Tracking state. */
4421
4422 // The velocity tracker for detecting flings.
4423 private VelocityTracker mVelocityTracker;
4424
4425 // The active pointer id, or -1 if none.
4426 private int mActivePointerId = -1;
4427
4428 // Time and location where tracking started.
4429 private long mStartTime;
4430 private float mStartX;
4431 private float mStartY;
4432
4433 // Most recently observed position.
4434 private float mLastX;
4435 private float mLastY;
4436
4437 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004438 private float mAccumulatedX;
4439 private float mAccumulatedY;
4440
Jeff Brown4dac9012013-04-10 01:03:19 -07004441 // Set to true if any movement was delivered to the app.
4442 // Implies that tap slop was exceeded.
4443 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004444
Jeff Brown4dac9012013-04-10 01:03:19 -07004445 // The most recently sent key down event.
4446 // The keycode remains set until the direction changes or a fling ends
4447 // so that repeated key events may be generated as required.
4448 private long mPendingKeyDownTime;
4449 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4450 private int mPendingKeyRepeatCount;
4451 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004452
Jeff Brown4dac9012013-04-10 01:03:19 -07004453 // The current fling velocity while a fling is in progress.
4454 private boolean mFlinging;
4455 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004456
4457 public SyntheticTouchNavigationHandler() {
4458 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004459 }
4460
4461 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004462 // Update the current device information.
4463 final long time = event.getEventTime();
4464 final int deviceId = event.getDeviceId();
4465 final int source = event.getSource();
4466 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4467 finishKeys(time);
4468 finishTracking(time);
4469 mCurrentDeviceId = deviceId;
4470 mCurrentSource = source;
4471 mCurrentDeviceSupported = false;
4472 InputDevice device = event.getDevice();
4473 if (device != null) {
4474 // In order to support an input device, we must know certain
4475 // characteristics about it, such as its size and resolution.
4476 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4477 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4478 if (xRange != null && yRange != null) {
4479 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004480
Jeff Brown4dac9012013-04-10 01:03:19 -07004481 // Infer the resolution if it not actually known.
4482 float xRes = xRange.getResolution();
4483 if (xRes <= 0) {
4484 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4485 }
4486 float yRes = yRange.getResolution();
4487 if (yRes <= 0) {
4488 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4489 }
4490 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004491
Jeff Brown4dac9012013-04-10 01:03:19 -07004492 // Precompute all of the configuration thresholds we will need.
4493 mConfigTapTimeout = TAP_TIMEOUT;
4494 mConfigTapSlop = TAP_SLOP_MILLIMETERS * nominalRes;
4495 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4496 mConfigMinFlingVelocity =
4497 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4498 mConfigMaxFlingVelocity =
4499 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4500
4501 if (LOCAL_DEBUG) {
4502 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4503 + " (" + Integer.toHexString(mCurrentSource) + "): "
4504 + "mConfigTapTimeout=" + mConfigTapTimeout
4505 + ", mConfigTapSlop=" + mConfigTapSlop
4506 + ", mConfigTickDistance=" + mConfigTickDistance
4507 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4508 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4509 }
4510 }
4511 }
Jeff Brown678a1252013-04-09 17:46:25 -07004512 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004513 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004514 return;
4515 }
4516
Jeff Brown4dac9012013-04-10 01:03:19 -07004517 // Handle the event.
4518 final int action = event.getActionMasked();
4519 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004520 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004521 boolean caughtFling = mFlinging;
4522 finishKeys(time);
4523 finishTracking(time);
4524 mActivePointerId = event.getPointerId(0);
4525 mVelocityTracker = VelocityTracker.obtain();
4526 mVelocityTracker.addMovement(event);
4527 mStartTime = time;
4528 mStartX = event.getX();
4529 mStartY = event.getY();
4530 mLastX = mStartX;
4531 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004532 mAccumulatedX = 0;
4533 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004534
4535 // If we caught a fling, then pretend that the tap slop has already
4536 // been exceeded to suppress taps whose only purpose is to stop the fling.
4537 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004538 break;
4539 }
4540
Jeff Brown4dac9012013-04-10 01:03:19 -07004541 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004542 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004543 if (mActivePointerId < 0) {
4544 break;
4545 }
4546 final int index = event.findPointerIndex(mActivePointerId);
4547 if (index < 0) {
4548 finishKeys(time);
4549 finishTracking(time);
4550 break;
4551 }
Jeff Brown678a1252013-04-09 17:46:25 -07004552
Jeff Brown4dac9012013-04-10 01:03:19 -07004553 mVelocityTracker.addMovement(event);
4554 final float x = event.getX(index);
4555 final float y = event.getY(index);
4556 mAccumulatedX += x - mLastX;
4557 mAccumulatedY += y - mLastY;
4558 mLastX = x;
4559 mLastY = y;
4560
4561 // Consume any accumulated movement so far.
4562 final int metaState = event.getMetaState();
4563 consumeAccumulatedMovement(time, metaState);
4564
4565 // Detect taps and flings.
4566 if (action == MotionEvent.ACTION_UP) {
4567 if (!mConsumedMovement
4568 && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop
4569 && time <= mStartTime + mConfigTapTimeout) {
4570 // It's a tap!
4571 finishKeys(time);
4572 sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
4573 sendKeyUp(time);
4574 } else if (mConsumedMovement
4575 && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4576 // It might be a fling.
4577 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4578 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4579 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4580 if (!startFling(time, vx, vy)) {
4581 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004582 }
4583 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004584 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004585 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004586 break;
4587 }
4588
4589 case MotionEvent.ACTION_CANCEL: {
4590 finishKeys(time);
4591 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004592 break;
4593 }
4594 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004595 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004596
4597 public void cancel(MotionEvent event) {
4598 if (mCurrentDeviceId == event.getDeviceId()
4599 && mCurrentSource == event.getSource()) {
4600 final long time = event.getEventTime();
4601 finishKeys(time);
4602 finishTracking(time);
4603 }
4604 }
4605
4606 private void finishKeys(long time) {
4607 cancelFling();
4608 sendKeyUp(time);
4609 }
4610
4611 private void finishTracking(long time) {
4612 if (mActivePointerId >= 0) {
4613 mActivePointerId = -1;
4614 mVelocityTracker.recycle();
4615 mVelocityTracker = null;
4616 }
4617 }
4618
4619 private void consumeAccumulatedMovement(long time, int metaState) {
4620 final float absX = Math.abs(mAccumulatedX);
4621 final float absY = Math.abs(mAccumulatedY);
4622 if (absX >= absY) {
4623 if (absX >= mConfigTickDistance) {
4624 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4625 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4626 mAccumulatedY = 0;
4627 mConsumedMovement = true;
4628 }
4629 } else {
4630 if (absY >= mConfigTickDistance) {
4631 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4632 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4633 mAccumulatedX = 0;
4634 mConsumedMovement = true;
4635 }
4636 }
4637 }
4638
4639 private float consumeAccumulatedMovement(long time, int metaState,
4640 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4641 while (accumulator <= -mConfigTickDistance) {
4642 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4643 accumulator += mConfigTickDistance;
4644 }
4645 while (accumulator >= mConfigTickDistance) {
4646 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4647 accumulator -= mConfigTickDistance;
4648 }
4649 return accumulator;
4650 }
4651
4652 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4653 if (mPendingKeyCode != keyCode) {
4654 sendKeyUp(time);
4655 mPendingKeyDownTime = time;
4656 mPendingKeyCode = keyCode;
4657 mPendingKeyRepeatCount = 0;
4658 } else {
4659 mPendingKeyRepeatCount += 1;
4660 }
4661 mPendingKeyMetaState = metaState;
4662
4663 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4664 // but it doesn't quite make sense when simulating the events in this way.
4665 if (LOCAL_DEBUG) {
4666 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4667 + ", repeatCount=" + mPendingKeyRepeatCount
4668 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4669 }
4670 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4671 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4672 mPendingKeyMetaState, mCurrentDeviceId,
4673 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4674 }
4675
4676 private void sendKeyUp(long time) {
4677 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4678 if (LOCAL_DEBUG) {
4679 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4680 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4681 }
4682 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4683 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4684 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4685 mCurrentSource));
4686 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4687 }
4688 }
4689
4690 private boolean startFling(long time, float vx, float vy) {
4691 if (LOCAL_DEBUG) {
4692 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4693 + ", min=" + mConfigMinFlingVelocity);
4694 }
4695
4696 // Flings must be oriented in the same direction as the preceding movements.
4697 switch (mPendingKeyCode) {
4698 case KeyEvent.KEYCODE_DPAD_LEFT:
4699 if (-vx >= mConfigMinFlingVelocity
4700 && Math.abs(vy) < mConfigMinFlingVelocity) {
4701 mFlingVelocity = -vx;
4702 break;
4703 }
4704 return false;
4705
4706 case KeyEvent.KEYCODE_DPAD_RIGHT:
4707 if (vx >= mConfigMinFlingVelocity
4708 && Math.abs(vy) < mConfigMinFlingVelocity) {
4709 mFlingVelocity = vx;
4710 break;
4711 }
4712 return false;
4713
4714 case KeyEvent.KEYCODE_DPAD_UP:
4715 if (-vy >= mConfigMinFlingVelocity
4716 && Math.abs(vx) < mConfigMinFlingVelocity) {
4717 mFlingVelocity = -vy;
4718 break;
4719 }
4720 return false;
4721
4722 case KeyEvent.KEYCODE_DPAD_DOWN:
4723 if (vy >= mConfigMinFlingVelocity
4724 && Math.abs(vx) < mConfigMinFlingVelocity) {
4725 mFlingVelocity = vy;
4726 break;
4727 }
4728 return false;
4729 }
4730
4731 // Post the first fling event.
4732 mFlinging = postFling(time);
4733 return mFlinging;
4734 }
4735
4736 private boolean postFling(long time) {
4737 // The idea here is to estimate the time when the pointer would have
4738 // traveled one tick distance unit given the current fling velocity.
4739 // This effect creates continuity of motion.
4740 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4741 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
4742 postAtTime(mFlingRunnable, time + delay);
4743 if (LOCAL_DEBUG) {
4744 Log.d(LOCAL_TAG, "Posted fling: velocity="
4745 + mFlingVelocity + ", delay=" + delay
4746 + ", keyCode=" + mPendingKeyCode);
4747 }
4748 return true;
4749 }
4750 return false;
4751 }
4752
4753 private void cancelFling() {
4754 if (mFlinging) {
4755 removeCallbacks(mFlingRunnable);
4756 mFlinging = false;
4757 }
4758 }
4759
4760 private final Runnable mFlingRunnable = new Runnable() {
4761 @Override
4762 public void run() {
4763 final long time = SystemClock.uptimeMillis();
4764 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
4765 mFlingVelocity *= FLING_TICK_DECAY;
4766 if (!postFling(time)) {
4767 mFlinging = false;
4768 finishKeys(time);
4769 }
4770 }
4771 };
Jeff Browncb1404e2011-01-15 18:14:15 -08004772 }
4773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004775 * Returns true if the key is used for keyboard navigation.
4776 * @param keyEvent The key event.
4777 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004778 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004779 private static boolean isNavigationKey(KeyEvent keyEvent) {
4780 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004781 case KeyEvent.KEYCODE_DPAD_LEFT:
4782 case KeyEvent.KEYCODE_DPAD_RIGHT:
4783 case KeyEvent.KEYCODE_DPAD_UP:
4784 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08004785 case KeyEvent.KEYCODE_DPAD_CENTER:
4786 case KeyEvent.KEYCODE_PAGE_UP:
4787 case KeyEvent.KEYCODE_PAGE_DOWN:
4788 case KeyEvent.KEYCODE_MOVE_HOME:
4789 case KeyEvent.KEYCODE_MOVE_END:
4790 case KeyEvent.KEYCODE_TAB:
4791 case KeyEvent.KEYCODE_SPACE:
4792 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 return true;
4794 }
4795 return false;
4796 }
4797
4798 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004799 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004800 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08004801 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004802 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004803 private static boolean isTypingKey(KeyEvent keyEvent) {
4804 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 }
4806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004807 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004808 * 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 -08004809 * @param event The key event.
4810 * @return Whether this key event should be consumed (meaning the act of
4811 * leaving touch mode alone is considered the event).
4812 */
4813 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004814 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004815 if (!mAttachInfo.mInTouchMode) {
4816 return false;
4817 }
4818
Jeff Brown4e6319b2010-12-13 10:36:51 -08004819 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
4820 final int action = event.getAction();
4821 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004822 return false;
4823 }
4824
Jeff Brown4e6319b2010-12-13 10:36:51 -08004825 // Don't leave touch mode if the IME told us not to.
4826 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
4827 return false;
4828 }
4829
4830 // If the key can be used for keyboard navigation then leave touch mode
4831 // and select a focused view if needed (in ensureTouchMode).
4832 // When a new focused view is selected, we consume the navigation key because
4833 // navigation doesn't make much sense unless a view already has focus so
4834 // the key's purpose is to set focus.
4835 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 return ensureTouchMode(false);
4837 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08004838
4839 // If the key can be used for typing then leave touch mode
4840 // and select a focused view if needed (in ensureTouchMode).
4841 // Always allow the view to process the typing key.
4842 if (isTypingKey(event)) {
4843 ensureTouchMode(false);
4844 return false;
4845 }
4846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004847 return false;
4848 }
4849
Christopher Tatea53146c2010-09-07 11:57:52 -07004850 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08004851 void setLocalDragState(Object obj) {
4852 mLocalDragState = obj;
4853 }
4854
Christopher Tatea53146c2010-09-07 11:57:52 -07004855 private void handleDragEvent(DragEvent event) {
4856 // From the root, only drag start/end/location are dispatched. entered/exited
4857 // are determined and dispatched by the viewgroup hierarchy, who then report
4858 // that back here for ultimate reporting back to the framework.
4859 if (mView != null && mAdded) {
4860 final int what = event.mAction;
4861
4862 if (what == DragEvent.ACTION_DRAG_EXITED) {
4863 // A direct EXITED event means that the window manager knows we've just crossed
4864 // a window boundary, so the current drag target within this one must have
4865 // just been exited. Send it the usual notifications and then we're done
4866 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07004867 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004868 } else {
4869 // Cache the drag description when the operation starts, then fill it in
4870 // on subsequent calls as a convenience
4871 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07004872 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07004873 mDragDescription = event.mClipDescription;
4874 } else {
4875 event.mClipDescription = mDragDescription;
4876 }
4877
4878 // For events with a [screen] location, translate into window coordinates
4879 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
4880 mDragPoint.set(event.mX, event.mY);
4881 if (mTranslator != null) {
4882 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
4883 }
4884
4885 if (mCurScrollY != 0) {
4886 mDragPoint.offset(0, mCurScrollY);
4887 }
4888
4889 event.mX = mDragPoint.x;
4890 event.mY = mDragPoint.y;
4891 }
4892
4893 // Remember who the current drag target is pre-dispatch
4894 final View prevDragView = mCurrentDragView;
4895
4896 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07004897 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004898
4899 // If we changed apparent drag target, tell the OS about it
4900 if (prevDragView != mCurrentDragView) {
4901 try {
4902 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07004903 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07004904 }
4905 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07004906 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07004907 }
4908 } catch (RemoteException e) {
4909 Slog.e(TAG, "Unable to note drag target change");
4910 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004911 }
Chris Tated4533f12010-10-19 15:15:08 -07004912
Christopher Tate407b4e92010-11-30 17:14:08 -08004913 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07004914 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08004915 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07004916 try {
4917 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07004918 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07004919 } catch (RemoteException e) {
4920 Log.e(TAG, "Unable to report drop result");
4921 }
4922 }
Christopher Tate407b4e92010-11-30 17:14:08 -08004923
4924 // When the drag operation ends, release any local state object
4925 // that may have been in use
4926 if (what == DragEvent.ACTION_DRAG_ENDED) {
4927 setLocalDragState(null);
4928 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004929 }
4930 }
4931 event.recycle();
4932 }
4933
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004934 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
4935 if (mSeq != args.seq) {
4936 // The sequence has changed, so we need to update our value and make
4937 // sure to do a traversal afterward so the window manager is given our
4938 // most recent data.
4939 mSeq = args.seq;
4940 mAttachInfo.mForceReportNewAttributes = true;
4941 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08004942 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004943 if (mView == null) return;
4944 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004945 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004946 }
Dianne Hackborncf675782012-05-10 15:07:24 -07004947 if (mAttachInfo != null) {
4948 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
4949 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
4950 mAttachInfo.mGlobalSystemUiVisibility = visibility;
4951 mView.dispatchSystemUiVisibilityChanged(visibility);
4952 }
4953 }
Joe Onorato664644d2011-01-23 17:53:23 -08004954 }
4955
Dianne Hackborn12d3a942012-04-27 14:16:30 -07004956 public void handleDispatchDoneAnimating() {
4957 if (mWindowsAnimating) {
4958 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07004959 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07004960 scheduleTraversals();
4961 }
4962 }
4963 }
4964
Christopher Tate2c095f32010-10-04 14:13:40 -07004965 public void getLastTouchPoint(Point outLocation) {
4966 outLocation.x = (int) mLastTouchPoint.x;
4967 outLocation.y = (int) mLastTouchPoint.y;
4968 }
4969
Chris Tate9d1ab882010-11-02 15:55:39 -07004970 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07004971 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07004972 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07004973 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004974 }
4975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004976 private AudioManager getAudioManager() {
4977 if (mView == null) {
4978 throw new IllegalStateException("getAudioManager called when there is no mView");
4979 }
4980 if (mAudioManager == null) {
4981 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
4982 }
4983 return mAudioManager;
4984 }
4985
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004986 public AccessibilityInteractionController getAccessibilityInteractionController() {
4987 if (mView == null) {
4988 throw new IllegalStateException("getAccessibilityInteractionController"
4989 + " called when there is no mView");
4990 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07004991 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07004992 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004993 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07004994 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004995 }
4996
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07004997 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
4998 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07004999
5000 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005001 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005002 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005003 restore = true;
5004 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005005 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005006 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005007 if (params != null) {
5008 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005009 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005010 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005011 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005012 if (params != null && mOrigWindowType != params.type) {
5013 // For compatibility with old apps, don't crash here.
5014 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
5015 Slog.w(TAG, "Window type can not be changed after "
5016 + "the window is added; ignoring change of " + mView);
5017 params.type = mOrigWindowType;
5018 }
5019 }
Jeff Brown98365d72012-08-19 20:30:52 -07005020 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005021 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005022 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5023 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005024 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005025 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005026 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005027 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005028 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005029 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005030 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005031
5032 if (mTranslator != null) {
5033 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005034 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005035 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5036 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005037 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005038 return relayoutResult;
5039 }
Romain Guy8506ab42009-06-11 17:35:47 -07005040
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005041 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005042 * {@inheritDoc}
5043 */
5044 public void playSoundEffect(int effectId) {
5045 checkThread();
5046
Dan Morrille4d9a012013-03-28 18:10:43 -07005047 if (mMediaDisabled) {
5048 return;
5049 }
5050
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005051 try {
5052 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005053
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005054 switch (effectId) {
5055 case SoundEffectConstants.CLICK:
5056 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5057 return;
5058 case SoundEffectConstants.NAVIGATION_DOWN:
5059 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5060 return;
5061 case SoundEffectConstants.NAVIGATION_LEFT:
5062 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5063 return;
5064 case SoundEffectConstants.NAVIGATION_RIGHT:
5065 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5066 return;
5067 case SoundEffectConstants.NAVIGATION_UP:
5068 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5069 return;
5070 default:
5071 throw new IllegalArgumentException("unknown effect id " + effectId +
5072 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5073 }
5074 } catch (IllegalStateException e) {
5075 // Exception thrown by getAudioManager() when mView is null
5076 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5077 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 }
5079 }
5080
5081 /**
5082 * {@inheritDoc}
5083 */
5084 public boolean performHapticFeedback(int effectId, boolean always) {
5085 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005086 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005087 } catch (RemoteException e) {
5088 return false;
5089 }
5090 }
5091
5092 /**
5093 * {@inheritDoc}
5094 */
5095 public View focusSearch(View focused, int direction) {
5096 checkThread();
5097 if (!(mView instanceof ViewGroup)) {
5098 return null;
5099 }
5100 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5101 }
5102
5103 public void debug() {
5104 mView.debug();
5105 }
Romain Guy65b345f2011-07-27 18:51:50 -07005106
Romain Guy211370f2012-02-01 16:10:55 -08005107 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005108 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005109 if (mView != null) {
5110 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005111 }
5112 }
5113
Romain Guya998dff2012-03-23 18:58:36 -07005114 private static void getGfxInfo(View view, int[] info) {
Romain Guy65b345f2011-07-27 18:51:50 -07005115 DisplayList displayList = view.mDisplayList;
5116 info[0]++;
5117 if (displayList != null) {
5118 info[1] += displayList.getSize();
5119 }
5120
5121 if (view instanceof ViewGroup) {
5122 ViewGroup group = (ViewGroup) view;
5123
5124 int count = group.getChildCount();
5125 for (int i = 0; i < count; i++) {
5126 getGfxInfo(group.getChildAt(i), info);
5127 }
5128 }
5129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005130
Craig Mautner8f303ad2013-06-14 11:32:22 -07005131 /**
5132 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5133 * @return True, request has been queued. False, request has been completed.
5134 */
5135 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005136 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5137 // done by dispatchDetachedFromWindow will cause havoc on return.
5138 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005139 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005140 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005141 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005142
5143 if (!mIsDrawing) {
5144 destroyHardwareRenderer();
5145 } else {
5146 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5147 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5148 }
5149 mHandler.sendEmptyMessage(MSG_DIE);
5150 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005151 }
5152
5153 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005154 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005155 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005156 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005157 if (mRemoved) {
5158 return;
5159 }
5160 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005161 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005162 dispatchDetachedFromWindow();
5163 }
5164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005165 if (mAdded && !mFirst) {
Romain Guyfbb93fa2012-12-03 18:50:35 -08005166 invalidateDisplayLists();
Romain Guy29d89972010-09-22 16:10:57 -07005167 destroyHardwareRenderer();
5168
Romain Guyedbca122012-04-04 18:25:53 -07005169 if (mView != null) {
5170 int viewVisibility = mView.getVisibility();
5171 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5172 if (mWindowAttributesChanged || viewVisibilityChanged) {
5173 // If layout params have been changed, first give them
5174 // to the window manager to make sure it has the correct
5175 // animation info.
5176 try {
5177 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005178 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5179 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005180 }
5181 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005184
Romain Guyedbca122012-04-04 18:25:53 -07005185 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005187 }
Romain Guyedbca122012-04-04 18:25:53 -07005188
5189 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005190 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005191 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 }
5193
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005194 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005195 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5196 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005197 }
5198
Dianne Hackborna53de062012-05-08 18:53:51 -07005199 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005200 mHandler.post(new Runnable() {
5201 @Override
5202 public void run() {
5203 // Profiling
5204 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5205 profileRendering(mAttachInfo.mHasWindowFocus);
5206
Dan Morrille4d9a012013-03-28 18:10:43 -07005207 // Media (used by sound effects)
5208 mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
5209
Romain Guy5bb3c732012-11-29 17:52:58 -08005210 // Hardware rendering
5211 if (mAttachInfo.mHardwareRenderer != null) {
5212 if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mHolder.getSurface())) {
5213 invalidate();
5214 }
5215 }
5216
5217 // Layout debugging
5218 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5219 if (layout != mAttachInfo.mDebugLayout) {
5220 mAttachInfo.mDebugLayout = layout;
5221 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5222 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5223 }
5224 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005225 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005226 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005227 }
5228
Romain Guy29d89972010-09-22 16:10:57 -07005229 private void destroyHardwareRenderer() {
Romain Guya998dff2012-03-23 18:58:36 -07005230 AttachInfo attachInfo = mAttachInfo;
5231 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
5232
5233 if (hardwareRenderer != null) {
5234 if (mView != null) {
5235 hardwareRenderer.destroyHardwareResources(mView);
5236 }
5237 hardwareRenderer.destroy(true);
5238 hardwareRenderer.setRequested(false);
5239
5240 attachInfo.mHardwareRenderer = null;
5241 attachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005242 }
5243 }
5244
Jeff Browna175a5b2012-02-15 19:18:31 -08005245 public void dispatchFinishInputConnection(InputConnection connection) {
5246 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5247 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005249
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005250 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08005251 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005252 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5253 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005254 + " visibleInsets=" + visibleInsets.toShortString()
5255 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005256 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005257 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005258 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005259 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005260 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005261 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005262 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005263 SomeArgs args = SomeArgs.obtain();
5264 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5265 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5266 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5267 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5268 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005269 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005270 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005271 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005272 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005273
Craig Mautner5702d4d2012-06-30 14:10:16 -07005274 public void dispatchMoved(int newX, int newY) {
5275 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5276 if (mTranslator != null) {
5277 PointF point = new PointF(newX, newY);
5278 mTranslator.translatePointInScreenToAppWindow(point);
5279 newX = (int) (point.x + 0.5);
5280 newY = (int) (point.y + 0.5);
5281 }
5282 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5283 mHandler.sendMessage(msg);
5284 }
5285
Jeff Brown4952dfd2011-11-30 19:23:22 -08005286 /**
5287 * Represents a pending input event that is waiting in a queue.
5288 *
5289 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005290 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005291 * one input event to the application at a time and waits for the application
5292 * to finish handling it before delivering the next one.
5293 *
5294 * However, because the application or IME can synthesize and inject multiple
5295 * key events at a time without going through the input dispatcher, we end up
5296 * needing a queue on the application's side.
5297 */
5298 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005299 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5300 public static final int FLAG_DEFERRED = 1 << 1;
5301 public static final int FLAG_FINISHED = 1 << 2;
5302 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5303 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005304
5305 public QueuedInputEvent mNext;
5306
5307 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005308 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005309 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005310
5311 public boolean shouldSkipIme() {
5312 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5313 return true;
5314 }
5315 return mEvent instanceof MotionEvent
5316 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5317 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005318 }
5319
5320 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005321 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005322 QueuedInputEvent q = mQueuedInputEventPool;
5323 if (q != null) {
5324 mQueuedInputEventPoolSize -= 1;
5325 mQueuedInputEventPool = q.mNext;
5326 q.mNext = null;
5327 } else {
5328 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005329 }
5330
Jeff Brown4952dfd2011-11-30 19:23:22 -08005331 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005332 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005333 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005334 return q;
5335 }
5336
5337 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5338 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005339 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005340
5341 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5342 mQueuedInputEventPoolSize += 1;
5343 q.mNext = mQueuedInputEventPool;
5344 mQueuedInputEventPool = q;
5345 }
5346 }
5347
Jeff Brownf9261d22012-02-03 13:49:15 -08005348 void enqueueInputEvent(InputEvent event) {
5349 enqueueInputEvent(event, null, 0, false);
5350 }
5351
Jeff Brown4952dfd2011-11-30 19:23:22 -08005352 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005353 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005354 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005355
Jeff Brown4952dfd2011-11-30 19:23:22 -08005356 // Always enqueue the input event in order, regardless of its time stamp.
5357 // We do this because the application or the IME may inject key events
5358 // in response to touch events and we want to ensure that the injected keys
5359 // are processed in the order they were received and we cannot trust that
5360 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005361 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005362 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005363 mPendingInputEventHead = q;
5364 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005365 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005366 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005367 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005368 }
Michael Wright95ae9422013-03-14 10:58:50 -07005369 mPendingInputEventCount += 1;
5370 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5371 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005372
Jeff Brownf9261d22012-02-03 13:49:15 -08005373 if (processImmediately) {
5374 doProcessInputEvents();
5375 } else {
5376 scheduleProcessInputEvents();
5377 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005378 }
5379
5380 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005381 if (!mProcessInputEventsScheduled) {
5382 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005383 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5384 msg.setAsynchronous(true);
5385 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005386 }
5387 }
5388
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005389 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005390 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005391 while (mPendingInputEventHead != null) {
5392 QueuedInputEvent q = mPendingInputEventHead;
5393 mPendingInputEventHead = q.mNext;
5394 if (mPendingInputEventHead == null) {
5395 mPendingInputEventTail = null;
5396 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005397 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005398
Michael Wright95ae9422013-03-14 10:58:50 -07005399 mPendingInputEventCount -= 1;
5400 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5401 mPendingInputEventCount);
5402
Jeff Brownf9e989d2013-04-04 23:04:03 -07005403 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005404 }
5405
5406 // We are done processing all input events that we can process right now
5407 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005408 if (mProcessInputEventsScheduled) {
5409 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005410 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005411 }
5412 }
5413
Jeff Brownf9e989d2013-04-04 23:04:03 -07005414 private void deliverInputEvent(QueuedInputEvent q) {
5415 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
5416 try {
5417 if (mInputEventConsistencyVerifier != null) {
5418 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5419 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005420
Jeff Brownf9e989d2013-04-04 23:04:03 -07005421 InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5422 if (stage != null) {
5423 stage.deliver(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005424 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005425 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005426 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005427 } finally {
5428 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Michael Wrightbf020962013-03-28 17:27:50 -07005429 }
Michael Wrightbf020962013-03-28 17:27:50 -07005430 }
5431
Jeff Brownf9e989d2013-04-04 23:04:03 -07005432 private void finishInputEvent(QueuedInputEvent q) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005433 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005434 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005435 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005436 } else {
5437 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005438 }
5439
5440 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005441 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005442
Jeff Brownf9e989d2013-04-04 23:04:03 -07005443 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005444 if (event instanceof KeyEvent) {
5445 final KeyEvent keyEvent = (KeyEvent)event;
5446 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5447 } else {
5448 final MotionEvent motionEvent = (MotionEvent)event;
5449 final int action = motionEvent.getAction();
5450 return action == MotionEvent.ACTION_UP
5451 || action == MotionEvent.ACTION_CANCEL
5452 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005453 }
5454 }
5455
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005456 void scheduleConsumeBatchedInput() {
5457 if (!mConsumeBatchedInputScheduled) {
5458 mConsumeBatchedInputScheduled = true;
5459 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5460 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005461 }
5462 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005463
5464 void unscheduleConsumeBatchedInput() {
5465 if (mConsumeBatchedInputScheduled) {
5466 mConsumeBatchedInputScheduled = false;
5467 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5468 mConsumedBatchedInputRunnable, null);
5469 }
5470 }
5471
Jeff Brown771526c2012-04-27 15:13:25 -07005472 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005473 if (mConsumeBatchedInputScheduled) {
5474 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005475 if (mInputEventReceiver != null) {
Jeff Brown771526c2012-04-27 15:13:25 -07005476 mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005477 }
Jeff Brown330314c2012-04-27 02:20:22 -07005478 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005479 }
5480 }
5481
5482 final class TraversalRunnable implements Runnable {
5483 @Override
5484 public void run() {
5485 doTraversal();
5486 }
5487 }
5488 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005489
Jeff Brown32cbc38552011-12-01 14:01:49 -08005490 final class WindowInputEventReceiver extends InputEventReceiver {
5491 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5492 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005493 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005494
5495 @Override
5496 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005497 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005498 }
Jeff Brown072ec962012-02-07 14:46:57 -08005499
5500 @Override
5501 public void onBatchedInputEventPending() {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005502 scheduleConsumeBatchedInput();
5503 }
5504
5505 @Override
5506 public void dispose() {
5507 unscheduleConsumeBatchedInput();
5508 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005509 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005510 }
5511 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005512
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005513 final class ConsumeBatchedInputRunnable implements Runnable {
5514 @Override
5515 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005516 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005517 }
5518 }
5519 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5520 new ConsumeBatchedInputRunnable();
5521 boolean mConsumeBatchedInputScheduled;
5522
Jeff Brown6cb7b462012-03-05 13:21:17 -08005523 final class InvalidateOnAnimationRunnable implements Runnable {
5524 private boolean mPosted;
5525 private ArrayList<View> mViews = new ArrayList<View>();
5526 private ArrayList<AttachInfo.InvalidateInfo> mViewRects =
5527 new ArrayList<AttachInfo.InvalidateInfo>();
5528 private View[] mTempViews;
5529 private AttachInfo.InvalidateInfo[] mTempViewRects;
5530
5531 public void addView(View view) {
5532 synchronized (this) {
5533 mViews.add(view);
5534 postIfNeededLocked();
5535 }
5536 }
5537
5538 public void addViewRect(AttachInfo.InvalidateInfo info) {
5539 synchronized (this) {
5540 mViewRects.add(info);
5541 postIfNeededLocked();
5542 }
5543 }
5544
5545 public void removeView(View view) {
5546 synchronized (this) {
5547 mViews.remove(view);
5548
5549 for (int i = mViewRects.size(); i-- > 0; ) {
5550 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5551 if (info.target == view) {
5552 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005553 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005554 }
5555 }
5556
5557 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005558 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005559 mPosted = false;
5560 }
5561 }
5562 }
5563
5564 @Override
5565 public void run() {
5566 final int viewCount;
5567 final int viewRectCount;
5568 synchronized (this) {
5569 mPosted = false;
5570
5571 viewCount = mViews.size();
5572 if (viewCount != 0) {
5573 mTempViews = mViews.toArray(mTempViews != null
5574 ? mTempViews : new View[viewCount]);
5575 mViews.clear();
5576 }
5577
5578 viewRectCount = mViewRects.size();
5579 if (viewRectCount != 0) {
5580 mTempViewRects = mViewRects.toArray(mTempViewRects != null
5581 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
5582 mViewRects.clear();
5583 }
5584 }
5585
5586 for (int i = 0; i < viewCount; i++) {
5587 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07005588 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08005589 }
5590
5591 for (int i = 0; i < viewRectCount; i++) {
5592 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
5593 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005594 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005595 }
5596 }
5597
5598 private void postIfNeededLocked() {
5599 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005600 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005601 mPosted = true;
5602 }
5603 }
5604 }
5605 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
5606 new InvalidateOnAnimationRunnable();
5607
Jeff Browna175a5b2012-02-15 19:18:31 -08005608 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
5609 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
5610 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5611 }
5612
Jeff Browna175a5b2012-02-15 19:18:31 -08005613 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
5614 long delayMilliseconds) {
5615 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
5616 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5617 }
5618
Jeff Brown6cb7b462012-03-05 13:21:17 -08005619 public void dispatchInvalidateOnAnimation(View view) {
5620 mInvalidateOnAnimationRunnable.addView(view);
5621 }
5622
5623 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
5624 mInvalidateOnAnimationRunnable.addViewRect(info);
5625 }
5626
Romain Guy2a0f2282012-05-08 14:43:12 -07005627 public void enqueueDisplayList(DisplayList displayList) {
Romain Guy51e4d4d2012-03-15 18:30:47 -07005628 mDisplayLists.add(displayList);
Romain Guy2a0f2282012-05-08 14:43:12 -07005629 }
5630
Jeff Brown6cb7b462012-03-05 13:21:17 -08005631 public void cancelInvalidate(View view) {
5632 mHandler.removeMessages(MSG_INVALIDATE, view);
5633 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
5634 // them to the pool
5635 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
5636 mInvalidateOnAnimationRunnable.removeView(view);
5637 }
5638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005639 public void dispatchKey(KeyEvent event) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005640 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005641 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005642 mHandler.sendMessage(msg);
5643 }
5644
5645 public void dispatchKeyFromIme(KeyEvent event) {
5646 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005647 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005648 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08005649 }
5650
John Reckd6b10982012-04-19 18:01:35 -07005651 public void dispatchUnhandledKey(KeyEvent event) {
5652 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
5653 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5654 final int keyCode = event.getKeyCode();
5655 final int metaState = event.getMetaState();
5656
Jeff Brownfd23e3e2012-05-09 13:34:28 -07005657 // Check for fallback actions specified by the key character map.
5658 KeyCharacterMap.FallbackAction fallbackAction =
5659 kcm.getFallbackAction(keyCode, metaState);
5660 if (fallbackAction != null) {
5661 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5662 KeyEvent fallbackEvent = KeyEvent.obtain(
5663 event.getDownTime(), event.getEventTime(),
5664 event.getAction(), fallbackAction.keyCode,
5665 event.getRepeatCount(), fallbackAction.metaState,
5666 event.getDeviceId(), event.getScanCode(),
5667 flags, event.getSource(), null);
5668 fallbackAction.recycle();
5669
John Reckd6b10982012-04-19 18:01:35 -07005670 dispatchKey(fallbackEvent);
5671 }
5672 }
5673 }
5674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005675 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005676 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005677 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005678 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005679 }
5680
Romain Guybb9908b2012-03-08 11:14:07 -08005681 public void dispatchScreenStateChange(boolean on) {
5682 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
Romain Guy7e4e5612012-03-05 14:37:29 -08005683 msg.arg1 = on ? 1 : 0;
5684 mHandler.sendMessage(msg);
5685 }
5686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005687 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08005688 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
5689 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005690 }
5691
5692 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
5693 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005694 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005695 msg.arg1 = hasFocus ? 1 : 0;
5696 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005697 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005698 }
5699
Dianne Hackbornffa42482009-09-23 22:20:11 -07005700 public void dispatchCloseSystemDialogs(String reason) {
5701 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005702 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07005703 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08005704 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07005705 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005706
5707 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07005708 final int what;
5709 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005710 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
5711 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07005712 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08005713 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07005714 }
Jeff Browna175a5b2012-02-15 19:18:31 -08005715 Message msg = mHandler.obtainMessage(what, event);
5716 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07005717 }
5718
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005719 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
5720 int localValue, int localChanges) {
5721 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
5722 args.seq = seq;
5723 args.globalVisibility = globalVisibility;
5724 args.localValue = localValue;
5725 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08005726 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
5727 }
5728
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005729 public void dispatchDoneAnimating() {
5730 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
5731 }
5732
Jeff Browna175a5b2012-02-15 19:18:31 -08005733 public void dispatchCheckFocus() {
5734 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
5735 // This will result in a call to checkFocus() below.
5736 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
5737 }
Joe Onorato664644d2011-01-23 17:53:23 -08005738 }
5739
svetoslavganov75986cf2009-05-14 22:28:01 -07005740 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005741 * Post a callback to send a
5742 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07005743 * This event is send at most once every
5744 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005745 */
Svetoslav Ganov42138042012-03-20 11:51:39 -07005746 private void postSendWindowContentChangedCallback(View source) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005747 if (mSendWindowContentChangedAccessibilityEvent == null) {
5748 mSendWindowContentChangedAccessibilityEvent =
5749 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005750 }
Svetoslav6254f482013-06-04 17:22:14 -07005751 mSendWindowContentChangedAccessibilityEvent.runOrPost(source);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005752 }
5753
5754 /**
5755 * Remove a posted callback to send a
5756 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
5757 */
5758 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005759 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005760 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005761 }
5762 }
5763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005764 public boolean showContextMenuForChild(View originalView) {
5765 return false;
5766 }
5767
Adam Powell6e346362010-07-23 10:18:23 -07005768 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
5769 return null;
5770 }
5771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 public void createContextMenu(ContextMenu menu) {
5773 }
5774
5775 public void childDrawableStateChanged(View child) {
5776 }
5777
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005778 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
5779 if (mView == null) {
5780 return false;
5781 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005782 // Intercept accessibility focus events fired by virtual nodes to keep
5783 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005784 final int eventType = event.getEventType();
5785 switch (eventType) {
5786 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005787 final long sourceNodeId = event.getSourceNodeId();
5788 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5789 sourceNodeId);
5790 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5791 if (source != null) {
5792 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5793 if (provider != null) {
5794 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
5795 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
5796 setAccessibilityFocus(source, node);
5797 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005798 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005799 } break;
5800 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005801 final long sourceNodeId = event.getSourceNodeId();
5802 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5803 sourceNodeId);
5804 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5805 if (source != null) {
5806 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5807 if (provider != null) {
5808 setAccessibilityFocus(null, null);
5809 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005810 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005811 } break;
5812 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005813 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005814 return true;
5815 }
5816
Svetoslav Ganov42138042012-03-20 11:51:39 -07005817 @Override
5818 public void childAccessibilityStateChanged(View child) {
5819 postSendWindowContentChangedCallback(child);
5820 }
5821
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08005822 @Override
5823 public boolean canResolveLayoutDirection() {
5824 return true;
5825 }
5826
5827 @Override
5828 public boolean isLayoutDirectionResolved() {
5829 return true;
5830 }
5831
5832 @Override
5833 public int getLayoutDirection() {
5834 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
5835 }
5836
5837 @Override
5838 public boolean canResolveTextDirection() {
5839 return true;
5840 }
5841
5842 @Override
5843 public boolean isTextDirectionResolved() {
5844 return true;
5845 }
5846
5847 @Override
5848 public int getTextDirection() {
5849 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
5850 }
5851
5852 @Override
5853 public boolean canResolveTextAlignment() {
5854 return true;
5855 }
5856
5857 @Override
5858 public boolean isTextAlignmentResolved() {
5859 return true;
5860 }
5861
5862 @Override
5863 public int getTextAlignment() {
5864 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
5865 }
5866
Svetoslav Ganov42138042012-03-20 11:51:39 -07005867 private View getCommonPredecessor(View first, View second) {
5868 if (mAttachInfo != null) {
5869 if (mTempHashSet == null) {
5870 mTempHashSet = new HashSet<View>();
5871 }
5872 HashSet<View> seen = mTempHashSet;
5873 seen.clear();
5874 View firstCurrent = first;
5875 while (firstCurrent != null) {
5876 seen.add(firstCurrent);
5877 ViewParent firstCurrentParent = firstCurrent.mParent;
5878 if (firstCurrentParent instanceof View) {
5879 firstCurrent = (View) firstCurrentParent;
5880 } else {
5881 firstCurrent = null;
5882 }
5883 }
5884 View secondCurrent = second;
5885 while (secondCurrent != null) {
5886 if (seen.contains(secondCurrent)) {
5887 seen.clear();
5888 return secondCurrent;
5889 }
5890 ViewParent secondCurrentParent = secondCurrent.mParent;
5891 if (secondCurrentParent instanceof View) {
5892 secondCurrent = (View) secondCurrentParent;
5893 } else {
5894 secondCurrent = null;
5895 }
5896 }
5897 seen.clear();
5898 }
5899 return null;
5900 }
5901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005902 void checkThread() {
5903 if (mThread != Thread.currentThread()) {
5904 throw new CalledFromWrongThreadException(
5905 "Only the original thread that created a view hierarchy can touch its views.");
5906 }
5907 }
5908
5909 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07005910 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005911 }
5912
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07005913 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
5914 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
5915 if (rectangle != null) {
5916 mTempRect.set(rectangle);
5917 mTempRect.offset(0, -mCurScrollY);
5918 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
5919 try {
5920 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
5921 } catch (RemoteException re) {
5922 /* ignore */
5923 }
5924 }
5925 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005926 }
Romain Guy8506ab42009-06-11 17:35:47 -07005927
Adam Powell539ee872012-02-03 19:00:49 -08005928 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
5929 // Do nothing.
5930 }
5931
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07005932 class TakenSurfaceHolder extends BaseSurfaceHolder {
5933 @Override
5934 public boolean onAllowLockCanvas() {
5935 return mDrawingAllowed;
5936 }
5937
5938 @Override
5939 public void onRelayoutContainer() {
5940 // Not currently interesting -- from changing between fixed and layout size.
5941 }
5942
5943 public void setFormat(int format) {
5944 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
5945 }
5946
5947 public void setType(int type) {
5948 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
5949 }
5950
5951 @Override
5952 public void onUpdateSurface() {
5953 // We take care of format and type changes on our own.
5954 throw new IllegalStateException("Shouldn't be here");
5955 }
5956
5957 public boolean isCreating() {
5958 return mIsCreating;
5959 }
5960
5961 @Override
5962 public void setFixedSize(int width, int height) {
5963 throw new UnsupportedOperationException(
5964 "Currently only support sizing from layout");
5965 }
5966
5967 public void setKeepScreenOn(boolean screenOn) {
5968 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
5969 }
5970 }
Romain Guy8506ab42009-06-11 17:35:47 -07005971
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005972 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005973 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07005974 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005975
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005976 W(ViewRootImpl viewAncestor) {
5977 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07005978 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005979 }
5980
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005981 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -07005982 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005983 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005984 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005985 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005986 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005987 }
5988 }
5989
Craig Mautner5702d4d2012-06-30 14:10:16 -07005990 @Override
5991 public void moved(int newX, int newY) {
5992 final ViewRootImpl viewAncestor = mViewAncestor.get();
5993 if (viewAncestor != null) {
5994 viewAncestor.dispatchMoved(newX, newY);
5995 }
5996 }
5997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005998 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005999 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006000 if (viewAncestor != null) {
6001 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006002 }
6003 }
6004
Romain Guybb9908b2012-03-08 11:14:07 -08006005 public void dispatchScreenState(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -08006006 final ViewRootImpl viewAncestor = mViewAncestor.get();
6007 if (viewAncestor != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08006008 viewAncestor.dispatchScreenStateChange(on);
Romain Guy7e4e5612012-03-05 14:37:29 -08006009 }
6010 }
Romain Guybb9908b2012-03-08 11:14:07 -08006011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006012 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006013 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006014 if (viewAncestor != null) {
6015 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006016 }
6017 }
6018
6019 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006020 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006021 if (viewAncestor != null) {
6022 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006023 }
6024 }
6025
6026 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006027 try {
6028 return ActivityManagerNative.getDefault().checkPermission(
6029 permission, Binder.getCallingPid(), Binder.getCallingUid());
6030 } catch (RemoteException e) {
6031 return PackageManager.PERMISSION_DENIED;
6032 }
6033 }
6034
6035 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006036 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006037 if (viewAncestor != null) {
6038 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006039 if (view != null) {
6040 if (checkCallingPermission(Manifest.permission.DUMP) !=
6041 PackageManager.PERMISSION_GRANTED) {
6042 throw new SecurityException("Insufficient permissions to invoke"
6043 + " executeCommand() from pid=" + Binder.getCallingPid()
6044 + ", uid=" + Binder.getCallingUid());
6045 }
6046
6047 OutputStream clientStream = null;
6048 try {
6049 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6050 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6051 } catch (IOException e) {
6052 e.printStackTrace();
6053 } finally {
6054 if (clientStream != null) {
6055 try {
6056 clientStream.close();
6057 } catch (IOException e) {
6058 e.printStackTrace();
6059 }
6060 }
6061 }
6062 }
6063 }
6064 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006065
Dianne Hackbornffa42482009-09-23 22:20:11 -07006066 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006067 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006068 if (viewAncestor != null) {
6069 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006070 }
6071 }
6072
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006073 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6074 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006075 if (sync) {
6076 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006077 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006078 } catch (RemoteException e) {
6079 }
6080 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006081 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006082
Dianne Hackborn75804932009-10-20 20:15:20 -07006083 public void dispatchWallpaperCommand(String action, int x, int y,
6084 int z, Bundle extras, boolean sync) {
6085 if (sync) {
6086 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006087 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006088 } catch (RemoteException e) {
6089 }
6090 }
6091 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006092
6093 /* Drag/drop */
6094 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006095 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006096 if (viewAncestor != null) {
6097 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006098 }
6099 }
Joe Onorato664644d2011-01-23 17:53:23 -08006100
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006101 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6102 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006103 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006104 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006105 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6106 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006107 }
6108 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006109
6110 public void doneAnimating() {
6111 final ViewRootImpl viewAncestor = mViewAncestor.get();
6112 if (viewAncestor != null) {
6113 viewAncestor.dispatchDoneAnimating();
6114 }
6115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006116 }
6117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006118 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6119 public CalledFromWrongThreadException(String msg) {
6120 super(msg);
6121 }
6122 }
6123
6124 private SurfaceHolder mHolder = new SurfaceHolder() {
6125 // we only need a SurfaceHolder for opengl. it would be nice
6126 // to implement everything else though, especially the callback
6127 // support (opengl doesn't make use of it right now, but eventually
6128 // will).
6129 public Surface getSurface() {
6130 return mSurface;
6131 }
6132
6133 public boolean isCreating() {
6134 return false;
6135 }
6136
6137 public void addCallback(Callback callback) {
6138 }
6139
6140 public void removeCallback(Callback callback) {
6141 }
6142
6143 public void setFixedSize(int width, int height) {
6144 }
6145
6146 public void setSizeFromLayout() {
6147 }
6148
6149 public void setFormat(int format) {
6150 }
6151
6152 public void setType(int type) {
6153 }
6154
6155 public void setKeepScreenOn(boolean screenOn) {
6156 }
6157
6158 public Canvas lockCanvas() {
6159 return null;
6160 }
6161
6162 public Canvas lockCanvas(Rect dirty) {
6163 return null;
6164 }
6165
6166 public void unlockCanvasAndPost(Canvas canvas) {
6167 }
6168 public Rect getSurfaceFrame() {
6169 return null;
6170 }
6171 };
6172
6173 static RunQueue getRunQueue() {
6174 RunQueue rq = sRunQueues.get();
6175 if (rq != null) {
6176 return rq;
6177 }
6178 rq = new RunQueue();
6179 sRunQueues.set(rq);
6180 return rq;
6181 }
Romain Guy8506ab42009-06-11 17:35:47 -07006182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006183 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08006184 * The run queue is used to enqueue pending work from Views when no Handler is
6185 * attached. The work is executed during the next call to performTraversals on
6186 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006187 * @hide
6188 */
6189 static final class RunQueue {
6190 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
6191
6192 void post(Runnable action) {
6193 postDelayed(action, 0);
6194 }
6195
6196 void postDelayed(Runnable action, long delayMillis) {
6197 HandlerAction handlerAction = new HandlerAction();
6198 handlerAction.action = action;
6199 handlerAction.delay = delayMillis;
6200
6201 synchronized (mActions) {
6202 mActions.add(handlerAction);
6203 }
6204 }
6205
6206 void removeCallbacks(Runnable action) {
6207 final HandlerAction handlerAction = new HandlerAction();
6208 handlerAction.action = action;
6209
6210 synchronized (mActions) {
6211 final ArrayList<HandlerAction> actions = mActions;
6212
6213 while (actions.remove(handlerAction)) {
6214 // Keep going
6215 }
6216 }
6217 }
6218
6219 void executeActions(Handler handler) {
6220 synchronized (mActions) {
6221 final ArrayList<HandlerAction> actions = mActions;
6222 final int count = actions.size();
6223
6224 for (int i = 0; i < count; i++) {
6225 final HandlerAction handlerAction = actions.get(i);
6226 handler.postDelayed(handlerAction.action, handlerAction.delay);
6227 }
6228
Romain Guy15df6702009-08-17 20:17:30 -07006229 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006230 }
6231 }
6232
6233 private static class HandlerAction {
6234 Runnable action;
6235 long delay;
6236
6237 @Override
6238 public boolean equals(Object o) {
6239 if (this == o) return true;
6240 if (o == null || getClass() != o.getClass()) return false;
6241
6242 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006243 return !(action != null ? !action.equals(that.action) : that.action != null);
6244
6245 }
6246
6247 @Override
6248 public int hashCode() {
6249 int result = action != null ? action.hashCode() : 0;
6250 result = 31 * result + (int) (delay ^ (delay >>> 32));
6251 return result;
6252 }
6253 }
6254 }
6255
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006256 /**
6257 * Class for managing the accessibility interaction connection
6258 * based on the global accessibility state.
6259 */
6260 final class AccessibilityInteractionConnectionManager
6261 implements AccessibilityStateChangeListener {
6262 public void onAccessibilityStateChanged(boolean enabled) {
6263 if (enabled) {
6264 ensureConnection();
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006265 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6266 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6267 View focusedView = mView.findFocus();
6268 if (focusedView != null && focusedView != mView) {
6269 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6270 }
6271 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006272 } else {
6273 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006274 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006275 }
6276 }
6277
6278 public void ensureConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006279 if (mAttachInfo != null) {
6280 final boolean registered =
6281 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
6282 if (!registered) {
6283 mAttachInfo.mAccessibilityWindowId =
6284 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6285 new AccessibilityInteractionConnection(ViewRootImpl.this));
6286 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006287 }
6288 }
6289
6290 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006291 final boolean registered =
6292 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006293 if (registered) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006294 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006295 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6296 }
6297 }
6298 }
6299
6300 /**
6301 * This class is an interface this ViewAncestor provides to the
6302 * AccessibilityManagerService to the latter can interact with
6303 * the view hierarchy in this ViewAncestor.
6304 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006305 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006306 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006307 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006308
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006309 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6310 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006311 }
6312
Svetoslav Ganov42138042012-03-20 11:51:39 -07006313 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006314 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006315 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006316 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006317 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6318 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006319 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006320 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006321 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6322 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006323 } else {
6324 // We cannot make the call and notify the caller so it does not wait.
6325 try {
6326 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6327 } catch (RemoteException re) {
6328 /* best effort - ignore */
6329 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006330 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006331 }
6332
Svetoslav Ganov42138042012-03-20 11:51:39 -07006333 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006334 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006335 Bundle arguments, int interactionId,
6336 IAccessibilityInteractionConnectionCallback callback, int flags,
6337 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006338 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6339 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006340 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006341 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006342 interactionId, callback, flags, interogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006343 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006344 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006345 try {
6346 callback.setPerformAccessibilityActionResult(false, interactionId);
6347 } catch (RemoteException re) {
6348 /* best effort - ignore */
6349 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006350 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006351 }
6352
Svetoslav Ganov42138042012-03-20 11:51:39 -07006353 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006354 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
6355 String viewId, int interactionId,
6356 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006357 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006358 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6359 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006360 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006361 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
6362 viewId, interactionId, callback, flags, interrogatingPid,
6363 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006364 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006365 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006366 try {
6367 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6368 } catch (RemoteException re) {
6369 /* best effort - ignore */
6370 }
6371 }
6372 }
6373
Svetoslav Ganov42138042012-03-20 11:51:39 -07006374 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006375 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006376 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006377 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006378 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6379 if (viewRootImpl != null && viewRootImpl.mView != null) {
6380 viewRootImpl.getAccessibilityInteractionController()
6381 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006382 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6383 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006384 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006385 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006386 try {
6387 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6388 } catch (RemoteException re) {
6389 /* best effort - ignore */
6390 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006391 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006392 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006393
Svetoslav Ganov42138042012-03-20 11:51:39 -07006394 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006395 public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
Svetoslav Ganov86783472012-06-06 21:12:20 -07006396 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006397 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006398 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6399 if (viewRootImpl != null && viewRootImpl.mView != null) {
6400 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006401 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006402 flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006403 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006404 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006405 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006406 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006407 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006408 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006409 }
6410 }
6411 }
6412
Svetoslav Ganov42138042012-03-20 11:51:39 -07006413 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006414 public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006415 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006416 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006417 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6418 if (viewRootImpl != null && viewRootImpl.mView != null) {
6419 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006420 .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006421 callback, flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006422 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006423 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006424 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006425 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006426 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006427 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006428 }
6429 }
6430 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006431 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006432
Svetoslav Ganova0156172011-06-26 17:55:44 -07006433 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006434 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07006435 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006436
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006437 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07006438 // The accessibility may be turned off while we were waiting so check again.
6439 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6440 mLastEventTimeMillis = SystemClock.uptimeMillis();
6441 AccessibilityEvent event = AccessibilityEvent.obtain();
6442 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
6443 event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
6444 mSource.sendAccessibilityEventUnchecked(event);
6445 } else {
6446 mLastEventTimeMillis = 0;
6447 }
6448 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07006449 mSource.resetSubtreeAccessibilityStateChanged();
6450 mSource = null;
6451 }
6452
6453 public void runOrPost(View source) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006454 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006455 // If there is no common predecessor, then mSource points to
6456 // a removed view, hence in this case always prefer the source.
6457 View predecessor = getCommonPredecessor(mSource, source);
6458 mSource = (predecessor != null) ? predecessor : source;
Svetoslav6254f482013-06-04 17:22:14 -07006459 return;
6460 }
6461 mSource = source;
6462 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
6463 final long minEventIntevalMillis =
6464 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
6465 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006466 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07006467 run();
6468 } else {
6469 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006470 }
6471 }
6472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473}