blob: 6b2ed912d9d41a82b20f4dc237b3a4817effe21b [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;
Romain Guy211370f2012-02-01 16:10:55 -080026import android.content.pm.ApplicationInfo;
Romain Guy6b7bd242010-10-06 19:49:23 -070027import android.content.pm.PackageManager;
28import android.content.res.CompatibilityInfo;
29import android.content.res.Configuration;
30import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Canvas;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080032import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070034import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070035import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070036import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Rect;
38import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070039import android.graphics.drawable.Drawable;
Romain Guy6b7bd242010-10-06 19:49:23 -070040import android.media.AudioManager;
41import android.os.Binder;
42import android.os.Bundle;
43import android.os.Debug;
44import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070045import android.os.Looper;
46import android.os.Message;
47import android.os.ParcelFileDescriptor;
Romain Guy7e4e5612012-03-05 14:37:29 -080048import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070050import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070051import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070052import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080053import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070055import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070056import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070057import android.util.Slog;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080058import android.util.TypedValue;
Jeff Browna175a5b2012-02-15 19:18:31 -080059import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070061import android.view.accessibility.AccessibilityEvent;
62import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070063import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
64import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganov02107852011-10-03 17:06:56 -070065import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070066import android.view.accessibility.IAccessibilityInteractionConnection;
67import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080068import android.view.animation.AccelerateDecelerateInterpolator;
69import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.view.inputmethod.InputConnection;
71import android.view.inputmethod.InputMethodManager;
72import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070073
Svetoslav Ganov42138042012-03-20 11:51:39 -070074import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070075import com.android.internal.os.SomeArgs;
Joe Onorato86f67862010-11-05 18:57:34 -070076import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070077import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070078import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import java.io.IOException;
81import java.io.OutputStream;
Romain Guy6b7bd242010-10-06 19:49:23 -070082import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070084import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086/**
87 * The top of a view hierarchy, implementing the needed protocol between View
88 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070089 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 *
91 * {@hide}
92 */
Romain Guy812ccbe2010-06-01 14:07:24 -070093@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -080094public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -080095 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -070096 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -070098 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 /** @noinspection PointlessBooleanExpression*/
100 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
101 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800102 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
104 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
105 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
106 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700107 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700108 private static final boolean DEBUG_FPS = false;
Michael Wrightc8a7e542013-03-20 17:58:33 -0700109 private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110
Romain Guy51e4d4d2012-03-15 18:30:47 -0700111 private static final boolean USE_RENDER_THREAD = false;
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700112
Romain Guy59a12ca2011-06-09 17:48:21 -0700113 /**
114 * Set this system property to true to force the view hierarchy to render
115 * at 60 Hz. This can be used to measure the potential framerate.
116 */
Romain Guyd0750312012-11-29 11:34:43 -0800117 private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 /**
120 * Maximum time we allow the user to roll the trackball enough to generate
121 * a key event, before resetting the counters.
122 */
123 static final int MAX_TRACKBALL_DELAY = 250;
124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
126
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800127 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
128 static boolean sFirstDrawComplete = false;
129
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800130 static final ArrayList<ComponentCallbacks> sConfigCallbacks
131 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700132
Romain Guy211370f2012-02-01 16:10:55 -0800133 private static boolean sUseRenderThread = false;
134 private static boolean sRenderThreadQueried = false;
135 private static final Object[] sRenderThreadQueryLock = new Object[0];
136
Jeff Brownf9e989d2013-04-04 23:04:03 -0700137 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700138 final IWindowSession mWindowSession;
139 final Display mDisplay;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800140 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700143
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800144 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 final Thread mThread;
147
148 final WindowLeaked mLocation;
149
150 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
151
152 final W mWindow;
153
Dianne Hackborn180c4842011-09-13 12:39:25 -0700154 final int mTargetSdkVersion;
155
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700156 int mSeq;
157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700159
160 View mAccessibilityFocusedHost;
161 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 int mViewVisibility;
164 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700165 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Dianne Hackbornce418e62011-03-01 14:31:38 -0800167 // Set to true if the owner of this window is in the stopped state,
168 // so the window should no longer be active.
169 boolean mStopped = false;
170
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700171 boolean mLastInCompatMode = false;
172
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700173 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700174 BaseSurfaceHolder mSurfaceHolder;
175 boolean mIsCreating;
176 boolean mDrawingAllowed;
177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 final Region mTransparentRegion;
179 final Region mPreviousTransparentRegion;
180
181 int mWidth;
182 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800183 Rect mDirty;
184 final Rect mCurrentDirty = new Rect();
Romain Guybb93d552009-03-24 21:04:15 -0700185 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700186
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700187 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
189 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700190 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700191 InputQueue.Callback mInputQueueCallback;
192 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700193 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800194 Choreographer mChoreographer;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 final Rect mTempRect; // used in the transaction to not thrash the heap.
197 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
199 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800200 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700202 /** Set to true while in performTraversals for detecting when die(true) is called from internal
203 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
204 boolean mIsInTraversal;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700205 boolean mFitSystemWindowsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 boolean mLayoutRequested;
207 boolean mFirst;
208 boolean mReportNextDraw;
209 boolean mFullRedrawNeeded;
210 boolean mNewSurfaceNeeded;
211 boolean mHasHadWindowFocus;
212 boolean mLastWasImTarget;
Dianne Hackborn12d3a942012-04-27 14:16:30 -0700213 boolean mWindowsAnimating;
Michael Jurkaf42d90102013-05-08 18:00:04 +0200214 boolean mDrawDuringWindowsAnimating;
Romain Guy1f59e5c2012-05-06 14:11:16 -0700215 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700216 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700217 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800218 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800219
220 // Pool of queued input events.
221 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
222 private QueuedInputEvent mQueuedInputEventPool;
223 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800224
Michael Wrightc8a7e542013-03-20 17:58:33 -0700225 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700226 * Pending input events are input events waiting to be delivered to the input stages
227 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700228 */
229 QueuedInputEvent mPendingInputEventHead;
230 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700231 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800232 boolean mProcessInputEventsScheduled;
Michael Wright95ae9422013-03-14 10:58:50 -0700233 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700234
235 InputStage mFirstInputStage;
236 InputStage mFirstPostImeInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
238 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700239 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700242 // Surface can never be reassigned or cleared (use Surface.clear()).
243 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244
245 boolean mAdded;
246 boolean mAddedTouchMode;
247
Jeff Brown98365d72012-08-19 20:30:52 -0700248 final CompatibilityInfoHolder mCompatibilityInfo;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 // These are accessed by multiple threads.
251 final Rect mWinFrame; // frame given by window manager.
252
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800253 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 final Rect mPendingVisibleInsets = new Rect();
255 final Rect mPendingContentInsets = new Rect();
256 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
257 = new ViewTreeObserver.InternalInsetsInfo();
258
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700259 final Rect mFitSystemWindowsInsets = new Rect();
260
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700261 final Configuration mLastConfiguration = new Configuration();
262 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 boolean mScrollMayChange;
265 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800266 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 int mScrollY;
268 int mCurScrollY;
269 Scroller mScroller;
Romain Guy7d70fbf2011-05-24 17:40:25 -0700270 HardwareLayer mResizeBuffer;
271 long mResizeBufferStartTime;
272 int mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800273 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700274 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700275
Romain Guy8506ab42009-06-11 17:35:47 -0700276 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
Christopher Tatea53146c2010-09-07 11:57:52 -0700278 /* Drag/drop */
279 ClipDescription mDragDescription;
280 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800281 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700282 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700283 final PointF mLastTouchPoint = new PointF();
Romain Guy59a12ca2011-06-09 17:48:21 -0700284
285 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800286 private Choreographer.FrameCallback mRenderProfiler;
287 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700288
Chet Haase2f2022a2011-10-11 06:41:59 -0700289 // Variables to track frames per second, enabled via DEBUG_FPS flag
290 private long mFpsStartTime = -1;
291 private long mFpsPrevTime = -1;
292 private int mFpsNumFrames;
293
Romain Guyfbb93fa2012-12-03 18:50:35 -0800294 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
Romain Guy51e4d4d2012-03-15 18:30:47 -0700295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 /**
297 * see {@link #playSoundEffect(int)}
298 */
299 AudioManager mAudioManager;
300
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700301 final AccessibilityManager mAccessibilityManager;
302
Gilles Debunne5ac84422011-10-19 09:35:58 -0700303 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700304
305 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
306
Svetoslav Ganova0156172011-06-26 17:55:44 -0700307 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700308
Svetoslav Ganov42138042012-03-20 11:51:39 -0700309 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800310
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700311 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700312 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700313
Chet Haase97140572012-09-13 14:56:47 -0700314 private boolean mInLayout = false;
315 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
316 boolean mHandlingLayoutInLayoutRequest = false;
317
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700318 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700319
Jeff Brown21bc5c92011-02-28 18:27:14 -0800320 /**
321 * Consistency verifier for debugging purposes.
322 */
323 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
324 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
325 new InputEventConsistencyVerifier(this, 0) : null;
326
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700327 static final class SystemUiVisibilityInfo {
328 int seq;
329 int globalVisibility;
330 int localValue;
331 int localChanges;
332 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700333
Jeff Brown98365d72012-08-19 20:30:52 -0700334 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700335 mContext = context;
336 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700337 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800338 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700339
340 CompatibilityInfoHolder cih = display.getCompatibilityInfo();
341 mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 mThread = Thread.currentThread();
344 mLocation = new WindowLeaked(null);
345 mLocation.fillInStackTrace();
346 mWidth = -1;
347 mHeight = -1;
348 mDirty = new Rect();
349 mTempRect = new Rect();
350 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700352 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700353 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 mViewVisibility = View.GONE;
355 mTransparentRegion = new Region();
356 mPreviousTransparentRegion = new Region();
357 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700359 mAccessibilityManager = AccessibilityManager.getInstance(context);
360 mAccessibilityInteractionConnectionManager =
361 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800362 mAccessibilityManager.addAccessibilityStateChangeListener(
363 mAccessibilityInteractionConnectionManager);
Jeff Brown98365d72012-08-19 20:30:52 -0700364 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700366 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700367 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700368 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800369 mChoreographer = Choreographer.getInstance();
Romain Guy7e4e5612012-03-05 14:37:29 -0800370
371 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
372 mAttachInfo.mScreenOn = powerManager.isScreenOn();
Dianne Hackborna53de062012-05-08 18:53:51 -0700373 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 }
375
Romain Guy211370f2012-02-01 16:10:55 -0800376 /**
377 * @return True if the application requests the use of a separate render thread,
378 * false otherwise
379 */
380 private static boolean isRenderThreadRequested(Context context) {
Romain Guy51e4d4d2012-03-15 18:30:47 -0700381 if (USE_RENDER_THREAD) {
382 synchronized (sRenderThreadQueryLock) {
383 if (!sRenderThreadQueried) {
384 final PackageManager packageManager = context.getPackageManager();
385 final String packageName = context.getApplicationInfo().packageName;
386 try {
387 ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
388 PackageManager.GET_META_DATA);
389 if (applicationInfo.metaData != null) {
390 sUseRenderThread = applicationInfo.metaData.getBoolean(
391 "android.graphics.renderThread", false);
392 }
393 } catch (PackageManager.NameNotFoundException e) {
394 } finally {
395 sRenderThreadQueried = true;
Romain Guy211370f2012-02-01 16:10:55 -0800396 }
Romain Guy211370f2012-02-01 16:10:55 -0800397 }
Romain Guy51e4d4d2012-03-15 18:30:47 -0700398 return sUseRenderThread;
Romain Guy211370f2012-02-01 16:10:55 -0800399 }
Romain Guy51e4d4d2012-03-15 18:30:47 -0700400 } else {
401 return false;
Romain Guy211370f2012-02-01 16:10:55 -0800402 }
403 }
404
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800405 public static void addFirstDrawHandler(Runnable callback) {
406 synchronized (sFirstDrawHandlers) {
407 if (!sFirstDrawComplete) {
408 sFirstDrawHandlers.add(callback);
409 }
410 }
411 }
412
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800413 public static void addConfigCallback(ComponentCallbacks callback) {
414 synchronized (sConfigCallbacks) {
415 sConfigCallbacks.add(callback);
416 }
417 }
418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 // FIXME for perf testing only
420 private boolean mProfile = false;
421
422 /**
423 * Call this to profile the next traversal call.
424 * FIXME for perf testing only. Remove eventually
425 */
426 public void profile() {
427 mProfile = true;
428 }
429
430 /**
431 * Indicates whether we are in touch mode. Calling this method triggers an IPC
432 * call and should be avoided whenever possible.
433 *
434 * @return True, if the device is in touch mode, false otherwise.
435 *
436 * @hide
437 */
438 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700439 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
440 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700442 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 } catch (RemoteException e) {
444 }
445 }
446 return false;
447 }
448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 /**
450 * We have one child
451 */
Romain Guye4d01122010-06-16 18:44:05 -0700452 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 synchronized (this) {
454 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700455 mView = view;
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700456 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700457 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700458 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800459 if (mWindowAttributes.packageName == null) {
460 mWindowAttributes.packageName = mBasePackageName;
461 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700462 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700463 // Keep track of the actual window flags supplied by the client.
464 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700465
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700466 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700467
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700468 if (view instanceof RootViewSurfaceTaker) {
469 mSurfaceHolderCallback =
470 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
471 if (mSurfaceHolderCallback != null) {
472 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700473 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700474 }
475 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800476
Romain Guy856d4e12011-10-14 15:47:55 -0700477 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
478 mTranslator = compatibilityInfo.getTranslator();
479
Romain Guy1aec9a22011-01-05 09:37:12 -0800480 // If the application owns the surface, don't enable hardware acceleration
481 if (mSurfaceHolder == null) {
Romain Guy211370f2012-02-01 16:10:55 -0800482 enableHardwareAcceleration(mView.getContext(), attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800483 }
484
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700485 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700486 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700487 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700488 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700489 attrs.backup();
490 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700491 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700492 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
493
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700494 if (!compatibilityInfo.supportsScreen()) {
495 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700496 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700497 }
498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 mSoftInputMode = attrs.softInputMode;
500 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700501 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700503 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700504 mAttachInfo.mApplicationScale =
505 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 if (panelParentView != null) {
507 mAttachInfo.mPanelParentWindowToken
508 = panelParentView.getApplicationWindowToken();
509 }
510 mAdded = true;
511 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 // Schedule the first layout -before- adding to the window
514 // manager, to make sure we do the relayout before receiving
515 // any other events from the system.
516 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700517 if ((mWindowAttributes.inputFeatures
518 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
519 mInputChannel = new InputChannel();
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700522 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700523 mAttachInfo.mRecomputeGlobalAttributes = true;
524 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700525 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
526 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700527 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 } catch (RemoteException e) {
529 mAdded = false;
530 mView = null;
531 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700532 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700533 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700535 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700537 } finally {
538 if (restore) {
539 attrs.restore();
540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700542
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700543 if (mTranslator != null) {
544 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700545 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800546 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 mPendingContentInsets.set(mAttachInfo.mContentInsets);
548 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800549 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700550 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 mAttachInfo.mRootView = null;
552 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700553 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700555 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700557 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
558 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
559 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 "Unable to add window -- token " + attrs.token
561 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700562 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
563 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 "Unable to add window -- token " + attrs.token
565 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700566 case WindowManagerGlobal.ADD_APP_EXITING:
567 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 "Unable to add window -- app for token " + attrs.token
569 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700570 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
571 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 "Unable to add window -- window " + mWindow
573 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700574 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 // Silently ignore -- we would have just removed it
576 // right away, anyway.
577 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700578 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
579 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 "Unable to add window " + mWindow +
581 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700582 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
583 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 "Unable to add window " + mWindow +
585 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700586 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
587 throw new WindowManager.InvalidDisplayException(
588 "Unable to add window " + mWindow +
589 " -- the specified display can not be found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 }
591 throw new RuntimeException(
592 "Unable to add window -- unknown error code " + res);
593 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700594
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700595 if (view instanceof RootViewSurfaceTaker) {
596 mInputQueueCallback =
597 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
598 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700599 if (mInputChannel != null) {
600 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700601 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700602 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700603 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700604 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
605 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700606 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700609 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
610 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700611
612 if (mAccessibilityManager.isEnabled()) {
613 mAccessibilityInteractionConnectionManager.ensureConnection();
614 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700615
616 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
617 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
618 }
Michael Wright95ae9422013-03-14 10:58:50 -0700619
Jeff Brownf9e989d2013-04-04 23:04:03 -0700620 // Set up the input pipeline.
621 CharSequence counterSuffix = attrs.getTitle();
622 InputStage syntheticStage = new SyntheticInputStage();
623 InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticStage);
624 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
625 "aq:native-post-ime:" + counterSuffix);
626 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
627 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
628 "aq:ime:" + counterSuffix);
629 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
630 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
631 "aq:native-pre-ime:" + counterSuffix);
632
633 mFirstInputStage = nativePreImeStage;
634 mFirstPostImeInputStage = earlyPostImeStage;
635 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 }
637 }
638 }
639
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800640 void destroyHardwareResources() {
Romain Guy65b345f2011-07-27 18:51:50 -0700641 if (mAttachInfo.mHardwareRenderer != null) {
642 if (mAttachInfo.mHardwareRenderer.isEnabled()) {
643 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
644 }
645 mAttachInfo.mHardwareRenderer.destroy(false);
Romain Guy6d7475d2011-07-27 16:28:21 -0700646 }
Romain Guy65b345f2011-07-27 18:51:50 -0700647 }
648
Romain Guy31f2c2e2011-11-21 10:55:41 -0800649 void terminateHardwareResources() {
650 if (mAttachInfo.mHardwareRenderer != null) {
651 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
652 mAttachInfo.mHardwareRenderer.destroy(false);
653 }
654 }
655
Romain Guy65b345f2011-07-27 18:51:50 -0700656 void destroyHardwareLayers() {
657 if (mThread != Thread.currentThread()) {
658 if (mAttachInfo.mHardwareRenderer != null &&
659 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700660 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700661 }
662 } else {
663 if (mAttachInfo.mHardwareRenderer != null &&
664 mAttachInfo.mHardwareRenderer.isEnabled()) {
665 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
666 }
667 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700668 }
669
Romain Guy11cb6422012-09-21 00:39:43 -0700670 void pushHardwareLayerUpdate(HardwareLayer layer) {
671 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
672 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
673 }
674 }
675
Chris Craik41ee4652012-05-31 15:05:57 -0700676 public boolean attachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700677 //noinspection SimplifiableIfStatement
Romain Guyba6be8a2012-04-23 18:22:09 -0700678 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Chris Craik41ee4652012-05-31 15:05:57 -0700679 return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700680 }
Chris Craik41ee4652012-05-31 15:05:57 -0700681 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -0700682 }
683
684 public void detachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700685 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700686 mAttachInfo.mHardwareRenderer.detachFunctor(functor);
687 }
688 }
689
Romain Guy211370f2012-02-01 16:10:55 -0800690 private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800691 mAttachInfo.mHardwareAccelerated = false;
692 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800693
Romain Guy856d4e12011-10-14 15:47:55 -0700694 // Don't enable hardware acceleration when the application is in compatibility mode
695 if (mTranslator != null) return;
696
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800697 // Try to enable hardware acceleration if requested
Jim Miller1b365922011-03-09 19:38:07 -0800698 final boolean hardwareAccelerated =
699 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
700
Romain Guy566c3312011-03-21 18:21:28 -0700701 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700702 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700703 return;
704 }
705
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700706 // Persistent processes (including the system) should not do
707 // accelerated rendering on low-end devices. In that case,
708 // sRendererDisabled will be set. In addition, the system process
709 // itself should never do accelerated rendering. In that case, both
710 // sRendererDisabled and sSystemRendererDisabled are set. When
711 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
712 // can be used by code on the system process to escape that and enable
713 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800714
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700715 final boolean fakeHwAccelerated = (attrs.privateFlags &
716 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
717 final boolean forceHwAccelerated = (attrs.privateFlags &
718 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800719
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700720 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
721 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800722 // Don't enable hardware acceleration when we're not on the main thread
Romain Guy211370f2012-02-01 16:10:55 -0800723 if (!HardwareRenderer.sSystemRendererDisabled &&
724 Looper.getMainLooper() != Looper.myLooper()) {
725 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800726 + "acceleration outside of the main thread, aborting");
727 return;
728 }
729
Romain Guy51e4d4d2012-03-15 18:30:47 -0700730 final boolean renderThread = isRenderThreadRequested(context);
Romain Guy211370f2012-02-01 16:10:55 -0800731 if (renderThread) {
732 Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
733 }
734
Romain Guyb051e892010-09-28 19:09:36 -0700735 if (mAttachInfo.mHardwareRenderer != null) {
736 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy211370f2012-02-01 16:10:55 -0800737 }
738
739 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700740 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700741 if (mAttachInfo.mHardwareRenderer != null) {
742 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
743 mAttachInfo.mHardwareAccelerated =
744 mAttachInfo.mHardwareAccelerationRequested = true;
745 }
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700746 } else if (fakeHwAccelerated) {
747 // The window had wanted to use hardware acceleration, but this
748 // is not allowed in its process. By setting this flag, it can
749 // still render as if it was accelerated. This is basically for
750 // the preview windows the window manager shows for launching
751 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700752 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700753 }
754 }
755 }
756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 public View getView() {
758 return mView;
759 }
760
761 final WindowLeaked getLocation() {
762 return mLocation;
763 }
764
765 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
766 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700767 int oldSoftInputMode = mWindowAttributes.softInputMode;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700768 // Keep track of the actual window flags supplied by the client.
769 mClientWindowLayoutFlags = attrs.flags;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700770 // preserve compatible window flag if exists.
771 int compatibleWindowFlag =
772 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Craig Mautner3fe38c02012-05-03 17:28:09 -0700773 // transfer over system UI visibility values as they carry current state.
774 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
775 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Romain Guyf21c9b02011-09-06 16:56:54 -0700776 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800777 if (mWindowAttributes.packageName == null) {
778 mWindowAttributes.packageName = mBasePackageName;
779 }
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700780 mWindowAttributes.flags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700781
782 applyKeepScreenOnFlag(mWindowAttributes);
783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 if (newView) {
785 mSoftInputMode = attrs.softInputMode;
786 requestLayout();
787 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700788 // Don't lose the mode we last auto-computed.
789 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
790 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
791 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
792 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
793 | (oldSoftInputMode
794 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 mWindowAttributesChanged = true;
797 scheduleTraversals();
798 }
799 }
800
801 void handleAppVisibility(boolean visible) {
802 if (mAppVisible != visible) {
803 mAppVisible = visible;
804 scheduleTraversals();
805 }
806 }
807
808 void handleGetNewSurface() {
809 mNewSurfaceNeeded = true;
810 mFullRedrawNeeded = true;
811 scheduleTraversals();
812 }
813
Romain Guybb9908b2012-03-08 11:14:07 -0800814 void handleScreenStateChange(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -0800815 if (on != mAttachInfo.mScreenOn) {
816 mAttachInfo.mScreenOn = on;
Romain Guybb9908b2012-03-08 11:14:07 -0800817 if (mView != null) {
818 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
819 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800820 if (on) {
821 mFullRedrawNeeded = true;
822 scheduleTraversals();
823 }
824 }
825 }
826
Craig Mautner6018aee2012-10-23 14:27:49 -0700827 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700828 public void requestFitSystemWindows() {
829 checkThread();
830 mFitSystemWindowsRequested = true;
831 scheduleTraversals();
832 }
833
Craig Mautner6018aee2012-10-23 14:27:49 -0700834 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800836 if (!mHandlingLayoutInLayoutRequest) {
837 checkThread();
838 mLayoutRequested = true;
839 scheduleTraversals();
840 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 }
842
Craig Mautner6018aee2012-10-23 14:27:49 -0700843 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 public boolean isLayoutRequested() {
845 return mLayoutRequested;
846 }
847
Romain Guycfef1232012-02-23 13:50:37 -0800848 void invalidate() {
849 mDirty.set(0, 0, mWidth, mHeight);
850 scheduleTraversals();
851 }
852
Dianne Hackborna53de062012-05-08 18:53:51 -0700853 void invalidateWorld(View view) {
854 view.invalidate();
855 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700856 ViewGroup parent = (ViewGroup) view;
857 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700858 invalidateWorld(parent.getChildAt(i));
859 }
860 }
861 }
862
Craig Mautner6018aee2012-10-23 14:27:49 -0700863 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800865 invalidateChildInParent(null, dirty);
866 }
867
868 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700870 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800871
Chet Haase70d4ba12010-10-06 09:46:45 -0700872 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700873 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800874 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700875 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700876 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700877 }
Romain Guycfef1232012-02-23 13:50:37 -0800878
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700879 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700881 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700882 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800883 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700884 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700885 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700886 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700887 }
Romain Guy1e095972009-07-07 11:22:45 -0700888 if (mAttachInfo.mScalingRequired) {
889 dirty.inset(-1, -1);
890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 }
Romain Guycfef1232012-02-23 13:50:37 -0800892
893 final Rect localDirty = mDirty;
894 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700895 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800896 mAttachInfo.mIgnoreDirtyState = true;
897 }
Romain Guycfef1232012-02-23 13:50:37 -0800898
899 // Add the new dirty rect to the current one
900 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
901 // Intersect with the bounds of the window to skip
902 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700903 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700904 final boolean intersected = localDirty.intersect(0, 0,
905 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
906 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700907 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 }
Chet Haase3561d062012-10-23 12:54:51 -0700909 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
910 scheduleTraversals();
911 }
Romain Guycfef1232012-02-23 13:50:37 -0800912
913 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915
Dianne Hackbornce418e62011-03-01 14:31:38 -0800916 void setStopped(boolean stopped) {
917 if (mStopped != stopped) {
918 mStopped = stopped;
919 if (!stopped) {
920 scheduleTraversals();
921 }
922 }
923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924
Romain Guycfef1232012-02-23 13:50:37 -0800925 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 return null;
927 }
928
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700929 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 if (child != mView) {
931 throw new RuntimeException("child is not mine, honest!");
932 }
933 // Note: don't apply scroll offset, because we want to know its
934 // visibility in the virtual canvas being given to the view hierarchy.
935 return r.intersect(0, 0, mWidth, mHeight);
936 }
937
938 public void bringChildToFront(View child) {
939 }
940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 int getHostVisibility() {
942 return mAppVisible ? mView.getVisibility() : View.GONE;
943 }
Romain Guy8506ab42009-06-11 17:35:47 -0700944
Romain Guy7d70fbf2011-05-24 17:40:25 -0700945 void disposeResizeBuffer() {
946 if (mResizeBuffer != null) {
947 mResizeBuffer.destroy();
948 mResizeBuffer = null;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800949 }
950 }
951
Chet Haasecca2c982011-05-20 14:34:18 -0700952 /**
953 * Add LayoutTransition to the list of transitions to be started in the next traversal.
954 * This list will be cleared after the transitions on the list are start()'ed. These
955 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
956 * happens during the layout phase of traversal, which we want to complete before any of the
957 * animations are started (because those animations may side-effect properties that layout
958 * depends upon, like the bounding rectangles of the affected views). So we add the transition
959 * to the list and it is started just prior to starting the drawing phase of traversal.
960 *
961 * @param transition The LayoutTransition to be started on the next traversal.
962 *
963 * @hide
964 */
965 public void requestTransitionStart(LayoutTransition transition) {
966 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
967 if (mPendingTransitions == null) {
968 mPendingTransitions = new ArrayList<LayoutTransition>();
969 }
970 mPendingTransitions.add(transition);
971 }
972 }
973
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700974 void scheduleTraversals() {
975 if (!mTraversalScheduled) {
976 mTraversalScheduled = true;
977 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
978 mChoreographer.postCallback(
979 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Jeff Brown330314c2012-04-27 02:20:22 -0700980 scheduleConsumeBatchedInput();
Jeff Brown96e942d2011-11-30 19:55:01 -0800981 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700982 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800983
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700984 void unscheduleTraversals() {
985 if (mTraversalScheduled) {
986 mTraversalScheduled = false;
987 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
988 mChoreographer.removeCallbacks(
989 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
990 }
991 }
992
993 void doTraversal() {
994 if (mTraversalScheduled) {
995 mTraversalScheduled = false;
996 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
997
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700998 if (mProfile) {
999 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001000 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001001
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001002 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
1003 try {
1004 performTraversals();
1005 } finally {
1006 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1007 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001008
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001009 if (mProfile) {
1010 Debug.stopMethodTracing();
1011 mProfile = false;
1012 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001013 }
1014 }
1015
Dianne Hackborn9d090892012-06-11 18:35:41 -07001016 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1017 // Update window's global keep screen on flag: if a view has requested
1018 // that the screen be kept on, then it is always set; otherwise, it is
1019 // set to whatever the client last requested for the global state.
1020 if (mAttachInfo.mKeepScreenOn) {
1021 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1022 } else {
1023 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1024 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1025 }
1026 }
1027
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001028 private boolean collectViewAttributes() {
1029 final View.AttachInfo attachInfo = mAttachInfo;
1030 if (attachInfo.mRecomputeGlobalAttributes) {
1031 //Log.i(TAG, "Computing view hierarchy attributes!");
1032 attachInfo.mRecomputeGlobalAttributes = false;
1033 boolean oldScreenOn = attachInfo.mKeepScreenOn;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001034 attachInfo.mKeepScreenOn = false;
1035 attachInfo.mSystemUiVisibility = 0;
1036 attachInfo.mHasSystemUiListeners = false;
1037 mView.dispatchCollectViewAttributes(attachInfo, 0);
Dianne Hackborn139e5aa2012-05-05 20:36:38 -07001038 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001039 WindowManager.LayoutParams params = mWindowAttributes;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001040 if (attachInfo.mKeepScreenOn != oldScreenOn
Craig Mautner7eac0f52012-09-13 13:14:14 -07001041 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1042 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001043 applyKeepScreenOnFlag(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001044 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1045 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1046 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1047 return true;
1048 }
1049 }
1050 return false;
1051 }
1052
1053 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1054 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1055 int childWidthMeasureSpec;
1056 int childHeightMeasureSpec;
1057 boolean windowSizeMayChange = false;
1058
1059 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1060 "Measuring " + host + " in display " + desiredWindowWidth
1061 + "x" + desiredWindowHeight + "...");
1062
1063 boolean goodMeasure = false;
1064 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1065 // On large screens, we don't want to allow dialogs to just
1066 // stretch to fill the entire width of the screen to display
1067 // one line of text. First try doing the layout at a smaller
1068 // size to see if it will fit.
1069 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1070 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1071 int baseSize = 0;
1072 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1073 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1074 }
1075 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1076 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1077 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1078 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001079 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001080 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1081 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1082 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1083 goodMeasure = true;
1084 } else {
1085 // Didn't fit in that size... try expanding a bit.
1086 baseSize = (baseSize+desiredWindowWidth)/2;
1087 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1088 + baseSize);
1089 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001090 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001091 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1092 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1093 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1094 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1095 goodMeasure = true;
1096 }
1097 }
1098 }
1099 }
1100
1101 if (!goodMeasure) {
1102 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1103 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001104 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001105 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1106 windowSizeMayChange = true;
1107 }
1108 }
1109
1110 if (DBG) {
1111 System.out.println("======================================");
1112 System.out.println("performTraversals -- after measure");
1113 host.debug();
1114 }
1115
1116 return windowSizeMayChange;
1117 }
1118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 private void performTraversals() {
1120 // cache mView since it is used so much below...
1121 final View host = mView;
1122
1123 if (DBG) {
1124 System.out.println("======================================");
1125 System.out.println("performTraversals");
1126 host.debug();
1127 }
1128
1129 if (host == null || !mAdded)
1130 return;
1131
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001132 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001134 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001136 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 WindowManager.LayoutParams lp = mWindowAttributes;
1138
1139 int desiredWindowWidth;
1140 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141
1142 final View.AttachInfo attachInfo = mAttachInfo;
1143
1144 final int viewVisibility = getHostVisibility();
1145 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1146 || mNewSurfaceNeeded;
1147
1148 WindowManager.LayoutParams params = null;
1149 if (mWindowAttributesChanged) {
1150 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001151 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 params = lp;
1153 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001154 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
1155 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1156 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001157 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001158 mLayoutRequested = true;
1159 if (mLastInCompatMode) {
1160 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1161 mLastInCompatMode = false;
1162 } else {
1163 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1164 mLastInCompatMode = true;
1165 }
1166 }
Romain Guyf21c9b02011-09-06 16:56:54 -07001167
1168 mWindowAttributesChangesFlag = 0;
1169
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001170 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001172 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 mLayoutRequested = true;
1174
Dianne Hackborna239c842011-06-01 12:28:20 -07001175 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1176 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001177 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001178 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001179 desiredWindowWidth = size.x;
1180 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001181 } else {
1182 DisplayMetrics packageMetrics =
1183 mView.getContext().getResources().getDisplayMetrics();
1184 desiredWindowWidth = packageMetrics.widthPixels;
1185 desiredWindowHeight = packageMetrics.heightPixels;
1186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187
1188 // For the very first time, tell the view hierarchy that it
1189 // is attached to the window. Note that at this point the surface
1190 // object is not initialized to its backing store, but soon it
1191 // will be (assuming the window is visible).
1192 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -08001193 // We used to use the following condition to choose 32 bits drawing caches:
1194 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1195 // However, windows are now always 32 bits by default, so choose 32 bits
1196 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 attachInfo.mHasWindowFocus = false;
1198 attachInfo.mWindowVisibility = viewVisibility;
1199 attachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001201 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001202 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001203 // Set the layout direction if it has not been set before (inherit is the default)
1204 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1205 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 host.dispatchAttachedToWindow(attachInfo, 0);
Dianne Hackborn961cae92013-03-20 14:59:43 -07001208 attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001209 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1210 host.fitSystemWindows(mFitSystemWindowsInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001214 desiredWindowWidth = frame.width();
1215 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001217 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001218 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001219 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001221 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 }
1223 }
1224
1225 if (viewVisibilityChanged) {
1226 attachInfo.mWindowVisibility = viewVisibility;
1227 host.dispatchWindowVisibilityChanged(viewVisibility);
1228 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001229 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 }
1231 if (viewVisibility == View.GONE) {
1232 // After making a window gone, we will count it as being
1233 // shown for the first time the next time it gets focus.
1234 mHasHadWindowFocus = false;
1235 }
1236 }
1237
Chet Haaseb78c2842012-04-19 13:39:50 -07001238 // Execute enqueued actions on every traversal in case a detached view enqueued an action
1239 getRunQueue().executeActions(attachInfo.mHandler);
1240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001242
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001243 boolean layoutRequested = mLayoutRequested && !mStopped;
1244 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001245
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001246 final Resources res = mView.getContext().getResources();
1247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 // make sure touch mode code executes by setting cached value
1250 // to opposite of the added touch mode.
1251 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001252 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001254 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1255 insetsChanged = true;
1256 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001257 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001260 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1262 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1263 + mAttachInfo.mVisibleInsets);
1264 }
1265 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1266 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001267 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268
Dianne Hackborna239c842011-06-01 12:28:20 -07001269 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1270 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001271 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001272 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001273 desiredWindowWidth = size.x;
1274 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001275 } else {
1276 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1277 desiredWindowWidth = packageMetrics.widthPixels;
1278 desiredWindowHeight = packageMetrics.heightPixels;
1279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281 }
1282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001284 windowSizeMayChange |= measureHierarchy(host, lp, res,
1285 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 }
1287
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001288 if (collectViewAttributes()) {
1289 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001291 if (attachInfo.mForceReportNewAttributes) {
1292 attachInfo.mForceReportNewAttributes = false;
1293 params = lp;
1294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295
1296 if (mFirst || attachInfo.mViewVisibilityChanged) {
1297 attachInfo.mViewVisibilityChanged = false;
1298 int resizeMode = mSoftInputMode &
1299 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1300 // If we are in auto resize mode, then we need to determine
1301 // what mode to use now.
1302 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1303 final int N = attachInfo.mScrollContainers.size();
1304 for (int i=0; i<N; i++) {
1305 if (attachInfo.mScrollContainers.get(i).isShown()) {
1306 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1307 }
1308 }
1309 if (resizeMode == 0) {
1310 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1311 }
1312 if ((lp.softInputMode &
1313 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1314 lp.softInputMode = (lp.softInputMode &
1315 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1316 resizeMode;
1317 params = lp;
1318 }
1319 }
1320 }
Romain Guy8506ab42009-06-11 17:35:47 -07001321
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001322 if (params != null) {
1323 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1324 if (!PixelFormat.formatHasAlpha(params.format)) {
1325 params.format = PixelFormat.TRANSLUCENT;
1326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001328 mAttachInfo.mOverscanRequested = (params.flags
1329 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 }
1331
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001332 if (mFitSystemWindowsRequested) {
1333 mFitSystemWindowsRequested = false;
1334 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001335 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001336 host.fitSystemWindows(mFitSystemWindowsInsets);
1337 if (mLayoutRequested) {
1338 // Short-circuit catching a new layout request here, so
1339 // we don't need to go through two layout passes when things
1340 // change due to fitting system windows, which can happen a lot.
1341 windowSizeMayChange |= measureHierarchy(host, lp,
1342 mView.getContext().getResources(),
1343 desiredWindowWidth, desiredWindowHeight);
1344 }
1345 }
1346
1347 if (layoutRequested) {
1348 // Clear this now, so that if anything requests a layout in the
1349 // rest of this function we will catch it and re-run a full
1350 // layout pass.
1351 mLayoutRequested = false;
1352 }
1353
1354 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001355 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001356 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1357 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1358 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1359 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360
1361 final boolean computesInternalInsets =
1362 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
Romain Guy812ccbe2010-06-01 14:07:24 -07001363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 boolean insetsPending = false;
1365 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001366
1367 if (mFirst || windowShouldResize || insetsChanged ||
1368 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369
1370 if (viewVisibility == View.VISIBLE) {
1371 // If this window is giving internal insets to the window
1372 // manager, and it is being added or changing its visibility,
1373 // then we want to first give the window manager "fake"
1374 // insets to cause it to effectively ignore the content of
1375 // the window during layout. This avoids it briefly causing
1376 // other windows to resize/move based on the raw frame of the
1377 // window, waiting until we can finish laying out this window
1378 // and get back to the window manager with the ultimately
1379 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001380 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 }
1382
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001383 if (mSurfaceHolder != null) {
1384 mSurfaceHolder.mSurfaceLock.lock();
1385 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001386 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001387
Romain Guyc361da82010-10-25 15:29:10 -07001388 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001390 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001393 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001394 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1395 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001396 }
Romain Guy2a83f002011-01-18 18:28:21 -08001397
1398 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001399 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
Michael Jurkaf42d90102013-05-08 18:00:04 +02001400 if (!mDrawDuringWindowsAnimating) {
1401 mWindowsAnimating |=
1402 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0;
1403 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001406 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 + " content=" + mPendingContentInsets.toShortString()
1408 + " visible=" + mPendingVisibleInsets.toShortString()
1409 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001410
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001411 if (mPendingConfiguration.seq != 0) {
1412 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1413 + mPendingConfiguration);
1414 updateConfiguration(mPendingConfiguration, !mFirst);
1415 mPendingConfiguration.seq = 0;
1416 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001417
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001418 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1419 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 contentInsetsChanged = !mPendingContentInsets.equals(
1421 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001422 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 mAttachInfo.mVisibleInsets);
1424 if (contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001425 if (mWidth > 0 && mHeight > 0 && lp != null &&
1426 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1427 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001428 mSurface != null && mSurface.isValid() &&
1429 !mAttachInfo.mTurnOffWindowResizeAnim &&
1430 mAttachInfo.mHardwareRenderer != null &&
1431 mAttachInfo.mHardwareRenderer.isEnabled() &&
1432 mAttachInfo.mHardwareRenderer.validate() &&
1433 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1434
1435 disposeResizeBuffer();
1436
1437 boolean completed = false;
Romain Guyc89b14b2012-08-08 14:53:48 -07001438 HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
Chet Haase08837c22011-11-28 11:53:21 -08001439 HardwareCanvas layerCanvas = null;
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001440 try {
1441 if (mResizeBuffer == null) {
1442 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1443 mWidth, mHeight, false);
1444 } else if (mResizeBuffer.getWidth() != mWidth ||
1445 mResizeBuffer.getHeight() != mHeight) {
1446 mResizeBuffer.resize(mWidth, mHeight);
1447 }
Chet Haase603f6de2012-09-14 15:31:25 -07001448 // TODO: should handle create/resize failure
Romain Guyc89b14b2012-08-08 14:53:48 -07001449 layerCanvas = mResizeBuffer.start(hwRendererCanvas);
Chet Haase08837c22011-11-28 11:53:21 -08001450 final int restoreCount = layerCanvas.save();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001451
1452 int yoff;
1453 final boolean scrolling = mScroller != null
1454 && mScroller.computeScrollOffset();
1455 if (scrolling) {
1456 yoff = mScroller.getCurrY();
1457 mScroller.abortAnimation();
1458 } else {
1459 yoff = mScrollY;
1460 }
1461
Chet Haase08837c22011-11-28 11:53:21 -08001462 layerCanvas.translate(0, -yoff);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001463 if (mTranslator != null) {
Chet Haase08837c22011-11-28 11:53:21 -08001464 mTranslator.translateCanvas(layerCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001465 }
1466
Romain Guy3a2d6aa2012-10-23 13:25:13 -07001467 DisplayList displayList = mView.mDisplayList;
1468 if (displayList != null) {
1469 layerCanvas.drawDisplayList(displayList, null,
1470 DisplayList.FLAG_CLIP_CHILDREN);
1471 } else {
1472 mView.draw(layerCanvas);
1473 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001474
Svetoslav Ganov42138042012-03-20 11:51:39 -07001475 drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1476
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001477 mResizeBufferStartTime = SystemClock.uptimeMillis();
1478 mResizeBufferDuration = mView.getResources().getInteger(
1479 com.android.internal.R.integer.config_mediumAnimTime);
1480 completed = true;
1481
Chet Haase08837c22011-11-28 11:53:21 -08001482 layerCanvas.restoreToCount(restoreCount);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001483 } catch (OutOfMemoryError e) {
1484 Log.w(TAG, "Not enough memory for content change anim buffer", e);
1485 } finally {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001486 if (mResizeBuffer != null) {
Romain Guyc89b14b2012-08-08 14:53:48 -07001487 mResizeBuffer.end(hwRendererCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001488 if (!completed) {
1489 mResizeBuffer.destroy();
1490 mResizeBuffer = null;
1491 }
1492 }
1493 }
1494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1497 + mAttachInfo.mContentInsets);
1498 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001499 if (overscanInsetsChanged) {
1500 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1501 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1502 + mAttachInfo.mOverscanInsets);
1503 // Need to relayout with content insets.
1504 contentInsetsChanged = true;
1505 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001506 if (contentInsetsChanged || mLastSystemUiVisibility !=
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001507 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
1508 || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001509 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001510 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001511 mFitSystemWindowsRequested = false;
1512 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1513 host.fitSystemWindows(mFitSystemWindowsInsets);
1514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 if (visibleInsetsChanged) {
1516 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1517 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1518 + mAttachInfo.mVisibleInsets);
1519 }
1520
1521 if (!hadSurface) {
1522 if (mSurface.isValid()) {
1523 // If we are creating a new surface, then we need to
1524 // completely redraw it. Also, when we get to the
1525 // point of drawing it we will hold off and schedule
1526 // a new traversal instead. This is so we can tell the
1527 // window manager about all of the windows being displayed
1528 // before actually drawing them, so it can display then
1529 // all at once.
1530 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001531 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001532 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001533
Romain Guyb051e892010-09-28 19:09:36 -07001534 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001535 try {
Romain Guy786fc932012-07-24 16:24:56 -07001536 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
1537 mHolder.getSurface());
Dianne Hackborn64825172011-03-02 21:32:58 -08001538 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001539 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001540 return;
1541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 }
1543 }
1544 } else if (!mSurface.isValid()) {
1545 // If the surface has been removed, then reset the scroll
1546 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001547 if (mLastScrolledFocus != null) {
1548 mLastScrolledFocus.clear();
1549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 mScrollY = mCurScrollY = 0;
1551 if (mScroller != null) {
1552 mScroller.abortAnimation();
1553 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001554 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001555 // Our surface is gone
1556 if (mAttachInfo.mHardwareRenderer != null &&
1557 mAttachInfo.mHardwareRenderer.isEnabled()) {
1558 mAttachInfo.mHardwareRenderer.destroy(true);
1559 }
Romain Guy2a83f002011-01-18 18:28:21 -08001560 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1561 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001562 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001563 try {
Romain Guy786fc932012-07-24 16:24:56 -07001564 mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
Dianne Hackborn64825172011-03-02 21:32:58 -08001565 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001566 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001567 return;
1568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 }
1570 } catch (RemoteException e) {
1571 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001574 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575
1576 attachInfo.mWindowLeft = frame.left;
1577 attachInfo.mWindowTop = frame.top;
1578
1579 // !!FIXME!! This next section handles the case where we did not get the
1580 // window size we asked for. We should avoid this by getting a maximum size from
1581 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001582 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001583 mWidth = frame.width();
1584 mHeight = frame.height();
1585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001587 if (mSurfaceHolder != null) {
1588 // The app owns the surface; tell it about what is going on.
1589 if (mSurface.isValid()) {
1590 // XXX .copyFrom() doesn't work!
1591 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1592 mSurfaceHolder.mSurface = mSurface;
1593 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001594 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001595 mSurfaceHolder.mSurfaceLock.unlock();
1596 if (mSurface.isValid()) {
1597 if (!hadSurface) {
1598 mSurfaceHolder.ungetCallbacks();
1599
1600 mIsCreating = true;
1601 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1602 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1603 if (callbacks != null) {
1604 for (SurfaceHolder.Callback c : callbacks) {
1605 c.surfaceCreated(mSurfaceHolder);
1606 }
1607 }
1608 surfaceChanged = true;
1609 }
1610 if (surfaceChanged) {
1611 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1612 lp.format, mWidth, mHeight);
1613 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1614 if (callbacks != null) {
1615 for (SurfaceHolder.Callback c : callbacks) {
1616 c.surfaceChanged(mSurfaceHolder, lp.format,
1617 mWidth, mHeight);
1618 }
1619 }
1620 }
1621 mIsCreating = false;
1622 } else if (hadSurface) {
1623 mSurfaceHolder.ungetCallbacks();
1624 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1625 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1626 if (callbacks != null) {
1627 for (SurfaceHolder.Callback c : callbacks) {
1628 c.surfaceDestroyed(mSurfaceHolder);
1629 }
1630 }
1631 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001632 try {
1633 mSurfaceHolder.mSurface = new Surface();
1634 } finally {
1635 mSurfaceHolder.mSurfaceLock.unlock();
1636 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001637 }
1638 }
Romain Guy53389bd2010-09-07 17:16:32 -07001639
Chet Haase40e03832011-10-06 08:34:13 -07001640 if (mAttachInfo.mHardwareRenderer != null &&
1641 mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guy370ab062013-05-21 12:15:07 -07001642 if (hwInitialized ||
Chet Haase40e03832011-10-06 08:34:13 -07001643 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1644 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1645 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1646 if (!hwInitialized) {
Romain Guy786fc932012-07-24 16:24:56 -07001647 mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
Chet Haase391fef02012-09-27 15:26:36 -07001648 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001649 }
Romain Guy03985752011-07-11 15:33:51 -07001650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 }
1652
Dianne Hackbornce418e62011-03-01 14:31:38 -08001653 if (!mStopped) {
1654 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001655 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001656 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1657 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001658 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1659 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001660
1661 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1662 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1663 + " mHeight=" + mHeight
1664 + " measuredHeight=" + host.getMeasuredHeight()
1665 + " coveredInsetsChanged=" + contentInsetsChanged);
1666
1667 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001668 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001669
1670 // Implementation of weights from WindowManager.LayoutParams
1671 // We just grow the dimensions as needed and re-measure if
1672 // needs be
1673 int width = host.getMeasuredWidth();
1674 int height = host.getMeasuredHeight();
1675 boolean measureAgain = false;
1676
1677 if (lp.horizontalWeight > 0.0f) {
1678 width += (int) ((mWidth - width) * lp.horizontalWeight);
1679 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1680 MeasureSpec.EXACTLY);
1681 measureAgain = true;
1682 }
1683 if (lp.verticalWeight > 0.0f) {
1684 height += (int) ((mHeight - height) * lp.verticalWeight);
1685 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1686 MeasureSpec.EXACTLY);
1687 measureAgain = true;
1688 }
1689
1690 if (measureAgain) {
1691 if (DEBUG_LAYOUT) Log.v(TAG,
1692 "And hey let's measure once more: width=" + width
1693 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001694 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001695 }
1696
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001697 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001700 } else {
1701 // Not the first pass and no window/insets/visibility change but the window
1702 // may have moved and we need check that and if so to update the left and right
1703 // in the attach info. We translate only the window frame since on window move
1704 // the window manager tells us only for the new frame but the insets are the
1705 // same and we do not want to translate them more than once.
1706
1707 // TODO: Well, we are checking whether the frame has changed similarly
1708 // to how this is done for the insets. This is however incorrect since
1709 // the insets and the frame are translated. For example, the old frame
1710 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1711 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1712 // true since we are comparing a not translated value to a translated one.
1713 // This scenario is rare but we may want to fix that.
1714
1715 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1716 || attachInfo.mWindowTop != frame.top);
1717 if (windowMoved) {
1718 if (mTranslator != null) {
1719 mTranslator.translateRectInScreenToAppWinFrame(frame);
1720 }
1721 attachInfo.mWindowLeft = frame.left;
1722 attachInfo.mWindowTop = frame.top;
1723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 }
1725
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001726 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 boolean triggerGlobalLayoutListener = didLayout
1728 || attachInfo.mRecomputeGlobalAttributes;
1729 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001730 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001732 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 // We can compute the transparent area
1734
Dianne Hackborn4702a852012-08-17 15:18:29 -07001735 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 // start out transparent
1737 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1738 host.getLocationInWindow(mTmpLocation);
1739 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1740 mTmpLocation[0] + host.mRight - host.mLeft,
1741 mTmpLocation[1] + host.mBottom - host.mTop);
1742
1743 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001744 if (mTranslator != null) {
1745 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1746 }
1747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1749 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001750 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 // reconfigure window manager
1752 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001753 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 } catch (RemoteException e) {
1755 }
1756 }
1757 }
1758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 if (DBG) {
1760 System.out.println("======================================");
1761 System.out.println("performTraversals -- after setFrame");
1762 host.debug();
1763 }
1764 }
1765
1766 if (triggerGlobalLayoutListener) {
1767 attachInfo.mRecomputeGlobalAttributes = false;
1768 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001769
1770 if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07001771 postSendWindowContentChangedCallback(mView);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 }
1774
1775 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001776 // Clear the original insets.
1777 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1778 insets.reset();
1779
1780 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001782
1783 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1785 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001786
1787 // Translate insets to screen coordinates if needed.
1788 final Rect contentInsets;
1789 final Rect visibleInsets;
1790 final Region touchableRegion;
1791 if (mTranslator != null) {
1792 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1793 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1794 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1795 } else {
1796 contentInsets = insets.contentInsets;
1797 visibleInsets = insets.visibleInsets;
1798 touchableRegion = insets.touchableRegion;
1799 }
1800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001802 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001803 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 } catch (RemoteException e) {
1805 }
1806 }
1807 }
Romain Guy8506ab42009-06-11 17:35:47 -07001808
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001809 boolean skipDraw = false;
1810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 if (mFirst) {
1812 // handle first focus request
1813 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1814 + mView.hasFocus());
1815 if (mView != null) {
1816 if (!mView.hasFocus()) {
1817 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001819 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001822 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824 }
Jeff Brown98365d72012-08-19 20:30:52 -07001825 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001826 // The first time we relayout the window, if the system is
1827 // doing window animations, we want to hold of on any future
1828 // draws until the animation is done.
1829 mWindowsAnimating = true;
1830 }
1831 } else if (mWindowsAnimating) {
1832 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 }
1834
1835 mFirst = false;
1836 mWillDrawSoon = false;
1837 mNewSurfaceNeeded = false;
1838 mViewVisibility = viewVisibility;
1839
1840 if (mAttachInfo.mHasWindowFocus) {
1841 final boolean imTarget = WindowManager.LayoutParams
1842 .mayUseInputMethod(mWindowAttributes.flags);
1843 if (imTarget != mLastWasImTarget) {
1844 mLastWasImTarget = imTarget;
1845 InputMethodManager imm = InputMethodManager.peekInstance();
1846 if (imm != null && imTarget) {
1847 imm.startGettingWindowFocus(mView);
1848 imm.onWindowFocus(mView, mView.findFocus(),
1849 mWindowAttributes.softInputMode,
1850 !mHasHadWindowFocus, mWindowAttributes.flags);
1851 }
1852 }
1853 }
Romain Guy8506ab42009-06-11 17:35:47 -07001854
Jeff Brown96e942d2011-11-30 19:55:01 -08001855 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001856 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001857 mReportNextDraw = true;
1858 }
1859
Romain Guyea835032011-07-28 19:24:37 -07001860 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1861 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862
Chet Haase61158c62011-09-06 22:19:45 -07001863 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001864 if (!skipDraw || mReportNextDraw) {
1865 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1866 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1867 mPendingTransitions.get(i).startChangingAnimations();
1868 }
1869 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001870 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001871
1872 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001875 if (viewVisibility == View.VISIBLE) {
1876 // Try again
1877 scheduleTraversals();
1878 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001879 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1880 mPendingTransitions.get(i).endChangingAnimations();
1881 }
1882 mPendingTransitions.clear();
1883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001885
1886 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 }
1888
Romain Guy3696779b2013-01-28 14:04:07 -08001889 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
1890 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1891 try {
1892 if (!mWindowSession.outOfMemory(mWindow) &&
1893 Process.myUid() != Process.SYSTEM_UID) {
1894 Slog.w(TAG, "No processes killed for memory; killing self");
1895 Process.killProcess(Process.myPid());
1896 }
1897 } catch (RemoteException ex) {
1898 }
1899 mLayoutRequested = true; // ask wm for a new surface next time.
1900 }
1901
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001902 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1903 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1904 try {
1905 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1906 } finally {
1907 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1908 }
1909 }
1910
Chet Haase97140572012-09-13 14:56:47 -07001911 /**
1912 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
1913 * is currently undergoing a layout pass.
1914 *
1915 * @return whether the view hierarchy is currently undergoing a layout pass
1916 */
1917 boolean isInLayout() {
1918 return mInLayout;
1919 }
1920
1921 /**
Chet Haasecc699b42012-12-13 09:06:55 -08001922 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
1923 * undergoing a layout pass. requestLayout() should not generally be called during layout,
1924 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
1925 * all children in that container hierarchy are measured and laid out at the end of the layout
1926 * pass for that container). If requestLayout() is called anyway, we handle it correctly
1927 * by registering all requesters during a frame as it proceeds. At the end of the frame,
1928 * we check all of those views to see if any still have pending layout requests, which
1929 * indicates that they were not correctly handled by their container hierarchy. If that is
1930 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
1931 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07001932 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08001933 * requests to the next frame to avoid possible infinite loops.
1934 *
1935 * <p>The return value from this method indicates whether the request should proceed
1936 * (if it is a request during the first layout pass) or should be skipped and posted to the
1937 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07001938 *
1939 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08001940 *
1941 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07001942 */
Chet Haasecc699b42012-12-13 09:06:55 -08001943 boolean requestLayoutDuringLayout(final View view) {
1944 if (view.mParent == null || view.mAttachInfo == null) {
1945 // Would not normally trigger another layout, so just let it pass through as usual
1946 return true;
1947 }
Chet Haase107a4822013-03-13 06:46:50 -07001948 if (!mLayoutRequesters.contains(view)) {
1949 mLayoutRequesters.add(view);
1950 }
Chet Haase97140572012-09-13 14:56:47 -07001951 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07001952 // Let the request proceed normally; it will be processed in a second layout pass
1953 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08001954 return true;
Chet Haase97140572012-09-13 14:56:47 -07001955 } else {
Chet Haase107a4822013-03-13 06:46:50 -07001956 // Don't let the request proceed during the second layout pass.
1957 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08001958 return false;
Chet Haase97140572012-09-13 14:56:47 -07001959 }
1960 }
1961
Chet Haase3efa7b52012-12-03 08:33:17 -08001962 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
1963 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001964 mLayoutRequested = false;
1965 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07001966 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001967
1968 final View host = mView;
1969 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1970 Log.v(TAG, "Laying out " + host + " to (" +
1971 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
1972 }
1973
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001974 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
1975 try {
1976 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08001977
Chet Haased5a83522012-11-21 16:24:44 -08001978 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07001979 int numViewsRequestingLayout = mLayoutRequesters.size();
1980 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08001981 // requestLayout() was called during layout.
1982 // If no layout-request flags are set on the requesting views, there is no problem.
1983 // If some requests are still pending, then we need to clear those flags and do
1984 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07001985 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
1986 false);
1987 if (validLayoutRequesters != null) {
1988 // Set this flag to indicate that any further requests are happening during
1989 // the second pass, which may result in posting those requests to the next
1990 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08001991 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07001992
1993 // Process fresh layout requests, then measure and layout
1994 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08001995 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07001996 final View view = validLayoutRequesters.get(i);
1997 Log.w("View", "requestLayout() improperly called by " + view +
1998 " during layout: running second layout pass");
1999 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002000 }
2001 measureHierarchy(host, lp, mView.getContext().getResources(),
2002 desiredWindowWidth, desiredWindowHeight);
2003 mInLayout = true;
2004 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002005
Chet Haasecc699b42012-12-13 09:06:55 -08002006 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002007
2008 // Check the valid requests again, this time without checking/clearing the
2009 // layout flags, since requests happening during the second pass get noop'd
2010 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2011 if (validLayoutRequesters != null) {
2012 final ArrayList<View> finalRequesters = validLayoutRequesters;
2013 // Post second-pass requests to the next frame
2014 getRunQueue().post(new Runnable() {
2015 @Override
2016 public void run() {
2017 int numValidRequests = finalRequesters.size();
2018 for (int i = 0; i < numValidRequests; ++i) {
2019 final View view = finalRequesters.get(i);
2020 Log.w("View", "requestLayout() improperly called by " + view +
2021 " during second layout pass: posting in next frame");
2022 view.requestLayout();
2023 }
2024 }
2025 });
2026 }
Chet Haasecc699b42012-12-13 09:06:55 -08002027 }
Chet Haase107a4822013-03-13 06:46:50 -07002028
Chet Haase97140572012-09-13 14:56:47 -07002029 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002030 } finally {
2031 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2032 }
Chet Haase97140572012-09-13 14:56:47 -07002033 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002034 }
2035
Chet Haase107a4822013-03-13 06:46:50 -07002036 /**
2037 * This method is called during layout when there have been calls to requestLayout() during
2038 * layout. It walks through the list of views that requested layout to determine which ones
2039 * still need it, based on visibility in the hierarchy and whether they have already been
2040 * handled (as is usually the case with ListView children).
2041 *
2042 * @param layoutRequesters The list of views that requested layout during layout
2043 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2044 * If so, the FORCE_LAYOUT flag was not set on requesters.
2045 * @return A list of the actual views that still need to be laid out.
2046 */
2047 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2048 boolean secondLayoutRequests) {
2049
2050 int numViewsRequestingLayout = layoutRequesters.size();
2051 ArrayList<View> validLayoutRequesters = null;
2052 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2053 View view = layoutRequesters.get(i);
2054 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2055 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2056 View.PFLAG_FORCE_LAYOUT)) {
2057 boolean gone = false;
2058 View parent = view;
2059 // Only trigger new requests for views in a non-GONE hierarchy
2060 while (parent != null) {
2061 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2062 gone = true;
2063 break;
2064 }
2065 if (parent.mParent instanceof View) {
2066 parent = (View) parent.mParent;
2067 } else {
2068 parent = null;
2069 }
2070 }
2071 if (!gone) {
2072 if (validLayoutRequesters == null) {
2073 validLayoutRequesters = new ArrayList<View>();
2074 }
2075 validLayoutRequesters.add(view);
2076 }
2077 }
2078 }
2079 if (!secondLayoutRequests) {
2080 // If we're checking the layout flags, then we need to clean them up also
2081 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2082 View view = layoutRequesters.get(i);
2083 while (view != null &&
2084 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2085 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2086 if (view.mParent instanceof View) {
2087 view = (View) view.mParent;
2088 } else {
2089 view = null;
2090 }
2091 }
2092 }
2093 }
2094 layoutRequesters.clear();
2095 return validLayoutRequesters;
2096 }
2097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 public void requestTransparentRegion(View child) {
2099 // the test below should not fail unless someone is messing with us
2100 checkThread();
2101 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002102 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 // Need to make sure we re-evaluate the window attributes next
2104 // time around, to ensure the window has the correct format.
2105 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002106 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002107 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 }
2109 }
2110
2111 /**
2112 * Figures out the measure spec for the root view in a window based on it's
2113 * layout params.
2114 *
2115 * @param windowSize
2116 * The available width or height of the window
2117 *
2118 * @param rootDimension
2119 * The layout params for one dimension (width or height) of the
2120 * window.
2121 *
2122 * @return The measure spec to use to measure the root view.
2123 */
Romain Guya998dff2012-03-23 18:58:36 -07002124 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 int measureSpec;
2126 switch (rootDimension) {
2127
Romain Guy980a9382010-01-08 15:06:28 -08002128 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 // Window can't resize. Force root view to be windowSize.
2130 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2131 break;
2132 case ViewGroup.LayoutParams.WRAP_CONTENT:
2133 // Window can resize. Set max size for root view.
2134 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2135 break;
2136 default:
2137 // Window wants to be an exact size. Force root view to be that size.
2138 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2139 break;
2140 }
2141 return measureSpec;
2142 }
2143
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002144 int mHardwareYOffset;
2145 int mResizeAlpha;
2146 final Paint mResizePaint = new Paint();
2147
Romain Guy7d70fbf2011-05-24 17:40:25 -07002148 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002149 canvas.translate(0, -mHardwareYOffset);
2150 }
2151
Romain Guy7d70fbf2011-05-24 17:40:25 -07002152 public void onHardwarePostDraw(HardwareCanvas canvas) {
2153 if (mResizeBuffer != null) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002154 mResizePaint.setAlpha(mResizeAlpha);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002155 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002156 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002157 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002158 }
2159
Chet Haaseed30fd82011-04-22 16:18:45 -07002160 /**
2161 * @hide
2162 */
2163 void outputDisplayList(View view) {
2164 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
Chet Haaseed30fd82011-04-22 16:18:45 -07002165 DisplayList displayList = view.getDisplayList();
2166 if (displayList != null) {
Romain Guy59a12ca2011-06-09 17:48:21 -07002167 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
2168 }
2169 }
2170 }
2171
2172 /**
2173 * @see #PROPERTY_PROFILE_RENDERING
2174 */
2175 private void profileRendering(boolean enabled) {
2176 if (mProfileRendering) {
2177 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002178
2179 if (mRenderProfiler != null) {
2180 mChoreographer.removeFrameCallback(mRenderProfiler);
2181 }
2182 if (mRenderProfilingEnabled) {
2183 if (mRenderProfiler == null) {
2184 mRenderProfiler = new Choreographer.FrameCallback() {
2185 @Override
2186 public void doFrame(long frameTimeNanos) {
2187 mDirty.set(0, 0, mWidth, mHeight);
2188 scheduleTraversals();
2189 if (mRenderProfilingEnabled) {
2190 mChoreographer.postFrameCallback(mRenderProfiler);
2191 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002192 }
Chris Craikae4f32042013-02-07 12:57:10 -08002193 };
2194 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002195 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002196 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002197 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002198 }
2199 }
2200 }
2201
Chet Haase2f2022a2011-10-11 06:41:59 -07002202 /**
2203 * Called from draw() when DEBUG_FPS is enabled
2204 */
2205 private void trackFPS() {
2206 // Tracks frames per second drawn. First value in a series of draws may be bogus
2207 // because it down not account for the intervening idle time
2208 long nowTime = System.currentTimeMillis();
2209 if (mFpsStartTime < 0) {
2210 mFpsStartTime = mFpsPrevTime = nowTime;
2211 mFpsNumFrames = 0;
2212 } else {
2213 ++mFpsNumFrames;
2214 String thisHash = Integer.toHexString(System.identityHashCode(this));
2215 long frameTime = nowTime - mFpsPrevTime;
2216 long totalTime = nowTime - mFpsStartTime;
2217 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2218 mFpsPrevTime = nowTime;
2219 if (totalTime > 1000) {
2220 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2221 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2222 mFpsStartTime = nowTime;
2223 mFpsNumFrames = 0;
2224 }
2225 }
2226 }
2227
Jeff Brown96e942d2011-11-30 19:55:01 -08002228 private void performDraw() {
Craig Mautner006f0e42012-03-21 11:00:32 -07002229 if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2230 return;
2231 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002232
Jeff Brown96e942d2011-11-30 19:55:01 -08002233 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2234 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002235
Romain Guy1f59e5c2012-05-06 14:11:16 -07002236 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002237 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2238 try {
2239 draw(fullRedrawNeeded);
2240 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002241 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002242 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2243 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002244
Jeff Brown96e942d2011-11-30 19:55:01 -08002245 if (mReportNextDraw) {
2246 mReportNextDraw = false;
2247
2248 if (LOCAL_LOGV) {
2249 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2250 }
2251 if (mSurfaceHolder != null && mSurface.isValid()) {
2252 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2253 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2254 if (callbacks != null) {
2255 for (SurfaceHolder.Callback c : callbacks) {
2256 if (c instanceof SurfaceHolder.Callback2) {
2257 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2258 mSurfaceHolder);
2259 }
2260 }
2261 }
2262 }
2263 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002264 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002265 } catch (RemoteException e) {
2266 }
2267 }
2268 }
2269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 private void draw(boolean fullRedrawNeeded) {
2271 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002272 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273 return;
2274 }
2275
Chet Haase2f2022a2011-10-11 06:41:59 -07002276 if (DEBUG_FPS) {
2277 trackFPS();
2278 }
2279
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002280 if (!sFirstDrawComplete) {
2281 synchronized (sFirstDrawHandlers) {
2282 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002283 final int count = sFirstDrawHandlers.size();
2284 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002285 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002286 }
2287 }
2288 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 scrollToRectOrFocus(null, false);
2291
Romain Guy25eba5c2012-04-04 17:29:03 -07002292 final AttachInfo attachInfo = mAttachInfo;
2293 if (attachInfo.mViewScrollChanged) {
2294 attachInfo.mViewScrollChanged = false;
2295 attachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002296 }
Romain Guy8506ab42009-06-11 17:35:47 -07002297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002299 boolean animating = mScroller != null && mScroller.computeScrollOffset();
2300 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002301 yoff = mScroller.getCurrY();
2302 } else {
2303 yoff = mScrollY;
2304 }
2305 if (mCurScrollY != yoff) {
2306 mCurScrollY = yoff;
2307 fullRedrawNeeded = true;
2308 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002309
Romain Guy25eba5c2012-04-04 17:29:03 -07002310 final float appScale = attachInfo.mApplicationScale;
2311 final boolean scalingRequired = attachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002313 int resizeAlpha = 0;
Romain Guy7d70fbf2011-05-24 17:40:25 -07002314 if (mResizeBuffer != null) {
2315 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2316 if (deltaTime < mResizeBufferDuration) {
2317 float amt = deltaTime/(float) mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002318 amt = mResizeInterpolator.getInterpolation(amt);
2319 animating = true;
2320 resizeAlpha = 255 - (int)(amt*255);
2321 } else {
Romain Guy7d70fbf2011-05-24 17:40:25 -07002322 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002323 }
2324 }
2325
Jeff Brown96e942d2011-11-30 19:55:01 -08002326 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002327 if (mSurfaceHolder != null) {
2328 // The app owns the surface, we won't draw.
2329 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002330 if (animating) {
2331 if (mScroller != null) {
2332 mScroller.abortAnimation();
2333 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07002334 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002335 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002336 return;
2337 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002338
2339 if (fullRedrawNeeded) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002340 attachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002341 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002342 }
Chet Haasead4f7032011-06-22 09:18:31 -07002343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002345 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002346 + mWindowAttributes.getTitle()
2347 + ": dirty={" + dirty.left + "," + dirty.top
2348 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002349 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2350 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002351 }
2352
Romain Guyfbb93fa2012-12-03 18:50:35 -08002353 invalidateDisplayLists();
2354
Romain Guy25eba5c2012-04-04 17:29:03 -07002355 attachInfo.mTreeObserver.dispatchOnDraw();
2356
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002357 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002358 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002359 // Draw with hardware renderer.
2360 mIsAnimating = false;
2361 mHardwareYOffset = yoff;
2362 mResizeAlpha = resizeAlpha;
Romain Guyfea12b82011-01-27 15:36:40 -08002363
Jeff Brown96e942d2011-11-30 19:55:01 -08002364 mCurrentDirty.set(dirty);
Jeff Brown96e942d2011-11-30 19:55:01 -08002365 dirty.setEmpty();
2366
Romain Guye55945e2013-04-04 15:26:04 -07002367 attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
2368 animating ? null : mCurrentDirty);
Romain Guy3696779b2013-01-28 14:04:07 -08002369 } else {
2370 // If we get here with a disabled & requested hardware renderer, something went
2371 // wrong (an invalidate posted right before we destroyed the hardware surface
2372 // for instance) so we should just bail out. Locking the surface with software
2373 // rendering at this point would lock it forever and prevent hardware renderer
2374 // from doing its job when it comes back.
2375 // Before we request a new frame we must however attempt to reinitiliaze the
2376 // hardware renderer if it's in requested state. This would happen after an
2377 // eglTerminate() for instance.
2378 if (attachInfo.mHardwareRenderer != null &&
2379 !attachInfo.mHardwareRenderer.isEnabled() &&
2380 attachInfo.mHardwareRenderer.isRequested()) {
2381
2382 try {
2383 attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
2384 mHolder.getSurface());
2385 } catch (Surface.OutOfResourcesException e) {
2386 handleOutOfResourcesException(e);
2387 return;
2388 }
2389
2390 mFullRedrawNeeded = true;
2391 scheduleTraversals();
2392 return;
2393 }
2394
2395 if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2396 return;
2397 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 }
Romain Guy8506ab42009-06-11 17:35:47 -07002400
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002401 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002402 mFullRedrawNeeded = true;
2403 scheduleTraversals();
2404 }
2405 }
2406
Romain Guy25eba5c2012-04-04 17:29:03 -07002407 /**
Romain Guyedbca122012-04-04 18:25:53 -07002408 * @return true if drawing was succesfull, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002409 */
2410 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2411 boolean scalingRequired, Rect dirty) {
2412
2413 // Draw with software renderer.
2414 Canvas canvas;
2415 try {
2416 int left = dirty.left;
2417 int top = dirty.top;
2418 int right = dirty.right;
2419 int bottom = dirty.bottom;
2420
Romain Guy25eba5c2012-04-04 17:29:03 -07002421 canvas = mSurface.lockCanvas(dirty);
2422
Romain Guye55945e2013-04-04 15:26:04 -07002423 // The dirty rectangle can be modified by Surface.lockCanvas()
2424 //noinspection ConstantConditions
Romain Guy25eba5c2012-04-04 17:29:03 -07002425 if (left != dirty.left || top != dirty.top || right != dirty.right ||
2426 bottom != dirty.bottom) {
2427 attachInfo.mIgnoreDirtyState = true;
2428 }
2429
2430 // TODO: Do this in native
2431 canvas.setDensity(mDensity);
2432 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002433 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002434 return false;
2435 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002436 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002437 // Don't assume this is due to out of memory, it could be
2438 // something else, and if it is something else then we could
2439 // kill stuff (or ourself) for no reason.
2440 mLayoutRequested = true; // ask wm for a new surface next time.
2441 return false;
2442 }
2443
2444 try {
2445 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2446 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2447 + canvas.getWidth() + ", h=" + canvas.getHeight());
2448 //canvas.drawARGB(255, 255, 0, 0);
2449 }
2450
Romain Guy25eba5c2012-04-04 17:29:03 -07002451 // If this bitmap's format includes an alpha channel, we
2452 // need to clear it before drawing so that the child will
2453 // properly re-composite its drawing on a transparent
2454 // background. This automatically respects the clip/dirty region
2455 // or
2456 // If we are applying an offset, we need to clear the area
2457 // where the offset doesn't appear to avoid having garbage
2458 // left in the blank areas.
2459 if (!canvas.isOpaque() || yoff != 0) {
2460 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2461 }
2462
2463 dirty.setEmpty();
2464 mIsAnimating = false;
2465 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002466 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002467
2468 if (DEBUG_DRAW) {
2469 Context cxt = mView.getContext();
2470 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2471 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2472 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2473 }
2474 try {
2475 canvas.translate(0, -yoff);
2476 if (mTranslator != null) {
2477 mTranslator.translateCanvas(canvas);
2478 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002479 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002480 attachInfo.mSetIgnoreDirtyState = false;
2481
Romain Guy25eba5c2012-04-04 17:29:03 -07002482 mView.draw(canvas);
2483
Svetoslav Ganov42138042012-03-20 11:51:39 -07002484 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002485 } finally {
2486 if (!attachInfo.mSetIgnoreDirtyState) {
2487 // Only clear the flag if it was not set during the mView.draw() call
2488 attachInfo.mIgnoreDirtyState = false;
2489 }
2490 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002491 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002492 try {
2493 surface.unlockCanvasAndPost(canvas);
2494 } catch (IllegalArgumentException e) {
2495 Log.e(TAG, "Could not unlock surface", e);
2496 mLayoutRequested = true; // ask wm for a new surface next time.
2497 //noinspection ReturnInsideFinallyBlock
2498 return false;
2499 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002500
Romain Guy25eba5c2012-04-04 17:29:03 -07002501 if (LOCAL_LOGV) {
2502 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2503 }
2504 }
2505 return true;
2506 }
2507
Svetoslav Ganov42138042012-03-20 11:51:39 -07002508 /**
2509 * We want to draw a highlight around the current accessibility focused.
2510 * Since adding a style for all possible view is not a viable option we
2511 * have this specialized drawing method.
2512 *
2513 * Note: We are doing this here to be able to draw the highlight for
2514 * virtual views in addition to real ones.
2515 *
2516 * @param canvas The canvas on which to draw.
2517 */
2518 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
Svetoslav Ganov07b726c2012-04-30 12:24:57 -07002519 AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2520 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002521 return;
2522 }
2523 if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
2524 return;
2525 }
2526 Drawable drawable = getAccessibilityFocusedDrawable();
2527 if (drawable == null) {
2528 return;
2529 }
2530 AccessibilityNodeProvider provider =
2531 mAccessibilityFocusedHost.getAccessibilityNodeProvider();
2532 Rect bounds = mView.mAttachInfo.mTmpInvalRect;
2533 if (provider == null) {
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002534 mAccessibilityFocusedHost.getBoundsOnScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002535 } else {
2536 if (mAccessibilityFocusedVirtualView == null) {
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07002537 return;
2538 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002539 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002540 }
Svetoslav Ganov78bd9832012-10-15 19:12:29 -07002541 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Svetoslav Ganova94c3192012-10-31 18:28:49 -07002542 bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002543 drawable.setBounds(bounds);
2544 drawable.draw(canvas);
2545 }
2546
2547 private Drawable getAccessibilityFocusedDrawable() {
2548 if (mAttachInfo != null) {
2549 // Lazily load the accessibility focus drawable.
2550 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2551 TypedValue value = new TypedValue();
2552 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2553 R.attr.accessibilityFocusedDrawable, value, true);
2554 if (resolved) {
2555 mAttachInfo.mAccessibilityFocusDrawable =
2556 mView.mContext.getResources().getDrawable(value.resourceId);
2557 }
2558 }
2559 return mAttachInfo.mAccessibilityFocusDrawable;
2560 }
2561 return null;
2562 }
2563
Romain Guy51e4d4d2012-03-15 18:30:47 -07002564 void invalidateDisplayLists() {
2565 final ArrayList<DisplayList> displayLists = mDisplayLists;
2566 final int count = displayLists.size();
2567
2568 for (int i = 0; i < count; i++) {
Romain Guy38c2ece2012-05-24 14:20:56 -07002569 final DisplayList displayList = displayLists.get(i);
Romain Guyfbb93fa2012-12-03 18:50:35 -08002570 if (displayList.isDirty()) {
Romain Guyfbb93fa2012-12-03 18:50:35 -08002571 displayList.clear();
Romain Guyfbb93fa2012-12-03 18:50:35 -08002572 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07002573 }
2574
2575 displayLists.clear();
2576 }
2577
Michael Jurkaf42d90102013-05-08 18:00:04 +02002578 /**
2579 * @hide
2580 */
2581 public void setDrawDuringWindowsAnimating(boolean value) {
2582 mDrawDuringWindowsAnimating = value;
2583 if (value) {
2584 handleDispatchDoneAnimating();
2585 }
2586 }
2587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2589 final View.AttachInfo attachInfo = mAttachInfo;
2590 final Rect ci = attachInfo.mContentInsets;
2591 final Rect vi = attachInfo.mVisibleInsets;
2592 int scrollY = 0;
2593 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 if (vi.left > ci.left || vi.top > ci.top
2596 || vi.right > ci.right || vi.bottom > ci.bottom) {
2597 // We'll assume that we aren't going to change the scroll
2598 // offset, since we want to avoid that unless it is actually
2599 // going to make the focus visible... otherwise we scroll
2600 // all over the place.
2601 scrollY = mScrollY;
2602 // We can be called for two different situations: during a draw,
2603 // to update the scroll position if the focus has changed (in which
2604 // case 'rectangle' is null), or in response to a
2605 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2606 // is non-null and we just want to scroll to whatever that
2607 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002608 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002609 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002610 return false;
2611 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002612 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002613 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002614 // If the focus has changed, then ignore any requests to scroll
2615 // to a rectangle; first we want to make sure the entire focus
2616 // view is visible.
2617 rectangle = null;
2618 }
2619 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2620 + " rectangle=" + rectangle + " ci=" + ci
2621 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002622 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 // Optimization: if the focus hasn't changed since last
2624 // time, and no layout has happened, then just leave things
2625 // as they are.
2626 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2627 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002628 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 // We need to determine if the currently focused view is
2630 // within the visible part of the window and, if not, apply
2631 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002632 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 mScrollMayChange = false;
2634 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2635 // Try to find the rectangle from the focus view.
2636 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2637 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2638 + mView.getWidth() + " h=" + mView.getHeight()
2639 + " ci=" + ci.toShortString()
2640 + " vi=" + vi.toShortString());
2641 if (rectangle == null) {
2642 focus.getFocusedRect(mTempRect);
2643 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2644 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002645 if (mView instanceof ViewGroup) {
2646 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2647 focus, mTempRect);
2648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002649 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2650 "Focus in window: focusRect="
2651 + mTempRect.toShortString()
2652 + " visRect=" + mVisRect.toShortString());
2653 } else {
2654 mTempRect.set(rectangle);
2655 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2656 "Request scroll to rect: "
2657 + mTempRect.toShortString()
2658 + " visRect=" + mVisRect.toShortString());
2659 }
2660 if (mTempRect.intersect(mVisRect)) {
2661 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2662 "Focus window visible rect: "
2663 + mTempRect.toShortString());
2664 if (mTempRect.height() >
2665 (mView.getHeight()-vi.top-vi.bottom)) {
2666 // If the focus simply is not going to fit, then
2667 // best is probably just to leave things as-is.
2668 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2669 "Too tall; leaving scrollY=" + scrollY);
2670 } else if ((mTempRect.top-scrollY) < vi.top) {
2671 scrollY -= vi.top - (mTempRect.top-scrollY);
2672 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2673 "Top covered; scrollY=" + scrollY);
2674 } else if ((mTempRect.bottom-scrollY)
2675 > (mView.getHeight()-vi.bottom)) {
2676 scrollY += (mTempRect.bottom-scrollY)
2677 - (mView.getHeight()-vi.bottom);
2678 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2679 "Bottom covered; scrollY=" + scrollY);
2680 }
2681 handled = true;
2682 }
2683 }
2684 }
2685 }
Romain Guy8506ab42009-06-11 17:35:47 -07002686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 if (scrollY != mScrollY) {
2688 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2689 + mScrollY + " , new=" + scrollY);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002690 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 if (mScroller == null) {
2692 mScroller = new Scroller(mView.getContext());
2693 }
2694 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2695 } else if (mScroller != null) {
2696 mScroller.abortAnimation();
2697 }
2698 mScrollY = scrollY;
2699 }
Romain Guy8506ab42009-06-11 17:35:47 -07002700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 return handled;
2702 }
Romain Guy8506ab42009-06-11 17:35:47 -07002703
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002704 /**
2705 * @hide
2706 */
2707 public View getAccessibilityFocusedHost() {
2708 return mAccessibilityFocusedHost;
2709 }
2710
2711 /**
2712 * @hide
2713 */
2714 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2715 return mAccessibilityFocusedVirtualView;
2716 }
2717
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002718 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002719 // If we have a virtual view with accessibility focus we need
2720 // to clear the focus and invalidate the virtual view bounds.
2721 if (mAccessibilityFocusedVirtualView != null) {
2722
2723 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2724 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002725
2726 // Wipe the state of the current accessibility focus since
2727 // the call into the provider to clear accessibility focus
2728 // will fire an accessibility event which will end up calling
2729 // this method and we want to have clean state when this
2730 // invocation happens.
2731 mAccessibilityFocusedHost = null;
2732 mAccessibilityFocusedVirtualView = null;
2733
Alan Viverette239a0c02013-05-07 17:17:35 -07002734 // Clear accessibility focus on the host after clearing state since
2735 // this method may be reentrant.
2736 focusHost.clearAccessibilityFocusNoCallbacks();
2737
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002738 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2739 if (provider != null) {
2740 // Invalidate the area of the cleared accessibility focus.
2741 focusNode.getBoundsInParent(mTempRect);
2742 focusHost.invalidate(mTempRect);
2743 // Clear accessibility focus in the virtual node.
2744 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2745 focusNode.getSourceNodeId());
2746 provider.performAction(virtualNodeId,
2747 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2748 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002749 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002750 }
2751 if (mAccessibilityFocusedHost != null) {
2752 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002753 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2754 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002755
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002756 // Set the new focus host and node.
2757 mAccessibilityFocusedHost = view;
2758 mAccessibilityFocusedVirtualView = node;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002759 }
2760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002761 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002762 if (DEBUG_INPUT_RESIZE) {
2763 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002764 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002765 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002766 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 }
2768
2769 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002770 if (DEBUG_INPUT_RESIZE) {
2771 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002772 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002773 checkThread();
2774 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002775 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002776
Svetoslav Ganov42138042012-03-20 11:51:39 -07002777 @Override
2778 public ViewParent getParentForAccessibility() {
2779 return null;
2780 }
2781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 public void focusableViewAvailable(View v) {
2783 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002784 if (mView != null) {
2785 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002787 } else {
2788 // the one case where will transfer focus away from the current one
2789 // is if the current view is a view group that prefers to give focus
2790 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002791 View focused = mView.findFocus();
2792 if (focused instanceof ViewGroup) {
2793 ViewGroup group = (ViewGroup) focused;
2794 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2795 && isViewDescendantOf(v, focused)) {
2796 v.requestFocus();
2797 }
Romain Guy1c90f032011-05-24 14:59:50 -07002798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 }
2800 }
2801 }
2802
2803 public void recomputeViewAttributes(View child) {
2804 checkThread();
2805 if (mView == child) {
2806 mAttachInfo.mRecomputeGlobalAttributes = true;
2807 if (!mWillDrawSoon) {
2808 scheduleTraversals();
2809 }
2810 }
2811 }
2812
2813 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002814 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002815 if (mAttachInfo.mHardwareRenderer != null &&
2816 mAttachInfo.mHardwareRenderer.isEnabled()) {
2817 mAttachInfo.mHardwareRenderer.validate();
2818 }
Dianne Hackborn961cae92013-03-20 14:59:43 -07002819 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820 mView.dispatchDetachedFromWindow();
2821 }
2822
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002823 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2824 mAccessibilityManager.removeAccessibilityStateChangeListener(
2825 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002826 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002827
Romain Guya998dff2012-03-23 18:58:36 -07002828 destroyHardwareRenderer();
2829
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002830 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002831
Romain Guyb7e0f792013-06-07 15:36:49 -07002832 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 mView = null;
2834 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07002835 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002837 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002838
Jeff Browncc4f7db2011-08-30 20:34:48 -07002839 if (mInputQueueCallback != null && mInputQueue != null) {
2840 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002841 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002842 mInputQueueCallback = null;
2843 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002844 }
2845 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002846 mInputEventReceiver.dispose();
2847 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002850 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 } catch (RemoteException e) {
2852 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07002853
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002854 // Dispose the input channel after removing the window so the Window Manager
2855 // doesn't interpret the input channel being closed as an abnormal termination.
2856 if (mInputChannel != null) {
2857 mInputChannel.dispose();
2858 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002859 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002860
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002861 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 }
Romain Guy8506ab42009-06-11 17:35:47 -07002863
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002864 void updateConfiguration(Configuration config, boolean force) {
2865 if (DEBUG_CONFIGURATION) Log.v(TAG,
2866 "Applying new config to window "
2867 + mWindowAttributes.getTitle()
2868 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002869
2870 CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
2871 if (ci != null) {
2872 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002873 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002874 }
2875
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002876 synchronized (sConfigCallbacks) {
2877 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2878 sConfigCallbacks.get(i).onConfigurationChanged(config);
2879 }
2880 }
2881 if (mView != null) {
2882 // At this point the resources have been updated to
2883 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002884 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002885 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002886 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002887 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2888 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002889 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07002890 if (lastLayoutDirection != currentLayoutDirection &&
2891 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002892 mView.setLayoutDirection(currentLayoutDirection);
2893 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002894 mView.dispatchConfigurationChanged(config);
2895 }
2896 }
2897 }
2898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002899 /**
2900 * Return true if child is an ancestor of parent, (or equal to the parent).
2901 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002902 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002903 if (child == parent) {
2904 return true;
2905 }
2906
2907 final ViewParent theParent = child.getParent();
2908 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2909 }
2910
Romain Guycdb86672010-03-18 18:54:50 -07002911 private static void forceLayout(View view) {
2912 view.forceLayout();
2913 if (view instanceof ViewGroup) {
2914 ViewGroup group = (ViewGroup) view;
2915 final int count = group.getChildCount();
2916 for (int i = 0; i < count; i++) {
2917 forceLayout(group.getChildAt(i));
2918 }
2919 }
2920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921
Jeff Browna175a5b2012-02-15 19:18:31 -08002922 private final static int MSG_INVALIDATE = 1;
2923 private final static int MSG_INVALIDATE_RECT = 2;
2924 private final static int MSG_DIE = 3;
2925 private final static int MSG_RESIZED = 4;
2926 private final static int MSG_RESIZED_REPORT = 5;
2927 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
2928 private final static int MSG_DISPATCH_KEY = 7;
2929 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2930 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08002931 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2932 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2933 private final static int MSG_CHECK_FOCUS = 13;
2934 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2935 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2936 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2937 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2938 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002939 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2940 private final static int MSG_DISPATCH_SCREEN_STATE = 20;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002941 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
2942 private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
2943 private final static int MSG_INVALIDATE_WORLD = 23;
2944 private final static int MSG_WINDOW_MOVED = 24;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945
Jeff Browna175a5b2012-02-15 19:18:31 -08002946 final class ViewRootHandler extends Handler {
2947 @Override
2948 public String getMessageName(Message message) {
2949 switch (message.what) {
2950 case MSG_INVALIDATE:
2951 return "MSG_INVALIDATE";
2952 case MSG_INVALIDATE_RECT:
2953 return "MSG_INVALIDATE_RECT";
2954 case MSG_DIE:
2955 return "MSG_DIE";
2956 case MSG_RESIZED:
2957 return "MSG_RESIZED";
2958 case MSG_RESIZED_REPORT:
2959 return "MSG_RESIZED_REPORT";
2960 case MSG_WINDOW_FOCUS_CHANGED:
2961 return "MSG_WINDOW_FOCUS_CHANGED";
2962 case MSG_DISPATCH_KEY:
2963 return "MSG_DISPATCH_KEY";
2964 case MSG_DISPATCH_APP_VISIBILITY:
2965 return "MSG_DISPATCH_APP_VISIBILITY";
2966 case MSG_DISPATCH_GET_NEW_SURFACE:
2967 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08002968 case MSG_DISPATCH_KEY_FROM_IME:
2969 return "MSG_DISPATCH_KEY_FROM_IME";
2970 case MSG_FINISH_INPUT_CONNECTION:
2971 return "MSG_FINISH_INPUT_CONNECTION";
2972 case MSG_CHECK_FOCUS:
2973 return "MSG_CHECK_FOCUS";
2974 case MSG_CLOSE_SYSTEM_DIALOGS:
2975 return "MSG_CLOSE_SYSTEM_DIALOGS";
2976 case MSG_DISPATCH_DRAG_EVENT:
2977 return "MSG_DISPATCH_DRAG_EVENT";
2978 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
2979 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
2980 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
2981 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
2982 case MSG_UPDATE_CONFIGURATION:
2983 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08002984 case MSG_PROCESS_INPUT_EVENTS:
2985 return "MSG_PROCESS_INPUT_EVENTS";
Romain Guy51e4d4d2012-03-15 18:30:47 -07002986 case MSG_DISPATCH_SCREEN_STATE:
2987 return "MSG_DISPATCH_SCREEN_STATE";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07002988 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
2989 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07002990 case MSG_DISPATCH_DONE_ANIMATING:
2991 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07002992 case MSG_WINDOW_MOVED:
2993 return "MSG_WINDOW_MOVED";
Jeff Browna175a5b2012-02-15 19:18:31 -08002994 }
2995 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07002996 }
Romain Guyf9284692011-07-13 18:46:21 -07002997
Jeff Browna175a5b2012-02-15 19:18:31 -08002998 @Override
2999 public void handleMessage(Message msg) {
3000 switch (msg.what) {
3001 case MSG_INVALIDATE:
3002 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003004 case MSG_INVALIDATE_RECT:
3005 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3006 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003007 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003008 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003009 case MSG_PROCESS_INPUT_EVENTS:
3010 mProcessInputEventsScheduled = false;
3011 doProcessInputEvents();
3012 break;
3013 case MSG_DISPATCH_APP_VISIBILITY:
3014 handleAppVisibility(msg.arg1 != 0);
3015 break;
3016 case MSG_DISPATCH_GET_NEW_SURFACE:
3017 handleGetNewSurface();
3018 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003019 case MSG_RESIZED: {
3020 // Recycled in the fall through...
3021 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003022 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003023 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003024 && mPendingContentInsets.equals(args.arg2)
3025 && mPendingVisibleInsets.equals(args.arg3)
3026 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003027 break;
Romain Guycdb86672010-03-18 18:54:50 -07003028 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003029 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003030 case MSG_RESIZED_REPORT:
3031 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003032 SomeArgs args = (SomeArgs) msg.obj;
3033
3034 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003035 if (config != null) {
3036 updateConfiguration(config, false);
3037 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003038
3039 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003040 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003041 mPendingContentInsets.set((Rect) args.arg2);
3042 mPendingVisibleInsets.set((Rect) args.arg3);
3043
3044 args.recycle();
3045
Jeff Browna175a5b2012-02-15 19:18:31 -08003046 if (msg.what == MSG_RESIZED_REPORT) {
3047 mReportNextDraw = true;
3048 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003049
Jeff Browna175a5b2012-02-15 19:18:31 -08003050 if (mView != null) {
3051 forceLayout(mView);
3052 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003053
Jeff Browna175a5b2012-02-15 19:18:31 -08003054 requestLayout();
3055 }
3056 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003057 case MSG_WINDOW_MOVED:
3058 if (mAdded) {
3059 final int w = mWinFrame.width();
3060 final int h = mWinFrame.height();
3061 final int l = msg.arg1;
3062 final int t = msg.arg2;
3063 mWinFrame.left = l;
3064 mWinFrame.right = l + w;
3065 mWinFrame.top = t;
3066 mWinFrame.bottom = t + h;
3067
3068 if (mView != null) {
3069 forceLayout(mView);
3070 }
3071 requestLayout();
3072 }
3073 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003074 case MSG_WINDOW_FOCUS_CHANGED: {
3075 if (mAdded) {
3076 boolean hasWindowFocus = msg.arg1 != 0;
3077 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003078
Jeff Browna175a5b2012-02-15 19:18:31 -08003079 profileRendering(hasWindowFocus);
3080
3081 if (hasWindowFocus) {
3082 boolean inTouchMode = msg.arg2 != 0;
3083 ensureTouchModeLocally(inTouchMode);
3084
Romain Guye55945e2013-04-04 15:26:04 -07003085 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003086 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003087 try {
Romain Guy3696779b2013-01-28 14:04:07 -08003088 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
3089 mWidth, mHeight, mHolder.getSurface());
Jeff Browna175a5b2012-02-15 19:18:31 -08003090 } catch (Surface.OutOfResourcesException e) {
3091 Log.e(TAG, "OutOfResourcesException locking surface", e);
3092 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003093 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003094 Slog.w(TAG, "No processes killed for memory; killing self");
3095 Process.killProcess(Process.myPid());
3096 }
3097 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003098 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003099 // Retry in a bit.
3100 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3101 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003102 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 }
Romain Guy8506ab42009-06-11 17:35:47 -07003105
Jeff Browna175a5b2012-02-15 19:18:31 -08003106 mLastWasImTarget = WindowManager.LayoutParams
3107 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003108
Jeff Browna175a5b2012-02-15 19:18:31 -08003109 InputMethodManager imm = InputMethodManager.peekInstance();
3110 if (mView != null) {
3111 if (hasWindowFocus && imm != null && mLastWasImTarget) {
3112 imm.startGettingWindowFocus(mView);
3113 }
3114 mAttachInfo.mKeyDispatchState.reset();
3115 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003116 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003118
Jeff Browna175a5b2012-02-15 19:18:31 -08003119 // Note: must be done after the focus change callbacks,
3120 // so all of the view state is set up correctly.
3121 if (hasWindowFocus) {
3122 if (imm != null && mLastWasImTarget) {
3123 imm.onWindowFocus(mView, mView.findFocus(),
3124 mWindowAttributes.softInputMode,
3125 !mHasHadWindowFocus, mWindowAttributes.flags);
3126 }
3127 // Clear the forward bit. We can just do this directly, since
3128 // the window manager doesn't care about it.
3129 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003131 ((WindowManager.LayoutParams)mView.getLayoutParams())
3132 .softInputMode &=
3133 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3134 mHasHadWindowFocus = true;
3135 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003136
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003137 setAccessibilityFocus(null, null);
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07003138
Svetoslav Ganov42138042012-03-20 11:51:39 -07003139 if (mView != null && mAccessibilityManager.isEnabled()) {
3140 if (hasWindowFocus) {
3141 mView.sendAccessibilityEvent(
3142 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003143 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003144 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003145 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003146 } break;
3147 case MSG_DIE:
3148 doDie();
3149 break;
3150 case MSG_DISPATCH_KEY: {
3151 KeyEvent event = (KeyEvent)msg.obj;
3152 enqueueInputEvent(event, null, 0, true);
3153 } break;
3154 case MSG_DISPATCH_KEY_FROM_IME: {
3155 if (LOCAL_LOGV) Log.v(
3156 TAG, "Dispatching key "
3157 + msg.obj + " from IME to " + mView);
3158 KeyEvent event = (KeyEvent)msg.obj;
3159 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3160 // The IME is trying to say this event is from the
3161 // system! Bad bad bad!
3162 //noinspection UnusedAssignment
3163 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
3164 }
3165 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3166 } break;
3167 case MSG_FINISH_INPUT_CONNECTION: {
3168 InputMethodManager imm = InputMethodManager.peekInstance();
3169 if (imm != null) {
3170 imm.reportFinishInputConnection((InputConnection)msg.obj);
3171 }
3172 } break;
3173 case MSG_CHECK_FOCUS: {
3174 InputMethodManager imm = InputMethodManager.peekInstance();
3175 if (imm != null) {
3176 imm.checkFocus();
3177 }
3178 } break;
3179 case MSG_CLOSE_SYSTEM_DIALOGS: {
3180 if (mView != null) {
3181 mView.onCloseSystemDialogs((String)msg.obj);
3182 }
3183 } break;
3184 case MSG_DISPATCH_DRAG_EVENT:
3185 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3186 DragEvent event = (DragEvent)msg.obj;
3187 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3188 handleDragEvent(event);
3189 } break;
3190 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003191 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003192 } break;
3193 case MSG_UPDATE_CONFIGURATION: {
3194 Configuration config = (Configuration)msg.obj;
3195 if (config.isOtherSeqNewer(mLastConfiguration)) {
3196 config = mLastConfiguration;
3197 }
3198 updateConfiguration(config, false);
3199 } break;
Romain Guybb9908b2012-03-08 11:14:07 -08003200 case MSG_DISPATCH_SCREEN_STATE: {
Romain Guy7e4e5612012-03-05 14:37:29 -08003201 if (mView != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08003202 handleScreenStateChange(msg.arg1 == 1);
Romain Guy7e4e5612012-03-05 14:37:29 -08003203 }
3204 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003205 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003206 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003207 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003208 case MSG_DISPATCH_DONE_ANIMATING: {
3209 handleDispatchDoneAnimating();
3210 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003211 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003212 if (mView != null) {
3213 invalidateWorld(mView);
3214 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003215 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 }
3218 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003219
Jeff Browna175a5b2012-02-15 19:18:31 -08003220 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 /**
3223 * Something in the current window tells us we need to change the touch mode. For
3224 * example, we are not in touch mode, and the user touches the screen.
3225 *
3226 * If the touch mode has changed, tell the window manager, and handle it locally.
3227 *
3228 * @param inTouchMode Whether we want to be in touch mode.
3229 * @return True if the touch mode changed and focus changed was changed as a result
3230 */
3231 boolean ensureTouchMode(boolean inTouchMode) {
3232 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3233 + "touch mode is " + mAttachInfo.mInTouchMode);
3234 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3235
3236 // tell the window manager
3237 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003238 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 } catch (RemoteException e) {
3240 throw new RuntimeException(e);
3241 }
3242
3243 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003244 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 }
3246
3247 /**
3248 * Ensure that the touch mode for this window is set, and if it is changing,
3249 * take the appropriate action.
3250 * @param inTouchMode Whether we want to be in touch mode.
3251 * @return True if the touch mode changed and focus changed was changed as a result
3252 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003253 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3255 + "touch mode is " + mAttachInfo.mInTouchMode);
3256
3257 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3258
3259 mAttachInfo.mInTouchMode = inTouchMode;
3260 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3261
Romain Guy2d4cff62010-04-09 15:39:00 -07003262 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003263 }
3264
3265 private boolean enterTouchMode() {
3266 if (mView != null) {
3267 if (mView.hasFocus()) {
3268 // note: not relying on mFocusedView here because this could
3269 // be when the window is first being added, and mFocused isn't
3270 // set yet.
3271 final View focused = mView.findFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003272 if (focused != null && !focused.isFocusableInTouchMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 final ViewGroup ancestorToTakeFocus =
3274 findAncestorToTakeFocusInTouchMode(focused);
3275 if (ancestorToTakeFocus != null) {
3276 // there is an ancestor that wants focus after its descendants that
3277 // is focusable in touch mode.. give it focus
3278 return ancestorToTakeFocus.requestFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003279 } else {
3280 // nothing appropriate to have focus in touch mode, clear it out
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003281 focused.unFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003282 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 }
3284 }
3285 }
3286 }
3287 return false;
3288 }
3289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 /**
3291 * Find an ancestor of focused that wants focus after its descendants and is
3292 * focusable in touch mode.
3293 * @param focused The currently focused view.
3294 * @return An appropriate view, or null if no such view exists.
3295 */
Romain Guya998dff2012-03-23 18:58:36 -07003296 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 ViewParent parent = focused.getParent();
3298 while (parent instanceof ViewGroup) {
3299 final ViewGroup vgParent = (ViewGroup) parent;
3300 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3301 && vgParent.isFocusableInTouchMode()) {
3302 return vgParent;
3303 }
3304 if (vgParent.isRootNamespace()) {
3305 return null;
3306 } else {
3307 parent = vgParent.getParent();
3308 }
3309 }
3310 return null;
3311 }
3312
3313 private boolean leaveTouchMode() {
3314 if (mView != null) {
3315 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003316 View focusedView = mView.findFocus();
3317 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003319 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003320 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3322 // some view group has focus, and doesn't prefer its children
3323 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003324 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 }
3326 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003327
3328 // find the best view to give focus to in this brave new non-touch-mode
3329 // world
3330 final View focused = focusSearch(null, View.FOCUS_DOWN);
3331 if (focused != null) {
3332 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 }
3334 }
3335 return false;
3336 }
3337
Jeff Brownf9e989d2013-04-04 23:04:03 -07003338 /**
3339 * Base class for implementing a stage in the chain of responsibility
3340 * for processing input events.
3341 * <p>
3342 * Events are delivered to the stage by the {@link #deliver} method. The stage
3343 * then has the choice of finishing the event or forwarding it to the next stage.
3344 * </p>
3345 */
3346 abstract class InputStage {
3347 private final InputStage mNext;
3348
3349 protected static final int FORWARD = 0;
3350 protected static final int FINISH_HANDLED = 1;
3351 protected static final int FINISH_NOT_HANDLED = 2;
3352
3353 /**
3354 * Creates an input stage.
3355 * @param next The next stage to which events should be forwarded.
3356 */
3357 public InputStage(InputStage next) {
3358 mNext = next;
3359 }
3360
3361 /**
3362 * Delivers an event to be processed.
3363 */
3364 public final void deliver(QueuedInputEvent q) {
3365 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3366 forward(q);
3367 } else if (mView == null || !mAdded) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003368 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3369 finish(q, false);
3370 } else if (!mAttachInfo.mHasWindowFocus &&
3371 !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
3372 !isTerminalInputEvent(q.mEvent)) {
3373 // If this is a focused event and the window doesn't currently have input focus,
3374 // then drop this event. This could be an event that came back from the previous
3375 // stage but the window has lost focus in the meantime.
3376 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003377 finish(q, false);
3378 } else {
3379 apply(q, onProcess(q));
3380 }
3381 }
3382
3383 /**
3384 * Marks the the input event as finished then forwards it to the next stage.
3385 */
3386 protected void finish(QueuedInputEvent q, boolean handled) {
3387 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3388 if (handled) {
3389 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3390 }
3391 forward(q);
3392 }
3393
3394 /**
3395 * Forwards the event to the next stage.
3396 */
3397 protected void forward(QueuedInputEvent q) {
3398 onDeliverToNext(q);
3399 }
3400
3401 /**
3402 * Applies a result code from {@link #onProcess} to the specified event.
3403 */
3404 protected void apply(QueuedInputEvent q, int result) {
3405 if (result == FORWARD) {
3406 forward(q);
3407 } else if (result == FINISH_HANDLED) {
3408 finish(q, true);
3409 } else if (result == FINISH_NOT_HANDLED) {
3410 finish(q, false);
3411 } else {
3412 throw new IllegalArgumentException("Invalid result: " + result);
3413 }
3414 }
3415
3416 /**
3417 * Called when an event is ready to be processed.
3418 * @return A result code indicating how the event was handled.
3419 */
3420 protected int onProcess(QueuedInputEvent q) {
3421 return FORWARD;
3422 }
3423
3424 /**
3425 * Called when an event is being delivered to the next stage.
3426 */
3427 protected void onDeliverToNext(QueuedInputEvent q) {
3428 if (mNext != null) {
3429 mNext.deliver(q);
3430 } else {
3431 finishInputEvent(q);
3432 }
3433 }
3434 }
3435
3436 /**
3437 * Base class for implementing an input pipeline stage that supports
3438 * asynchronous and out-of-order processing of input events.
3439 * <p>
3440 * In addition to what a normal input stage can do, an asynchronous
3441 * input stage may also defer an input event that has been delivered to it
3442 * and finish or forward it later.
3443 * </p>
3444 */
3445 abstract class AsyncInputStage extends InputStage {
3446 private final String mTraceCounter;
3447
3448 private QueuedInputEvent mQueueHead;
3449 private QueuedInputEvent mQueueTail;
3450 private int mQueueLength;
3451
3452 protected static final int DEFER = 3;
3453
3454 /**
3455 * Creates an asynchronous input stage.
3456 * @param next The next stage to which events should be forwarded.
3457 * @param traceCounter The name of a counter to record the size of
3458 * the queue of pending events.
3459 */
3460 public AsyncInputStage(InputStage next, String traceCounter) {
3461 super(next);
3462 mTraceCounter = traceCounter;
3463 }
3464
3465 /**
3466 * Marks the event as deferred, which is to say that it will be handled
3467 * asynchronously. The caller is responsible for calling {@link #forward}
3468 * or {@link #finish} later when it is done handling the event.
3469 */
3470 protected void defer(QueuedInputEvent q) {
3471 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3472 enqueue(q);
3473 }
3474
3475 @Override
3476 protected void forward(QueuedInputEvent q) {
3477 // Clear the deferred flag.
3478 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3479
3480 // Fast path if the queue is empty.
3481 QueuedInputEvent curr = mQueueHead;
3482 if (curr == null) {
3483 super.forward(q);
3484 return;
3485 }
3486
3487 // Determine whether the event must be serialized behind any others
3488 // before it can be delivered to the next stage. This is done because
3489 // deferred events might be handled out of order by the stage.
3490 final int deviceId = q.mEvent.getDeviceId();
3491 QueuedInputEvent prev = null;
3492 boolean blocked = false;
3493 while (curr != null && curr != q) {
3494 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3495 blocked = true;
3496 }
3497 prev = curr;
3498 curr = curr.mNext;
3499 }
3500
3501 // If the event is blocked, then leave it in the queue to be delivered later.
3502 // Note that the event might not yet be in the queue if it was not previously
3503 // deferred so we will enqueue it if needed.
3504 if (blocked) {
3505 if (curr == null) {
3506 enqueue(q);
3507 }
3508 return;
3509 }
3510
3511 // The event is not blocked. Deliver it immediately.
3512 if (curr != null) {
3513 curr = curr.mNext;
3514 dequeue(q, prev);
3515 }
3516 super.forward(q);
3517
3518 // Dequeuing this event may have unblocked successors. Deliver them.
3519 while (curr != null) {
3520 if (deviceId == curr.mEvent.getDeviceId()) {
3521 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3522 break;
3523 }
3524 QueuedInputEvent next = curr.mNext;
3525 dequeue(curr, prev);
3526 super.forward(curr);
3527 curr = next;
3528 } else {
3529 prev = curr;
3530 curr = curr.mNext;
3531 }
3532 }
3533 }
3534
3535 @Override
3536 protected void apply(QueuedInputEvent q, int result) {
3537 if (result == DEFER) {
3538 defer(q);
3539 } else {
3540 super.apply(q, result);
3541 }
3542 }
3543
3544 private void enqueue(QueuedInputEvent q) {
3545 if (mQueueTail == null) {
3546 mQueueHead = q;
3547 mQueueTail = q;
3548 } else {
3549 mQueueTail.mNext = q;
3550 mQueueTail = q;
3551 }
3552
3553 mQueueLength += 1;
3554 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3555 }
3556
3557 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3558 if (prev == null) {
3559 mQueueHead = q.mNext;
3560 } else {
3561 prev.mNext = q.mNext;
3562 }
3563 if (mQueueTail == q) {
3564 mQueueTail = prev;
3565 }
3566 q.mNext = null;
3567
3568 mQueueLength -= 1;
3569 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3570 }
3571 }
3572
3573 /**
3574 * Delivers pre-ime input events to a native activity.
3575 * Does not support pointer events.
3576 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003577 final class NativePreImeInputStage extends AsyncInputStage
3578 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003579 public NativePreImeInputStage(InputStage next, String traceCounter) {
3580 super(next, traceCounter);
3581 }
3582
3583 @Override
3584 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003585 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3586 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3587 return DEFER;
3588 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003589 return FORWARD;
3590 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003591
3592 @Override
3593 public void onFinishedInputEvent(Object token, boolean handled) {
3594 QueuedInputEvent q = (QueuedInputEvent)token;
3595 if (handled) {
3596 finish(q, true);
3597 return;
3598 }
3599 forward(q);
3600 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003601 }
3602
3603 /**
3604 * Delivers pre-ime input events to the view hierarchy.
3605 * Does not support pointer events.
3606 */
3607 final class ViewPreImeInputStage extends InputStage {
3608 public ViewPreImeInputStage(InputStage next) {
3609 super(next);
3610 }
3611
3612 @Override
3613 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003614 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003615 return processKeyEvent(q);
3616 }
3617 return FORWARD;
3618 }
3619
3620 private int processKeyEvent(QueuedInputEvent q) {
3621 final KeyEvent event = (KeyEvent)q.mEvent;
3622 if (mView.dispatchKeyEventPreIme(event)) {
3623 return FINISH_HANDLED;
3624 }
3625 return FORWARD;
3626 }
3627 }
3628
3629 /**
3630 * Delivers input events to the ime.
3631 * Does not support pointer events.
3632 */
3633 final class ImeInputStage extends AsyncInputStage
3634 implements InputMethodManager.FinishedInputEventCallback {
3635 public ImeInputStage(InputStage next, String traceCounter) {
3636 super(next, traceCounter);
3637 }
3638
3639 @Override
3640 protected int onProcess(QueuedInputEvent q) {
3641 if (mLastWasImTarget) {
3642 InputMethodManager imm = InputMethodManager.peekInstance();
3643 if (imm != null) {
3644 final InputEvent event = q.mEvent;
3645 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3646 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3647 if (result == InputMethodManager.DISPATCH_HANDLED) {
3648 return FINISH_HANDLED;
3649 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
3650 return FINISH_NOT_HANDLED;
3651 } else {
3652 return DEFER; // callback will be invoked later
3653 }
3654 }
3655 }
3656 return FORWARD;
3657 }
3658
3659 @Override
3660 public void onFinishedInputEvent(Object token, boolean handled) {
3661 QueuedInputEvent q = (QueuedInputEvent)token;
3662 if (handled) {
3663 finish(q, true);
3664 return;
3665 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003666 forward(q);
3667 }
3668 }
3669
3670 /**
3671 * Performs early processing of post-ime input events.
3672 */
3673 final class EarlyPostImeInputStage extends InputStage {
3674 public EarlyPostImeInputStage(InputStage next) {
3675 super(next);
3676 }
3677
3678 @Override
3679 protected int onProcess(QueuedInputEvent q) {
3680 if (q.mEvent instanceof KeyEvent) {
3681 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003682 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003683 final int source = q.mEvent.getSource();
3684 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003685 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003686 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003687 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003688 return FORWARD;
3689 }
3690
3691 private int processKeyEvent(QueuedInputEvent q) {
3692 final KeyEvent event = (KeyEvent)q.mEvent;
3693
3694 // If the key's purpose is to exit touch mode then we consume it
3695 // and consider it handled.
3696 if (checkForLeavingTouchModeAndConsume(event)) {
3697 return FINISH_HANDLED;
3698 }
3699
3700 // Make sure the fallback event policy sees all keys that will be
3701 // delivered to the view hierarchy.
3702 mFallbackEventHandler.preDispatchKeyEvent(event);
3703 return FORWARD;
3704 }
3705
3706 private int processPointerEvent(QueuedInputEvent q) {
3707 final MotionEvent event = (MotionEvent)q.mEvent;
3708
3709 // Translate the pointer event for compatibility, if needed.
3710 if (mTranslator != null) {
3711 mTranslator.translateEventInScreenToAppWindow(event);
3712 }
3713
3714 // Enter touch mode on down or scroll.
3715 final int action = event.getAction();
3716 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3717 ensureTouchMode(true);
3718 }
3719
3720 // Offset the scroll position.
3721 if (mCurScrollY != 0) {
3722 event.offsetLocation(0, mCurScrollY);
3723 }
3724
3725 // Remember the touch position for possible drag-initiation.
3726 if (event.isTouchEvent()) {
3727 mLastTouchPoint.x = event.getRawX();
3728 mLastTouchPoint.y = event.getRawY();
3729 }
3730 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003731 }
3732 }
3733
Jeff Brownf9e989d2013-04-04 23:04:03 -07003734 /**
3735 * Delivers post-ime input events to a native activity.
3736 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003737 final class NativePostImeInputStage extends AsyncInputStage
3738 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003739 public NativePostImeInputStage(InputStage next, String traceCounter) {
3740 super(next, traceCounter);
3741 }
3742
3743 @Override
3744 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003745 if (mInputQueue != null) {
3746 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3747 return DEFER;
3748 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003749 return FORWARD;
3750 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003751
3752 @Override
3753 public void onFinishedInputEvent(Object token, boolean handled) {
3754 QueuedInputEvent q = (QueuedInputEvent)token;
3755 if (handled) {
3756 finish(q, true);
3757 return;
3758 }
3759 forward(q);
3760 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003761 }
3762
3763 /**
3764 * Delivers post-ime input events to the view hierarchy.
3765 */
3766 final class ViewPostImeInputStage extends InputStage {
3767 public ViewPostImeInputStage(InputStage next) {
3768 super(next);
3769 }
3770
3771 @Override
3772 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003773 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003774 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003775 } else {
3776 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003777 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3778 return processPointerEvent(q);
3779 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3780 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003781 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003782 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003783 }
3784 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003785 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003786
Jeff Brownf9e989d2013-04-04 23:04:03 -07003787 private int processKeyEvent(QueuedInputEvent q) {
3788 final KeyEvent event = (KeyEvent)q.mEvent;
3789
3790 // Deliver the key to the view hierarchy.
3791 if (mView.dispatchKeyEvent(event)) {
3792 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003793 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003794
3795 // If the Control modifier is held, try to interpret the key as a shortcut.
3796 if (event.getAction() == KeyEvent.ACTION_DOWN
3797 && event.isCtrlPressed()
3798 && event.getRepeatCount() == 0
3799 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3800 if (mView.dispatchKeyShortcutEvent(event)) {
3801 return FINISH_HANDLED;
3802 }
3803 }
3804
3805 // Apply the fallback event policy.
3806 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3807 return FINISH_HANDLED;
3808 }
3809
3810 // Handle automatic focus changes.
3811 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3812 int direction = 0;
3813 switch (event.getKeyCode()) {
3814 case KeyEvent.KEYCODE_DPAD_LEFT:
3815 if (event.hasNoModifiers()) {
3816 direction = View.FOCUS_LEFT;
3817 }
3818 break;
3819 case KeyEvent.KEYCODE_DPAD_RIGHT:
3820 if (event.hasNoModifiers()) {
3821 direction = View.FOCUS_RIGHT;
3822 }
3823 break;
3824 case KeyEvent.KEYCODE_DPAD_UP:
3825 if (event.hasNoModifiers()) {
3826 direction = View.FOCUS_UP;
3827 }
3828 break;
3829 case KeyEvent.KEYCODE_DPAD_DOWN:
3830 if (event.hasNoModifiers()) {
3831 direction = View.FOCUS_DOWN;
3832 }
3833 break;
3834 case KeyEvent.KEYCODE_TAB:
3835 if (event.hasNoModifiers()) {
3836 direction = View.FOCUS_FORWARD;
3837 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3838 direction = View.FOCUS_BACKWARD;
3839 }
3840 break;
3841 }
3842 if (direction != 0) {
3843 View focused = mView.findFocus();
3844 if (focused != null) {
3845 View v = focused.focusSearch(direction);
3846 if (v != null && v != focused) {
3847 // do the math the get the interesting rect
3848 // of previous focused into the coord system of
3849 // newly focused view
3850 focused.getFocusedRect(mTempRect);
3851 if (mView instanceof ViewGroup) {
3852 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3853 focused, mTempRect);
3854 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3855 v, mTempRect);
3856 }
3857 if (v.requestFocus(direction, mTempRect)) {
3858 playSoundEffect(SoundEffectConstants
3859 .getContantForFocusDirection(direction));
3860 return FINISH_HANDLED;
3861 }
3862 }
3863
3864 // Give the focused view a last chance to handle the dpad key.
3865 if (mView.dispatchUnhandledMove(focused, direction)) {
3866 return FINISH_HANDLED;
3867 }
3868 } else {
3869 // find the best view to give focus to in this non-touch-mode with no-focus
3870 View v = focusSearch(null, direction);
3871 if (v != null && v.requestFocus(direction)) {
3872 return FINISH_HANDLED;
3873 }
3874 }
3875 }
3876 }
3877 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003878 }
3879
Jeff Brownf9e989d2013-04-04 23:04:03 -07003880 private int processPointerEvent(QueuedInputEvent q) {
3881 final MotionEvent event = (MotionEvent)q.mEvent;
3882
3883 if (mView.dispatchPointerEvent(event)) {
3884 return FINISH_HANDLED;
3885 }
3886 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003887 }
3888
Jeff Brownf9e989d2013-04-04 23:04:03 -07003889 private int processTrackballEvent(QueuedInputEvent q) {
3890 final MotionEvent event = (MotionEvent)q.mEvent;
3891
3892 if (mView.dispatchTrackballEvent(event)) {
3893 return FINISH_HANDLED;
3894 }
3895 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003896 }
3897
Jeff Brownf9e989d2013-04-04 23:04:03 -07003898 private int processGenericMotionEvent(QueuedInputEvent q) {
3899 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003900
Jeff Brownf9e989d2013-04-04 23:04:03 -07003901 // Deliver the event to the view.
3902 if (mView.dispatchGenericMotionEvent(event)) {
3903 return FINISH_HANDLED;
3904 }
3905 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07003906 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003907 }
3908
Jeff Brownf9e989d2013-04-04 23:04:03 -07003909 /**
Jeff Brown678a1252013-04-09 17:46:25 -07003910 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07003911 */
3912 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07003913 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
3914 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
3915 private final SyntheticTouchNavigationHandler mTouchNavigation =
3916 new SyntheticTouchNavigationHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003917
3918 public SyntheticInputStage() {
3919 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08003920 }
3921
Jeff Brownf9e989d2013-04-04 23:04:03 -07003922 @Override
3923 protected int onProcess(QueuedInputEvent q) {
3924 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
3925 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07003926 final MotionEvent event = (MotionEvent)q.mEvent;
3927 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003928 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003929 mTrackball.process(event);
3930 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003931 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003932 mJoystick.process(event);
3933 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003934 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
3935 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07003936 mTouchNavigation.process(event);
3937 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003938 }
3939 }
3940 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003941 }
3942
Jeff Brownf9e989d2013-04-04 23:04:03 -07003943 @Override
3944 protected void onDeliverToNext(QueuedInputEvent q) {
3945 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
3946 // Cancel related synthetic events if any prior stage has handled the event.
3947 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07003948 final MotionEvent event = (MotionEvent)q.mEvent;
3949 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003950 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003951 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003952 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07003953 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003954 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
3955 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07003956 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003957 }
3958 }
3959 }
3960 super.onDeliverToNext(q);
3961 }
Jeff Brown678a1252013-04-09 17:46:25 -07003962 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003963
Jeff Brown678a1252013-04-09 17:46:25 -07003964 /**
3965 * Creates dpad events from unhandled trackball movements.
3966 */
3967 final class SyntheticTrackballHandler {
3968 private final TrackballAxis mX = new TrackballAxis();
3969 private final TrackballAxis mY = new TrackballAxis();
3970 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003971
Jeff Brown678a1252013-04-09 17:46:25 -07003972 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003973 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07003974 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07003975 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003976 // It has been too long since the last movement,
3977 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07003978 mX.reset(0);
3979 mY.reset(0);
3980 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003981 }
3982
3983 final int action = event.getAction();
3984 final int metaState = event.getMetaState();
3985 switch (action) {
3986 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07003987 mX.reset(2);
3988 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003989 enqueueInputEvent(new KeyEvent(curTime, curTime,
3990 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3991 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3992 InputDevice.SOURCE_KEYBOARD));
3993 break;
3994 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07003995 mX.reset(2);
3996 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07003997 enqueueInputEvent(new KeyEvent(curTime, curTime,
3998 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3999 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4000 InputDevice.SOURCE_KEYBOARD));
4001 break;
4002 }
4003
Jeff Brown678a1252013-04-09 17:46:25 -07004004 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4005 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004006 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004007 + " / Y=" + mY.position + " step="
4008 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004009 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004010 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4011 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004012
4013 // Generate DPAD events based on the trackball movement.
4014 // We pick the axis that has moved the most as the direction of
4015 // the DPAD. When we generate DPAD events for one axis, then the
4016 // other axis is reset -- we don't want to perform DPAD jumps due
4017 // to slight movements in the trackball when making major movements
4018 // along the other axis.
4019 int keycode = 0;
4020 int movement = 0;
4021 float accel = 1;
4022 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004023 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004024 if (movement != 0) {
4025 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4026 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004027 accel = mX.acceleration;
4028 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004029 }
4030 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004031 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004032 if (movement != 0) {
4033 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4034 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004035 accel = mY.acceleration;
4036 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004037 }
4038 }
4039
4040 if (keycode != 0) {
4041 if (movement < 0) movement = -movement;
4042 int accelMovement = (int)(movement * accel);
4043 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4044 + " accelMovement=" + accelMovement
4045 + " accel=" + accel);
4046 if (accelMovement > movement) {
4047 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4048 + keycode);
4049 movement--;
4050 int repeatCount = accelMovement - movement;
4051 enqueueInputEvent(new KeyEvent(curTime, curTime,
4052 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4053 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4054 InputDevice.SOURCE_KEYBOARD));
4055 }
4056 while (movement > 0) {
4057 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4058 + keycode);
4059 movement--;
4060 curTime = SystemClock.uptimeMillis();
4061 enqueueInputEvent(new KeyEvent(curTime, curTime,
4062 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4063 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4064 InputDevice.SOURCE_KEYBOARD));
4065 enqueueInputEvent(new KeyEvent(curTime, curTime,
4066 KeyEvent.ACTION_UP, keycode, 0, metaState,
4067 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4068 InputDevice.SOURCE_KEYBOARD));
4069 }
Jeff Brown678a1252013-04-09 17:46:25 -07004070 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004071 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004072 }
4073
Jeff Brown678a1252013-04-09 17:46:25 -07004074 public void cancel(MotionEvent event) {
4075 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004076
Jeff Brownf9e989d2013-04-04 23:04:03 -07004077 // If we reach this, we consumed a trackball event.
4078 // Because we will not translate the trackball event into a key event,
4079 // touch mode will not exit, so we exit touch mode here.
4080 if (mView != null && mAdded) {
4081 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004082 }
4083 }
Jeff Brown678a1252013-04-09 17:46:25 -07004084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085
Jeff Brown678a1252013-04-09 17:46:25 -07004086 /**
4087 * Maintains state information for a single trackball axis, generating
4088 * discrete (DPAD) movements based on raw trackball motion.
4089 */
4090 static final class TrackballAxis {
4091 /**
4092 * The maximum amount of acceleration we will apply.
4093 */
4094 static final float MAX_ACCELERATION = 20;
4095
4096 /**
4097 * The maximum amount of time (in milliseconds) between events in order
4098 * for us to consider the user to be doing fast trackball movements,
4099 * and thus apply an acceleration.
4100 */
4101 static final long FAST_MOVE_TIME = 150;
4102
4103 /**
4104 * Scaling factor to the time (in milliseconds) between events to how
4105 * much to multiple/divide the current acceleration. When movement
4106 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4107 * FAST_MOVE_TIME it divides it.
4108 */
4109 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4110
4111 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4112 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4113 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4114
4115 float position;
4116 float acceleration = 1;
4117 long lastMoveTime = 0;
4118 int step;
4119 int dir;
4120 int nonAccelMovement;
4121
4122 void reset(int _step) {
4123 position = 0;
4124 acceleration = 1;
4125 lastMoveTime = 0;
4126 step = _step;
4127 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004128 }
4129
Jeff Brown678a1252013-04-09 17:46:25 -07004130 /**
4131 * Add trackball movement into the state. If the direction of movement
4132 * has been reversed, the state is reset before adding the
4133 * movement (so that you don't have to compensate for any previously
4134 * collected movement before see the result of the movement in the
4135 * new direction).
4136 *
4137 * @return Returns the absolute value of the amount of movement
4138 * collected so far.
4139 */
4140 float collect(float off, long time, String axis) {
4141 long normTime;
4142 if (off > 0) {
4143 normTime = (long)(off * FAST_MOVE_TIME);
4144 if (dir < 0) {
4145 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4146 position = 0;
4147 step = 0;
4148 acceleration = 1;
4149 lastMoveTime = 0;
4150 }
4151 dir = 1;
4152 } else if (off < 0) {
4153 normTime = (long)((-off) * FAST_MOVE_TIME);
4154 if (dir > 0) {
4155 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4156 position = 0;
4157 step = 0;
4158 acceleration = 1;
4159 lastMoveTime = 0;
4160 }
4161 dir = -1;
4162 } else {
4163 normTime = 0;
4164 }
4165
4166 // The number of milliseconds between each movement that is
4167 // considered "normal" and will not result in any acceleration
4168 // or deceleration, scaled by the offset we have here.
4169 if (normTime > 0) {
4170 long delta = time - lastMoveTime;
4171 lastMoveTime = time;
4172 float acc = acceleration;
4173 if (delta < normTime) {
4174 // The user is scrolling rapidly, so increase acceleration.
4175 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4176 if (scale > 1) acc *= scale;
4177 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4178 + off + " normTime=" + normTime + " delta=" + delta
4179 + " scale=" + scale + " acc=" + acc);
4180 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4181 } else {
4182 // The user is scrolling slowly, so decrease acceleration.
4183 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4184 if (scale > 1) acc /= scale;
4185 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4186 + off + " normTime=" + normTime + " delta=" + delta
4187 + " scale=" + scale + " acc=" + acc);
4188 acceleration = acc > 1 ? acc : 1;
4189 }
4190 }
4191 position += off;
4192 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004193 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004194
Jeff Brown678a1252013-04-09 17:46:25 -07004195 /**
4196 * Generate the number of discrete movement events appropriate for
4197 * the currently collected trackball movement.
4198 *
4199 * @return Returns the number of discrete movements, either positive
4200 * or negative, or 0 if there is not enough trackball movement yet
4201 * for a discrete movement.
4202 */
4203 int generate() {
4204 int movement = 0;
4205 nonAccelMovement = 0;
4206 do {
4207 final int dir = position >= 0 ? 1 : -1;
4208 switch (step) {
4209 // If we are going to execute the first step, then we want
4210 // to do this as soon as possible instead of waiting for
4211 // a full movement, in order to make things look responsive.
4212 case 0:
4213 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4214 return movement;
4215 }
4216 movement += dir;
4217 nonAccelMovement += dir;
4218 step = 1;
4219 break;
4220 // If we have generated the first movement, then we need
4221 // to wait for the second complete trackball motion before
4222 // generating the second discrete movement.
4223 case 1:
4224 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4225 return movement;
4226 }
4227 movement += dir;
4228 nonAccelMovement += dir;
4229 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4230 step = 2;
4231 break;
4232 // After the first two, we generate discrete movements
4233 // consistently with the trackball, applying an acceleration
4234 // if the trackball is moving quickly. This is a simple
4235 // acceleration on top of what we already compute based
4236 // on how quickly the wheel is being turned, to apply
4237 // a longer increasing acceleration to continuous movement
4238 // in one direction.
4239 default:
4240 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4241 return movement;
4242 }
4243 movement += dir;
4244 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4245 float acc = acceleration;
4246 acc *= 1.1f;
4247 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4248 break;
4249 }
4250 } while (true);
4251 }
4252 }
4253
4254 /**
4255 * Creates dpad events from unhandled joystick movements.
4256 */
4257 final class SyntheticJoystickHandler extends Handler {
4258 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4259 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4260
4261 private int mLastXDirection;
4262 private int mLastYDirection;
4263 private int mLastXKeyCode;
4264 private int mLastYKeyCode;
4265
4266 public SyntheticJoystickHandler() {
4267 super(true);
4268 }
4269
4270 @Override
4271 public void handleMessage(Message msg) {
4272 switch (msg.what) {
4273 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4274 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4275 KeyEvent oldEvent = (KeyEvent)msg.obj;
4276 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4277 SystemClock.uptimeMillis(),
4278 oldEvent.getRepeatCount() + 1);
4279 if (mAttachInfo.mHasWindowFocus) {
4280 enqueueInputEvent(e);
4281 Message m = obtainMessage(msg.what, e);
4282 m.setAsynchronous(true);
4283 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4284 }
4285 } break;
4286 }
4287 }
4288
4289 public void process(MotionEvent event) {
4290 update(event, true);
4291 }
4292
4293 public void cancel(MotionEvent event) {
4294 update(event, false);
4295 }
4296
4297 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004298 final long time = event.getEventTime();
4299 final int metaState = event.getMetaState();
4300 final int deviceId = event.getDeviceId();
4301 final int source = event.getSource();
4302
4303 int xDirection = joystickAxisValueToDirection(
4304 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4305 if (xDirection == 0) {
4306 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004307 }
4308
Jeff Brownf9e989d2013-04-04 23:04:03 -07004309 int yDirection = joystickAxisValueToDirection(
4310 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4311 if (yDirection == 0) {
4312 yDirection = joystickAxisValueToDirection(event.getY());
4313 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004314
Jeff Brown678a1252013-04-09 17:46:25 -07004315 if (xDirection != mLastXDirection) {
4316 if (mLastXKeyCode != 0) {
4317 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004318 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004319 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004320 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004321 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004322 }
4323
Jeff Brown678a1252013-04-09 17:46:25 -07004324 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004325
4326 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004327 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004328 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4329 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004330 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004331 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4332 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004333 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004334 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004335 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004336 }
4337 }
4338
Jeff Brown678a1252013-04-09 17:46:25 -07004339 if (yDirection != mLastYDirection) {
4340 if (mLastYKeyCode != 0) {
4341 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004342 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004343 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004344 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004345 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004346 }
4347
Jeff Brown678a1252013-04-09 17:46:25 -07004348 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004349
4350 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004351 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004352 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4353 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004354 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004355 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4356 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004357 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004358 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004359 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004360 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004361 }
4362 }
4363
Jeff Brownf9e989d2013-04-04 23:04:03 -07004364 private int joystickAxisValueToDirection(float value) {
4365 if (value >= 0.5f) {
4366 return 1;
4367 } else if (value <= -0.5f) {
4368 return -1;
4369 } else {
4370 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004371 }
4372 }
Jeff Brown678a1252013-04-09 17:46:25 -07004373 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004374
Jeff Brown678a1252013-04-09 17:46:25 -07004375 /**
4376 * Creates dpad events from unhandled touch navigation movements.
4377 */
4378 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004379 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4380 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004381
Jeff Brown4dac9012013-04-10 01:03:19 -07004382 // Assumed nominal width and height in millimeters of a touch navigation pad,
4383 // if no resolution information is available from the input system.
4384 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4385 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004386
Jeff Brown4dac9012013-04-10 01:03:19 -07004387 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004388
Jeff Brown4dac9012013-04-10 01:03:19 -07004389 // Tap timeout in milliseconds.
4390 private static final int TAP_TIMEOUT = 250;
Jeff Brown678a1252013-04-09 17:46:25 -07004391
Jeff Brown4dac9012013-04-10 01:03:19 -07004392 // The maximum distance traveled for a gesture to be considered a tap in millimeters.
4393 private static final int TAP_SLOP_MILLIMETERS = 5;
Jeff Brown678a1252013-04-09 17:46:25 -07004394
Jeff Brown4dac9012013-04-10 01:03:19 -07004395 // The nominal distance traveled to move by one unit.
4396 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4397
4398 // Minimum and maximum fling velocity in ticks per second.
4399 // The minimum velocity should be set such that we perform enough ticks per
4400 // second that the fling appears to be fluid. For example, if we set the minimum
4401 // to 2 ticks per second, then there may be up to half a second delay between the next
4402 // to last and last ticks which is noticeably discrete and jerky. This value should
4403 // probably not be set to anything less than about 4.
4404 // If fling accuracy is a problem then consider tuning the tick distance instead.
4405 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4406 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4407
4408 // Fling velocity decay factor applied after each new key is emitted.
4409 // This parameter controls the deceleration and overall duration of the fling.
4410 // The fling stops automatically when its velocity drops below the minimum
4411 // fling velocity defined above.
4412 private static final float FLING_TICK_DECAY = 0.8f;
4413
4414 /* The input device that we are tracking. */
4415
4416 private int mCurrentDeviceId = -1;
4417 private int mCurrentSource;
4418 private boolean mCurrentDeviceSupported;
4419
4420 /* Configuration for the current input device. */
4421
4422 // The tap timeout and scaled slop.
4423 private int mConfigTapTimeout;
4424 private float mConfigTapSlop;
4425
4426 // The scaled tick distance. A movement of this amount should generally translate
4427 // into a single dpad event in a given direction.
4428 private float mConfigTickDistance;
4429
4430 // The minimum and maximum scaled fling velocity.
4431 private float mConfigMinFlingVelocity;
4432 private float mConfigMaxFlingVelocity;
4433
4434 /* Tracking state. */
4435
4436 // The velocity tracker for detecting flings.
4437 private VelocityTracker mVelocityTracker;
4438
4439 // The active pointer id, or -1 if none.
4440 private int mActivePointerId = -1;
4441
4442 // Time and location where tracking started.
4443 private long mStartTime;
4444 private float mStartX;
4445 private float mStartY;
4446
4447 // Most recently observed position.
4448 private float mLastX;
4449 private float mLastY;
4450
4451 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004452 private float mAccumulatedX;
4453 private float mAccumulatedY;
4454
Jeff Brown4dac9012013-04-10 01:03:19 -07004455 // Set to true if any movement was delivered to the app.
4456 // Implies that tap slop was exceeded.
4457 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004458
Jeff Brown4dac9012013-04-10 01:03:19 -07004459 // The most recently sent key down event.
4460 // The keycode remains set until the direction changes or a fling ends
4461 // so that repeated key events may be generated as required.
4462 private long mPendingKeyDownTime;
4463 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4464 private int mPendingKeyRepeatCount;
4465 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004466
Jeff Brown4dac9012013-04-10 01:03:19 -07004467 // The current fling velocity while a fling is in progress.
4468 private boolean mFlinging;
4469 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004470
4471 public SyntheticTouchNavigationHandler() {
4472 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004473 }
4474
4475 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004476 // Update the current device information.
4477 final long time = event.getEventTime();
4478 final int deviceId = event.getDeviceId();
4479 final int source = event.getSource();
4480 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4481 finishKeys(time);
4482 finishTracking(time);
4483 mCurrentDeviceId = deviceId;
4484 mCurrentSource = source;
4485 mCurrentDeviceSupported = false;
4486 InputDevice device = event.getDevice();
4487 if (device != null) {
4488 // In order to support an input device, we must know certain
4489 // characteristics about it, such as its size and resolution.
4490 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4491 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4492 if (xRange != null && yRange != null) {
4493 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004494
Jeff Brown4dac9012013-04-10 01:03:19 -07004495 // Infer the resolution if it not actually known.
4496 float xRes = xRange.getResolution();
4497 if (xRes <= 0) {
4498 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4499 }
4500 float yRes = yRange.getResolution();
4501 if (yRes <= 0) {
4502 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4503 }
4504 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004505
Jeff Brown4dac9012013-04-10 01:03:19 -07004506 // Precompute all of the configuration thresholds we will need.
4507 mConfigTapTimeout = TAP_TIMEOUT;
4508 mConfigTapSlop = TAP_SLOP_MILLIMETERS * nominalRes;
4509 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4510 mConfigMinFlingVelocity =
4511 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4512 mConfigMaxFlingVelocity =
4513 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4514
4515 if (LOCAL_DEBUG) {
4516 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4517 + " (" + Integer.toHexString(mCurrentSource) + "): "
4518 + "mConfigTapTimeout=" + mConfigTapTimeout
4519 + ", mConfigTapSlop=" + mConfigTapSlop
4520 + ", mConfigTickDistance=" + mConfigTickDistance
4521 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4522 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4523 }
4524 }
4525 }
Jeff Brown678a1252013-04-09 17:46:25 -07004526 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004527 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004528 return;
4529 }
4530
Jeff Brown4dac9012013-04-10 01:03:19 -07004531 // Handle the event.
4532 final int action = event.getActionMasked();
4533 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004534 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004535 boolean caughtFling = mFlinging;
4536 finishKeys(time);
4537 finishTracking(time);
4538 mActivePointerId = event.getPointerId(0);
4539 mVelocityTracker = VelocityTracker.obtain();
4540 mVelocityTracker.addMovement(event);
4541 mStartTime = time;
4542 mStartX = event.getX();
4543 mStartY = event.getY();
4544 mLastX = mStartX;
4545 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004546 mAccumulatedX = 0;
4547 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004548
4549 // If we caught a fling, then pretend that the tap slop has already
4550 // been exceeded to suppress taps whose only purpose is to stop the fling.
4551 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004552 break;
4553 }
4554
Jeff Brown4dac9012013-04-10 01:03:19 -07004555 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004556 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004557 if (mActivePointerId < 0) {
4558 break;
4559 }
4560 final int index = event.findPointerIndex(mActivePointerId);
4561 if (index < 0) {
4562 finishKeys(time);
4563 finishTracking(time);
4564 break;
4565 }
Jeff Brown678a1252013-04-09 17:46:25 -07004566
Jeff Brown4dac9012013-04-10 01:03:19 -07004567 mVelocityTracker.addMovement(event);
4568 final float x = event.getX(index);
4569 final float y = event.getY(index);
4570 mAccumulatedX += x - mLastX;
4571 mAccumulatedY += y - mLastY;
4572 mLastX = x;
4573 mLastY = y;
4574
4575 // Consume any accumulated movement so far.
4576 final int metaState = event.getMetaState();
4577 consumeAccumulatedMovement(time, metaState);
4578
4579 // Detect taps and flings.
4580 if (action == MotionEvent.ACTION_UP) {
4581 if (!mConsumedMovement
4582 && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop
4583 && time <= mStartTime + mConfigTapTimeout) {
4584 // It's a tap!
4585 finishKeys(time);
4586 sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
4587 sendKeyUp(time);
4588 } else if (mConsumedMovement
4589 && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4590 // It might be a fling.
4591 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4592 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4593 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4594 if (!startFling(time, vx, vy)) {
4595 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004596 }
4597 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004598 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004599 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004600 break;
4601 }
4602
4603 case MotionEvent.ACTION_CANCEL: {
4604 finishKeys(time);
4605 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004606 break;
4607 }
4608 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004609 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004610
4611 public void cancel(MotionEvent event) {
4612 if (mCurrentDeviceId == event.getDeviceId()
4613 && mCurrentSource == event.getSource()) {
4614 final long time = event.getEventTime();
4615 finishKeys(time);
4616 finishTracking(time);
4617 }
4618 }
4619
4620 private void finishKeys(long time) {
4621 cancelFling();
4622 sendKeyUp(time);
4623 }
4624
4625 private void finishTracking(long time) {
4626 if (mActivePointerId >= 0) {
4627 mActivePointerId = -1;
4628 mVelocityTracker.recycle();
4629 mVelocityTracker = null;
4630 }
4631 }
4632
4633 private void consumeAccumulatedMovement(long time, int metaState) {
4634 final float absX = Math.abs(mAccumulatedX);
4635 final float absY = Math.abs(mAccumulatedY);
4636 if (absX >= absY) {
4637 if (absX >= mConfigTickDistance) {
4638 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4639 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4640 mAccumulatedY = 0;
4641 mConsumedMovement = true;
4642 }
4643 } else {
4644 if (absY >= mConfigTickDistance) {
4645 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4646 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4647 mAccumulatedX = 0;
4648 mConsumedMovement = true;
4649 }
4650 }
4651 }
4652
4653 private float consumeAccumulatedMovement(long time, int metaState,
4654 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4655 while (accumulator <= -mConfigTickDistance) {
4656 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4657 accumulator += mConfigTickDistance;
4658 }
4659 while (accumulator >= mConfigTickDistance) {
4660 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4661 accumulator -= mConfigTickDistance;
4662 }
4663 return accumulator;
4664 }
4665
4666 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4667 if (mPendingKeyCode != keyCode) {
4668 sendKeyUp(time);
4669 mPendingKeyDownTime = time;
4670 mPendingKeyCode = keyCode;
4671 mPendingKeyRepeatCount = 0;
4672 } else {
4673 mPendingKeyRepeatCount += 1;
4674 }
4675 mPendingKeyMetaState = metaState;
4676
4677 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4678 // but it doesn't quite make sense when simulating the events in this way.
4679 if (LOCAL_DEBUG) {
4680 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4681 + ", repeatCount=" + mPendingKeyRepeatCount
4682 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4683 }
4684 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4685 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4686 mPendingKeyMetaState, mCurrentDeviceId,
4687 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4688 }
4689
4690 private void sendKeyUp(long time) {
4691 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4692 if (LOCAL_DEBUG) {
4693 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4694 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4695 }
4696 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4697 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4698 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4699 mCurrentSource));
4700 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4701 }
4702 }
4703
4704 private boolean startFling(long time, float vx, float vy) {
4705 if (LOCAL_DEBUG) {
4706 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4707 + ", min=" + mConfigMinFlingVelocity);
4708 }
4709
4710 // Flings must be oriented in the same direction as the preceding movements.
4711 switch (mPendingKeyCode) {
4712 case KeyEvent.KEYCODE_DPAD_LEFT:
4713 if (-vx >= mConfigMinFlingVelocity
4714 && Math.abs(vy) < mConfigMinFlingVelocity) {
4715 mFlingVelocity = -vx;
4716 break;
4717 }
4718 return false;
4719
4720 case KeyEvent.KEYCODE_DPAD_RIGHT:
4721 if (vx >= mConfigMinFlingVelocity
4722 && Math.abs(vy) < mConfigMinFlingVelocity) {
4723 mFlingVelocity = vx;
4724 break;
4725 }
4726 return false;
4727
4728 case KeyEvent.KEYCODE_DPAD_UP:
4729 if (-vy >= mConfigMinFlingVelocity
4730 && Math.abs(vx) < mConfigMinFlingVelocity) {
4731 mFlingVelocity = -vy;
4732 break;
4733 }
4734 return false;
4735
4736 case KeyEvent.KEYCODE_DPAD_DOWN:
4737 if (vy >= mConfigMinFlingVelocity
4738 && Math.abs(vx) < mConfigMinFlingVelocity) {
4739 mFlingVelocity = vy;
4740 break;
4741 }
4742 return false;
4743 }
4744
4745 // Post the first fling event.
4746 mFlinging = postFling(time);
4747 return mFlinging;
4748 }
4749
4750 private boolean postFling(long time) {
4751 // The idea here is to estimate the time when the pointer would have
4752 // traveled one tick distance unit given the current fling velocity.
4753 // This effect creates continuity of motion.
4754 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4755 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
4756 postAtTime(mFlingRunnable, time + delay);
4757 if (LOCAL_DEBUG) {
4758 Log.d(LOCAL_TAG, "Posted fling: velocity="
4759 + mFlingVelocity + ", delay=" + delay
4760 + ", keyCode=" + mPendingKeyCode);
4761 }
4762 return true;
4763 }
4764 return false;
4765 }
4766
4767 private void cancelFling() {
4768 if (mFlinging) {
4769 removeCallbacks(mFlingRunnable);
4770 mFlinging = false;
4771 }
4772 }
4773
4774 private final Runnable mFlingRunnable = new Runnable() {
4775 @Override
4776 public void run() {
4777 final long time = SystemClock.uptimeMillis();
4778 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
4779 mFlingVelocity *= FLING_TICK_DECAY;
4780 if (!postFling(time)) {
4781 mFlinging = false;
4782 finishKeys(time);
4783 }
4784 }
4785 };
Jeff Browncb1404e2011-01-15 18:14:15 -08004786 }
4787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004788 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004789 * Returns true if the key is used for keyboard navigation.
4790 * @param keyEvent The key event.
4791 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004792 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004793 private static boolean isNavigationKey(KeyEvent keyEvent) {
4794 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004795 case KeyEvent.KEYCODE_DPAD_LEFT:
4796 case KeyEvent.KEYCODE_DPAD_RIGHT:
4797 case KeyEvent.KEYCODE_DPAD_UP:
4798 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08004799 case KeyEvent.KEYCODE_DPAD_CENTER:
4800 case KeyEvent.KEYCODE_PAGE_UP:
4801 case KeyEvent.KEYCODE_PAGE_DOWN:
4802 case KeyEvent.KEYCODE_MOVE_HOME:
4803 case KeyEvent.KEYCODE_MOVE_END:
4804 case KeyEvent.KEYCODE_TAB:
4805 case KeyEvent.KEYCODE_SPACE:
4806 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004807 return true;
4808 }
4809 return false;
4810 }
4811
4812 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004813 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08004815 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004816 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004817 private static boolean isTypingKey(KeyEvent keyEvent) {
4818 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004819 }
4820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004821 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004822 * 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 -08004823 * @param event The key event.
4824 * @return Whether this key event should be consumed (meaning the act of
4825 * leaving touch mode alone is considered the event).
4826 */
4827 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004828 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004829 if (!mAttachInfo.mInTouchMode) {
4830 return false;
4831 }
4832
Jeff Brown4e6319b2010-12-13 10:36:51 -08004833 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
4834 final int action = event.getAction();
4835 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 return false;
4837 }
4838
Jeff Brown4e6319b2010-12-13 10:36:51 -08004839 // Don't leave touch mode if the IME told us not to.
4840 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
4841 return false;
4842 }
4843
4844 // If the key can be used for keyboard navigation then leave touch mode
4845 // and select a focused view if needed (in ensureTouchMode).
4846 // When a new focused view is selected, we consume the navigation key because
4847 // navigation doesn't make much sense unless a view already has focus so
4848 // the key's purpose is to set focus.
4849 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004850 return ensureTouchMode(false);
4851 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08004852
4853 // If the key can be used for typing then leave touch mode
4854 // and select a focused view if needed (in ensureTouchMode).
4855 // Always allow the view to process the typing key.
4856 if (isTypingKey(event)) {
4857 ensureTouchMode(false);
4858 return false;
4859 }
4860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004861 return false;
4862 }
4863
Christopher Tatea53146c2010-09-07 11:57:52 -07004864 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08004865 void setLocalDragState(Object obj) {
4866 mLocalDragState = obj;
4867 }
4868
Christopher Tatea53146c2010-09-07 11:57:52 -07004869 private void handleDragEvent(DragEvent event) {
4870 // From the root, only drag start/end/location are dispatched. entered/exited
4871 // are determined and dispatched by the viewgroup hierarchy, who then report
4872 // that back here for ultimate reporting back to the framework.
4873 if (mView != null && mAdded) {
4874 final int what = event.mAction;
4875
4876 if (what == DragEvent.ACTION_DRAG_EXITED) {
4877 // A direct EXITED event means that the window manager knows we've just crossed
4878 // a window boundary, so the current drag target within this one must have
4879 // just been exited. Send it the usual notifications and then we're done
4880 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07004881 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004882 } else {
4883 // Cache the drag description when the operation starts, then fill it in
4884 // on subsequent calls as a convenience
4885 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07004886 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07004887 mDragDescription = event.mClipDescription;
4888 } else {
4889 event.mClipDescription = mDragDescription;
4890 }
4891
4892 // For events with a [screen] location, translate into window coordinates
4893 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
4894 mDragPoint.set(event.mX, event.mY);
4895 if (mTranslator != null) {
4896 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
4897 }
4898
4899 if (mCurScrollY != 0) {
4900 mDragPoint.offset(0, mCurScrollY);
4901 }
4902
4903 event.mX = mDragPoint.x;
4904 event.mY = mDragPoint.y;
4905 }
4906
4907 // Remember who the current drag target is pre-dispatch
4908 final View prevDragView = mCurrentDragView;
4909
4910 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07004911 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004912
4913 // If we changed apparent drag target, tell the OS about it
4914 if (prevDragView != mCurrentDragView) {
4915 try {
4916 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07004917 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07004918 }
4919 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07004920 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07004921 }
4922 } catch (RemoteException e) {
4923 Slog.e(TAG, "Unable to note drag target change");
4924 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004925 }
Chris Tated4533f12010-10-19 15:15:08 -07004926
Christopher Tate407b4e92010-11-30 17:14:08 -08004927 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07004928 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08004929 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07004930 try {
4931 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07004932 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07004933 } catch (RemoteException e) {
4934 Log.e(TAG, "Unable to report drop result");
4935 }
4936 }
Christopher Tate407b4e92010-11-30 17:14:08 -08004937
4938 // When the drag operation ends, release any local state object
4939 // that may have been in use
4940 if (what == DragEvent.ACTION_DRAG_ENDED) {
4941 setLocalDragState(null);
4942 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004943 }
4944 }
4945 event.recycle();
4946 }
4947
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004948 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
4949 if (mSeq != args.seq) {
4950 // The sequence has changed, so we need to update our value and make
4951 // sure to do a traversal afterward so the window manager is given our
4952 // most recent data.
4953 mSeq = args.seq;
4954 mAttachInfo.mForceReportNewAttributes = true;
4955 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08004956 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004957 if (mView == null) return;
4958 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004959 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004960 }
Dianne Hackborncf675782012-05-10 15:07:24 -07004961 if (mAttachInfo != null) {
4962 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
4963 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
4964 mAttachInfo.mGlobalSystemUiVisibility = visibility;
4965 mView.dispatchSystemUiVisibilityChanged(visibility);
4966 }
4967 }
Joe Onorato664644d2011-01-23 17:53:23 -08004968 }
4969
Dianne Hackborn12d3a942012-04-27 14:16:30 -07004970 public void handleDispatchDoneAnimating() {
4971 if (mWindowsAnimating) {
4972 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07004973 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07004974 scheduleTraversals();
4975 }
4976 }
4977 }
4978
Christopher Tate2c095f32010-10-04 14:13:40 -07004979 public void getLastTouchPoint(Point outLocation) {
4980 outLocation.x = (int) mLastTouchPoint.x;
4981 outLocation.y = (int) mLastTouchPoint.y;
4982 }
4983
Chris Tate9d1ab882010-11-02 15:55:39 -07004984 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07004985 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07004986 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07004987 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004988 }
4989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004990 private AudioManager getAudioManager() {
4991 if (mView == null) {
4992 throw new IllegalStateException("getAudioManager called when there is no mView");
4993 }
4994 if (mAudioManager == null) {
4995 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
4996 }
4997 return mAudioManager;
4998 }
4999
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005000 public AccessibilityInteractionController getAccessibilityInteractionController() {
5001 if (mView == null) {
5002 throw new IllegalStateException("getAccessibilityInteractionController"
5003 + " called when there is no mView");
5004 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005005 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005006 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005007 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005008 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005009 }
5010
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005011 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5012 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005013
5014 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005015 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005016 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005017 restore = true;
5018 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005019 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005020 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005021 if (params != null) {
5022 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005023 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005024 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005025 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005026 if (params != null && mOrigWindowType != params.type) {
5027 // For compatibility with old apps, don't crash here.
5028 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
5029 Slog.w(TAG, "Window type can not be changed after "
5030 + "the window is added; ignoring change of " + mView);
5031 params.type = mOrigWindowType;
5032 }
5033 }
Jeff Brown98365d72012-08-19 20:30:52 -07005034 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005035 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005036 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5037 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005038 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005039 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005040 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005041 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005042 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005043 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005044 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005045
5046 if (mTranslator != null) {
5047 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005048 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005049 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5050 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005051 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005052 return relayoutResult;
5053 }
Romain Guy8506ab42009-06-11 17:35:47 -07005054
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005055 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005056 * {@inheritDoc}
5057 */
5058 public void playSoundEffect(int effectId) {
5059 checkThread();
5060
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005061 try {
5062 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005063
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005064 switch (effectId) {
5065 case SoundEffectConstants.CLICK:
5066 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5067 return;
5068 case SoundEffectConstants.NAVIGATION_DOWN:
5069 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5070 return;
5071 case SoundEffectConstants.NAVIGATION_LEFT:
5072 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5073 return;
5074 case SoundEffectConstants.NAVIGATION_RIGHT:
5075 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5076 return;
5077 case SoundEffectConstants.NAVIGATION_UP:
5078 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5079 return;
5080 default:
5081 throw new IllegalArgumentException("unknown effect id " + effectId +
5082 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5083 }
5084 } catch (IllegalStateException e) {
5085 // Exception thrown by getAudioManager() when mView is null
5086 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5087 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005088 }
5089 }
5090
5091 /**
5092 * {@inheritDoc}
5093 */
5094 public boolean performHapticFeedback(int effectId, boolean always) {
5095 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005096 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005097 } catch (RemoteException e) {
5098 return false;
5099 }
5100 }
5101
5102 /**
5103 * {@inheritDoc}
5104 */
5105 public View focusSearch(View focused, int direction) {
5106 checkThread();
5107 if (!(mView instanceof ViewGroup)) {
5108 return null;
5109 }
5110 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5111 }
5112
5113 public void debug() {
5114 mView.debug();
5115 }
Romain Guy65b345f2011-07-27 18:51:50 -07005116
Romain Guy211370f2012-02-01 16:10:55 -08005117 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005118 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005119 if (mView != null) {
5120 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005121 }
5122 }
5123
Romain Guya998dff2012-03-23 18:58:36 -07005124 private static void getGfxInfo(View view, int[] info) {
Romain Guy65b345f2011-07-27 18:51:50 -07005125 DisplayList displayList = view.mDisplayList;
5126 info[0]++;
5127 if (displayList != null) {
5128 info[1] += displayList.getSize();
5129 }
5130
5131 if (view instanceof ViewGroup) {
5132 ViewGroup group = (ViewGroup) view;
5133
5134 int count = group.getChildCount();
5135 for (int i = 0; i < count; i++) {
5136 getGfxInfo(group.getChildAt(i), info);
5137 }
5138 }
5139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140
5141 public void die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005142 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5143 // done by dispatchDetachedFromWindow will cause havoc on return.
5144 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005145 doDie();
5146 } else {
Romain Guy1f59e5c2012-05-06 14:11:16 -07005147 if (!mIsDrawing) {
5148 destroyHardwareRenderer();
5149 } else {
5150 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5151 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5152 }
Jeff Browna175a5b2012-02-15 19:18:31 -08005153 mHandler.sendEmptyMessage(MSG_DIE);
Dianne Hackborn94d69142009-09-28 22:14:42 -07005154 }
5155 }
5156
5157 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005158 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005159 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005160 synchronized (this) {
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 }
Romain Guyedbca122012-04-04 18:25:53 -07005184
5185 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 }
5191 }
5192
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005193 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005194 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5195 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005196 }
5197
Dianne Hackborna53de062012-05-08 18:53:51 -07005198 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005199 mHandler.post(new Runnable() {
5200 @Override
5201 public void run() {
5202 // Profiling
5203 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5204 profileRendering(mAttachInfo.mHasWindowFocus);
5205
5206 // Hardware rendering
5207 if (mAttachInfo.mHardwareRenderer != null) {
5208 if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mHolder.getSurface())) {
5209 invalidate();
5210 }
5211 }
5212
5213 // Layout debugging
5214 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5215 if (layout != mAttachInfo.mDebugLayout) {
5216 mAttachInfo.mDebugLayout = layout;
5217 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5218 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5219 }
5220 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005221 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005222 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005223 }
5224
Romain Guy29d89972010-09-22 16:10:57 -07005225 private void destroyHardwareRenderer() {
Romain Guya998dff2012-03-23 18:58:36 -07005226 AttachInfo attachInfo = mAttachInfo;
5227 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
5228
5229 if (hardwareRenderer != null) {
5230 if (mView != null) {
5231 hardwareRenderer.destroyHardwareResources(mView);
5232 }
5233 hardwareRenderer.destroy(true);
5234 hardwareRenderer.setRequested(false);
5235
5236 attachInfo.mHardwareRenderer = null;
5237 attachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005238 }
5239 }
5240
Jeff Browna175a5b2012-02-15 19:18:31 -08005241 public void dispatchFinishInputConnection(InputConnection connection) {
5242 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5243 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005244 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005245
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005246 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08005247 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005248 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5249 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005250 + " visibleInsets=" + visibleInsets.toShortString()
5251 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005252 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005253 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005254 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005255 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005256 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005257 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005258 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005259 SomeArgs args = SomeArgs.obtain();
5260 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5261 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5262 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5263 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5264 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005265 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005266 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005267 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005268 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005269
Craig Mautner5702d4d2012-06-30 14:10:16 -07005270 public void dispatchMoved(int newX, int newY) {
5271 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5272 if (mTranslator != null) {
5273 PointF point = new PointF(newX, newY);
5274 mTranslator.translatePointInScreenToAppWindow(point);
5275 newX = (int) (point.x + 0.5);
5276 newY = (int) (point.y + 0.5);
5277 }
5278 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5279 mHandler.sendMessage(msg);
5280 }
5281
Jeff Brown4952dfd2011-11-30 19:23:22 -08005282 /**
5283 * Represents a pending input event that is waiting in a queue.
5284 *
5285 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005286 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005287 * one input event to the application at a time and waits for the application
5288 * to finish handling it before delivering the next one.
5289 *
5290 * However, because the application or IME can synthesize and inject multiple
5291 * key events at a time without going through the input dispatcher, we end up
5292 * needing a queue on the application's side.
5293 */
5294 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005295 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5296 public static final int FLAG_DEFERRED = 1 << 1;
5297 public static final int FLAG_FINISHED = 1 << 2;
5298 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5299 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005300
5301 public QueuedInputEvent mNext;
5302
5303 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005304 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005305 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005306
5307 public boolean shouldSkipIme() {
5308 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5309 return true;
5310 }
5311 return mEvent instanceof MotionEvent
5312 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5313 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005314 }
5315
5316 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005317 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005318 QueuedInputEvent q = mQueuedInputEventPool;
5319 if (q != null) {
5320 mQueuedInputEventPoolSize -= 1;
5321 mQueuedInputEventPool = q.mNext;
5322 q.mNext = null;
5323 } else {
5324 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005325 }
5326
Jeff Brown4952dfd2011-11-30 19:23:22 -08005327 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005328 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005329 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005330 return q;
5331 }
5332
5333 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5334 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005335 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005336
5337 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5338 mQueuedInputEventPoolSize += 1;
5339 q.mNext = mQueuedInputEventPool;
5340 mQueuedInputEventPool = q;
5341 }
5342 }
5343
Jeff Brownf9261d22012-02-03 13:49:15 -08005344 void enqueueInputEvent(InputEvent event) {
5345 enqueueInputEvent(event, null, 0, false);
5346 }
5347
Jeff Brown4952dfd2011-11-30 19:23:22 -08005348 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005349 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005350 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005351
Jeff Brown4952dfd2011-11-30 19:23:22 -08005352 // Always enqueue the input event in order, regardless of its time stamp.
5353 // We do this because the application or the IME may inject key events
5354 // in response to touch events and we want to ensure that the injected keys
5355 // are processed in the order they were received and we cannot trust that
5356 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005357 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005358 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005359 mPendingInputEventHead = q;
5360 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005361 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005362 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005363 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005364 }
Michael Wright95ae9422013-03-14 10:58:50 -07005365 mPendingInputEventCount += 1;
5366 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5367 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005368
Jeff Brownf9261d22012-02-03 13:49:15 -08005369 if (processImmediately) {
5370 doProcessInputEvents();
5371 } else {
5372 scheduleProcessInputEvents();
5373 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005374 }
5375
5376 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005377 if (!mProcessInputEventsScheduled) {
5378 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005379 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5380 msg.setAsynchronous(true);
5381 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005382 }
5383 }
5384
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005385 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005386 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005387 while (mPendingInputEventHead != null) {
5388 QueuedInputEvent q = mPendingInputEventHead;
5389 mPendingInputEventHead = q.mNext;
5390 if (mPendingInputEventHead == null) {
5391 mPendingInputEventTail = null;
5392 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005393 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005394
Michael Wright95ae9422013-03-14 10:58:50 -07005395 mPendingInputEventCount -= 1;
5396 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5397 mPendingInputEventCount);
5398
Jeff Brownf9e989d2013-04-04 23:04:03 -07005399 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005400 }
5401
5402 // We are done processing all input events that we can process right now
5403 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005404 if (mProcessInputEventsScheduled) {
5405 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005406 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005407 }
5408 }
5409
Jeff Brownf9e989d2013-04-04 23:04:03 -07005410 private void deliverInputEvent(QueuedInputEvent q) {
5411 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
5412 try {
5413 if (mInputEventConsistencyVerifier != null) {
5414 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5415 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005416
Jeff Brownf9e989d2013-04-04 23:04:03 -07005417 InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5418 if (stage != null) {
5419 stage.deliver(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005420 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005421 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005422 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005423 } finally {
5424 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Michael Wrightbf020962013-03-28 17:27:50 -07005425 }
Michael Wrightbf020962013-03-28 17:27:50 -07005426 }
5427
Jeff Brownf9e989d2013-04-04 23:04:03 -07005428 private void finishInputEvent(QueuedInputEvent q) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005429 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005430 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005431 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005432 } else {
5433 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005434 }
5435
5436 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005437 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005438
Jeff Brownf9e989d2013-04-04 23:04:03 -07005439 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005440 if (event instanceof KeyEvent) {
5441 final KeyEvent keyEvent = (KeyEvent)event;
5442 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5443 } else {
5444 final MotionEvent motionEvent = (MotionEvent)event;
5445 final int action = motionEvent.getAction();
5446 return action == MotionEvent.ACTION_UP
5447 || action == MotionEvent.ACTION_CANCEL
5448 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005449 }
5450 }
5451
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005452 void scheduleConsumeBatchedInput() {
5453 if (!mConsumeBatchedInputScheduled) {
5454 mConsumeBatchedInputScheduled = true;
5455 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5456 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005457 }
5458 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005459
5460 void unscheduleConsumeBatchedInput() {
5461 if (mConsumeBatchedInputScheduled) {
5462 mConsumeBatchedInputScheduled = false;
5463 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5464 mConsumedBatchedInputRunnable, null);
5465 }
5466 }
5467
Jeff Brown771526c2012-04-27 15:13:25 -07005468 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005469 if (mConsumeBatchedInputScheduled) {
5470 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005471 if (mInputEventReceiver != null) {
Jeff Brown771526c2012-04-27 15:13:25 -07005472 mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005473 }
Jeff Brown330314c2012-04-27 02:20:22 -07005474 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005475 }
5476 }
5477
5478 final class TraversalRunnable implements Runnable {
5479 @Override
5480 public void run() {
5481 doTraversal();
5482 }
5483 }
5484 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005485
Jeff Brown32cbc38552011-12-01 14:01:49 -08005486 final class WindowInputEventReceiver extends InputEventReceiver {
5487 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5488 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005489 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005490
5491 @Override
5492 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005493 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005494 }
Jeff Brown072ec962012-02-07 14:46:57 -08005495
5496 @Override
5497 public void onBatchedInputEventPending() {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005498 scheduleConsumeBatchedInput();
5499 }
5500
5501 @Override
5502 public void dispose() {
5503 unscheduleConsumeBatchedInput();
5504 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005505 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005506 }
5507 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005508
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005509 final class ConsumeBatchedInputRunnable implements Runnable {
5510 @Override
5511 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005512 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005513 }
5514 }
5515 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5516 new ConsumeBatchedInputRunnable();
5517 boolean mConsumeBatchedInputScheduled;
5518
Jeff Brown6cb7b462012-03-05 13:21:17 -08005519 final class InvalidateOnAnimationRunnable implements Runnable {
5520 private boolean mPosted;
5521 private ArrayList<View> mViews = new ArrayList<View>();
5522 private ArrayList<AttachInfo.InvalidateInfo> mViewRects =
5523 new ArrayList<AttachInfo.InvalidateInfo>();
5524 private View[] mTempViews;
5525 private AttachInfo.InvalidateInfo[] mTempViewRects;
5526
5527 public void addView(View view) {
5528 synchronized (this) {
5529 mViews.add(view);
5530 postIfNeededLocked();
5531 }
5532 }
5533
5534 public void addViewRect(AttachInfo.InvalidateInfo info) {
5535 synchronized (this) {
5536 mViewRects.add(info);
5537 postIfNeededLocked();
5538 }
5539 }
5540
5541 public void removeView(View view) {
5542 synchronized (this) {
5543 mViews.remove(view);
5544
5545 for (int i = mViewRects.size(); i-- > 0; ) {
5546 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5547 if (info.target == view) {
5548 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005549 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005550 }
5551 }
5552
5553 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005554 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005555 mPosted = false;
5556 }
5557 }
5558 }
5559
5560 @Override
5561 public void run() {
5562 final int viewCount;
5563 final int viewRectCount;
5564 synchronized (this) {
5565 mPosted = false;
5566
5567 viewCount = mViews.size();
5568 if (viewCount != 0) {
5569 mTempViews = mViews.toArray(mTempViews != null
5570 ? mTempViews : new View[viewCount]);
5571 mViews.clear();
5572 }
5573
5574 viewRectCount = mViewRects.size();
5575 if (viewRectCount != 0) {
5576 mTempViewRects = mViewRects.toArray(mTempViewRects != null
5577 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
5578 mViewRects.clear();
5579 }
5580 }
5581
5582 for (int i = 0; i < viewCount; i++) {
5583 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07005584 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08005585 }
5586
5587 for (int i = 0; i < viewRectCount; i++) {
5588 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
5589 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005590 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005591 }
5592 }
5593
5594 private void postIfNeededLocked() {
5595 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005596 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005597 mPosted = true;
5598 }
5599 }
5600 }
5601 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
5602 new InvalidateOnAnimationRunnable();
5603
Jeff Browna175a5b2012-02-15 19:18:31 -08005604 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
5605 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
5606 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5607 }
5608
Jeff Browna175a5b2012-02-15 19:18:31 -08005609 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
5610 long delayMilliseconds) {
5611 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
5612 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5613 }
5614
Jeff Brown6cb7b462012-03-05 13:21:17 -08005615 public void dispatchInvalidateOnAnimation(View view) {
5616 mInvalidateOnAnimationRunnable.addView(view);
5617 }
5618
5619 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
5620 mInvalidateOnAnimationRunnable.addViewRect(info);
5621 }
5622
Romain Guy2a0f2282012-05-08 14:43:12 -07005623 public void enqueueDisplayList(DisplayList displayList) {
Romain Guy51e4d4d2012-03-15 18:30:47 -07005624 mDisplayLists.add(displayList);
Romain Guy2a0f2282012-05-08 14:43:12 -07005625 }
5626
Jeff Brown6cb7b462012-03-05 13:21:17 -08005627 public void cancelInvalidate(View view) {
5628 mHandler.removeMessages(MSG_INVALIDATE, view);
5629 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
5630 // them to the pool
5631 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
5632 mInvalidateOnAnimationRunnable.removeView(view);
5633 }
5634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005635 public void dispatchKey(KeyEvent event) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005636 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005637 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005638 mHandler.sendMessage(msg);
5639 }
5640
5641 public void dispatchKeyFromIme(KeyEvent event) {
5642 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005643 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005644 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08005645 }
5646
John Reckd6b10982012-04-19 18:01:35 -07005647 public void dispatchUnhandledKey(KeyEvent event) {
5648 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
5649 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5650 final int keyCode = event.getKeyCode();
5651 final int metaState = event.getMetaState();
5652
Jeff Brownfd23e3e2012-05-09 13:34:28 -07005653 // Check for fallback actions specified by the key character map.
5654 KeyCharacterMap.FallbackAction fallbackAction =
5655 kcm.getFallbackAction(keyCode, metaState);
5656 if (fallbackAction != null) {
5657 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5658 KeyEvent fallbackEvent = KeyEvent.obtain(
5659 event.getDownTime(), event.getEventTime(),
5660 event.getAction(), fallbackAction.keyCode,
5661 event.getRepeatCount(), fallbackAction.metaState,
5662 event.getDeviceId(), event.getScanCode(),
5663 flags, event.getSource(), null);
5664 fallbackAction.recycle();
5665
John Reckd6b10982012-04-19 18:01:35 -07005666 dispatchKey(fallbackEvent);
5667 }
5668 }
5669 }
5670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005671 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005672 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005673 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005674 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005675 }
5676
Romain Guybb9908b2012-03-08 11:14:07 -08005677 public void dispatchScreenStateChange(boolean on) {
5678 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
Romain Guy7e4e5612012-03-05 14:37:29 -08005679 msg.arg1 = on ? 1 : 0;
5680 mHandler.sendMessage(msg);
5681 }
5682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005683 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08005684 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
5685 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005686 }
5687
5688 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
5689 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005690 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 msg.arg1 = hasFocus ? 1 : 0;
5692 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005693 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005694 }
5695
Dianne Hackbornffa42482009-09-23 22:20:11 -07005696 public void dispatchCloseSystemDialogs(String reason) {
5697 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005698 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07005699 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08005700 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07005701 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005702
5703 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07005704 final int what;
5705 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005706 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
5707 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07005708 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08005709 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07005710 }
Jeff Browna175a5b2012-02-15 19:18:31 -08005711 Message msg = mHandler.obtainMessage(what, event);
5712 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07005713 }
5714
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005715 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
5716 int localValue, int localChanges) {
5717 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
5718 args.seq = seq;
5719 args.globalVisibility = globalVisibility;
5720 args.localValue = localValue;
5721 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08005722 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
5723 }
5724
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005725 public void dispatchDoneAnimating() {
5726 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
5727 }
5728
Jeff Browna175a5b2012-02-15 19:18:31 -08005729 public void dispatchCheckFocus() {
5730 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
5731 // This will result in a call to checkFocus() below.
5732 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
5733 }
Joe Onorato664644d2011-01-23 17:53:23 -08005734 }
5735
svetoslavganov75986cf2009-05-14 22:28:01 -07005736 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005737 * Post a callback to send a
5738 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07005739 * This event is send at most once every
5740 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005741 */
Svetoslav Ganov42138042012-03-20 11:51:39 -07005742 private void postSendWindowContentChangedCallback(View source) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005743 if (mSendWindowContentChangedAccessibilityEvent == null) {
5744 mSendWindowContentChangedAccessibilityEvent =
5745 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005746 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07005747 View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource;
5748 if (oldSource == null) {
5749 mSendWindowContentChangedAccessibilityEvent.mSource = source;
Jeff Browna175a5b2012-02-15 19:18:31 -08005750 mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
Svetoslav Ganova0156172011-06-26 17:55:44 -07005751 ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
Svetoslav Ganov42138042012-03-20 11:51:39 -07005752 } else {
Romain Guyba6be8a2012-04-23 18:22:09 -07005753 mSendWindowContentChangedAccessibilityEvent.mSource =
5754 getCommonPredecessor(oldSource, source);
Svetoslav Ganova0156172011-06-26 17:55:44 -07005755 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005756 }
5757
5758 /**
5759 * Remove a posted callback to send a
5760 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
5761 */
5762 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07005763 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005764 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005765 }
5766 }
5767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005768 public boolean showContextMenuForChild(View originalView) {
5769 return false;
5770 }
5771
Adam Powell6e346362010-07-23 10:18:23 -07005772 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
5773 return null;
5774 }
5775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005776 public void createContextMenu(ContextMenu menu) {
5777 }
5778
5779 public void childDrawableStateChanged(View child) {
5780 }
5781
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005782 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
5783 if (mView == null) {
5784 return false;
5785 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005786 // Intercept accessibility focus events fired by virtual nodes to keep
5787 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005788 final int eventType = event.getEventType();
5789 switch (eventType) {
5790 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005791 final long sourceNodeId = event.getSourceNodeId();
5792 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5793 sourceNodeId);
5794 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5795 if (source != null) {
5796 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5797 if (provider != null) {
5798 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
5799 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
5800 setAccessibilityFocus(source, node);
5801 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005802 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005803 } break;
5804 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07005805 final long sourceNodeId = event.getSourceNodeId();
5806 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
5807 sourceNodeId);
5808 View source = mView.findViewByAccessibilityId(accessibilityViewId);
5809 if (source != null) {
5810 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
5811 if (provider != null) {
5812 setAccessibilityFocus(null, null);
5813 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005814 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07005815 } break;
5816 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005817 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07005818 return true;
5819 }
5820
Svetoslav Ganov42138042012-03-20 11:51:39 -07005821 @Override
5822 public void childAccessibilityStateChanged(View child) {
5823 postSendWindowContentChangedCallback(child);
5824 }
5825
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08005826 @Override
5827 public boolean canResolveLayoutDirection() {
5828 return true;
5829 }
5830
5831 @Override
5832 public boolean isLayoutDirectionResolved() {
5833 return true;
5834 }
5835
5836 @Override
5837 public int getLayoutDirection() {
5838 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
5839 }
5840
5841 @Override
5842 public boolean canResolveTextDirection() {
5843 return true;
5844 }
5845
5846 @Override
5847 public boolean isTextDirectionResolved() {
5848 return true;
5849 }
5850
5851 @Override
5852 public int getTextDirection() {
5853 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
5854 }
5855
5856 @Override
5857 public boolean canResolveTextAlignment() {
5858 return true;
5859 }
5860
5861 @Override
5862 public boolean isTextAlignmentResolved() {
5863 return true;
5864 }
5865
5866 @Override
5867 public int getTextAlignment() {
5868 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
5869 }
5870
Svetoslav Ganov42138042012-03-20 11:51:39 -07005871 private View getCommonPredecessor(View first, View second) {
5872 if (mAttachInfo != null) {
5873 if (mTempHashSet == null) {
5874 mTempHashSet = new HashSet<View>();
5875 }
5876 HashSet<View> seen = mTempHashSet;
5877 seen.clear();
5878 View firstCurrent = first;
5879 while (firstCurrent != null) {
5880 seen.add(firstCurrent);
5881 ViewParent firstCurrentParent = firstCurrent.mParent;
5882 if (firstCurrentParent instanceof View) {
5883 firstCurrent = (View) firstCurrentParent;
5884 } else {
5885 firstCurrent = null;
5886 }
5887 }
5888 View secondCurrent = second;
5889 while (secondCurrent != null) {
5890 if (seen.contains(secondCurrent)) {
5891 seen.clear();
5892 return secondCurrent;
5893 }
5894 ViewParent secondCurrentParent = secondCurrent.mParent;
5895 if (secondCurrentParent instanceof View) {
5896 secondCurrent = (View) secondCurrentParent;
5897 } else {
5898 secondCurrent = null;
5899 }
5900 }
5901 seen.clear();
5902 }
5903 return null;
5904 }
5905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005906 void checkThread() {
5907 if (mThread != Thread.currentThread()) {
5908 throw new CalledFromWrongThreadException(
5909 "Only the original thread that created a view hierarchy can touch its views.");
5910 }
5911 }
5912
5913 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07005914 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005915 }
5916
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07005917 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
5918 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
5919 if (rectangle != null) {
5920 mTempRect.set(rectangle);
5921 mTempRect.offset(0, -mCurScrollY);
5922 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
5923 try {
5924 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
5925 } catch (RemoteException re) {
5926 /* ignore */
5927 }
5928 }
5929 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005930 }
Romain Guy8506ab42009-06-11 17:35:47 -07005931
Adam Powell539ee872012-02-03 19:00:49 -08005932 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
5933 // Do nothing.
5934 }
5935
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07005936 class TakenSurfaceHolder extends BaseSurfaceHolder {
5937 @Override
5938 public boolean onAllowLockCanvas() {
5939 return mDrawingAllowed;
5940 }
5941
5942 @Override
5943 public void onRelayoutContainer() {
5944 // Not currently interesting -- from changing between fixed and layout size.
5945 }
5946
5947 public void setFormat(int format) {
5948 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
5949 }
5950
5951 public void setType(int type) {
5952 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
5953 }
5954
5955 @Override
5956 public void onUpdateSurface() {
5957 // We take care of format and type changes on our own.
5958 throw new IllegalStateException("Shouldn't be here");
5959 }
5960
5961 public boolean isCreating() {
5962 return mIsCreating;
5963 }
5964
5965 @Override
5966 public void setFixedSize(int width, int height) {
5967 throw new UnsupportedOperationException(
5968 "Currently only support sizing from layout");
5969 }
5970
5971 public void setKeepScreenOn(boolean screenOn) {
5972 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
5973 }
5974 }
Romain Guy8506ab42009-06-11 17:35:47 -07005975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005976 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005977 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07005978 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005979
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005980 W(ViewRootImpl viewAncestor) {
5981 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07005982 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005983 }
5984
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005985 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -07005986 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005987 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005988 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005989 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005990 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005991 }
5992 }
5993
Craig Mautner5702d4d2012-06-30 14:10:16 -07005994 @Override
5995 public void moved(int newX, int newY) {
5996 final ViewRootImpl viewAncestor = mViewAncestor.get();
5997 if (viewAncestor != null) {
5998 viewAncestor.dispatchMoved(newX, newY);
5999 }
6000 }
6001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006002 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006003 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006004 if (viewAncestor != null) {
6005 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006006 }
6007 }
6008
Romain Guybb9908b2012-03-08 11:14:07 -08006009 public void dispatchScreenState(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -08006010 final ViewRootImpl viewAncestor = mViewAncestor.get();
6011 if (viewAncestor != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08006012 viewAncestor.dispatchScreenStateChange(on);
Romain Guy7e4e5612012-03-05 14:37:29 -08006013 }
6014 }
Romain Guybb9908b2012-03-08 11:14:07 -08006015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006016 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006017 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006018 if (viewAncestor != null) {
6019 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006020 }
6021 }
6022
6023 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006024 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006025 if (viewAncestor != null) {
6026 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006027 }
6028 }
6029
6030 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006031 try {
6032 return ActivityManagerNative.getDefault().checkPermission(
6033 permission, Binder.getCallingPid(), Binder.getCallingUid());
6034 } catch (RemoteException e) {
6035 return PackageManager.PERMISSION_DENIED;
6036 }
6037 }
6038
6039 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006040 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006041 if (viewAncestor != null) {
6042 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006043 if (view != null) {
6044 if (checkCallingPermission(Manifest.permission.DUMP) !=
6045 PackageManager.PERMISSION_GRANTED) {
6046 throw new SecurityException("Insufficient permissions to invoke"
6047 + " executeCommand() from pid=" + Binder.getCallingPid()
6048 + ", uid=" + Binder.getCallingUid());
6049 }
6050
6051 OutputStream clientStream = null;
6052 try {
6053 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6054 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6055 } catch (IOException e) {
6056 e.printStackTrace();
6057 } finally {
6058 if (clientStream != null) {
6059 try {
6060 clientStream.close();
6061 } catch (IOException e) {
6062 e.printStackTrace();
6063 }
6064 }
6065 }
6066 }
6067 }
6068 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006069
Dianne Hackbornffa42482009-09-23 22:20:11 -07006070 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006071 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006072 if (viewAncestor != null) {
6073 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006074 }
6075 }
6076
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006077 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6078 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006079 if (sync) {
6080 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006081 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006082 } catch (RemoteException e) {
6083 }
6084 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006085 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006086
Dianne Hackborn75804932009-10-20 20:15:20 -07006087 public void dispatchWallpaperCommand(String action, int x, int y,
6088 int z, Bundle extras, boolean sync) {
6089 if (sync) {
6090 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006091 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006092 } catch (RemoteException e) {
6093 }
6094 }
6095 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006096
6097 /* Drag/drop */
6098 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006099 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006100 if (viewAncestor != null) {
6101 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006102 }
6103 }
Joe Onorato664644d2011-01-23 17:53:23 -08006104
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006105 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6106 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006107 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006108 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006109 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6110 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006111 }
6112 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006113
6114 public void doneAnimating() {
6115 final ViewRootImpl viewAncestor = mViewAncestor.get();
6116 if (viewAncestor != null) {
6117 viewAncestor.dispatchDoneAnimating();
6118 }
6119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006120 }
6121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006122 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6123 public CalledFromWrongThreadException(String msg) {
6124 super(msg);
6125 }
6126 }
6127
6128 private SurfaceHolder mHolder = new SurfaceHolder() {
6129 // we only need a SurfaceHolder for opengl. it would be nice
6130 // to implement everything else though, especially the callback
6131 // support (opengl doesn't make use of it right now, but eventually
6132 // will).
6133 public Surface getSurface() {
6134 return mSurface;
6135 }
6136
6137 public boolean isCreating() {
6138 return false;
6139 }
6140
6141 public void addCallback(Callback callback) {
6142 }
6143
6144 public void removeCallback(Callback callback) {
6145 }
6146
6147 public void setFixedSize(int width, int height) {
6148 }
6149
6150 public void setSizeFromLayout() {
6151 }
6152
6153 public void setFormat(int format) {
6154 }
6155
6156 public void setType(int type) {
6157 }
6158
6159 public void setKeepScreenOn(boolean screenOn) {
6160 }
6161
6162 public Canvas lockCanvas() {
6163 return null;
6164 }
6165
6166 public Canvas lockCanvas(Rect dirty) {
6167 return null;
6168 }
6169
6170 public void unlockCanvasAndPost(Canvas canvas) {
6171 }
6172 public Rect getSurfaceFrame() {
6173 return null;
6174 }
6175 };
6176
6177 static RunQueue getRunQueue() {
6178 RunQueue rq = sRunQueues.get();
6179 if (rq != null) {
6180 return rq;
6181 }
6182 rq = new RunQueue();
6183 sRunQueues.set(rq);
6184 return rq;
6185 }
Romain Guy8506ab42009-06-11 17:35:47 -07006186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006187 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08006188 * The run queue is used to enqueue pending work from Views when no Handler is
6189 * attached. The work is executed during the next call to performTraversals on
6190 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006191 * @hide
6192 */
6193 static final class RunQueue {
6194 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
6195
6196 void post(Runnable action) {
6197 postDelayed(action, 0);
6198 }
6199
6200 void postDelayed(Runnable action, long delayMillis) {
6201 HandlerAction handlerAction = new HandlerAction();
6202 handlerAction.action = action;
6203 handlerAction.delay = delayMillis;
6204
6205 synchronized (mActions) {
6206 mActions.add(handlerAction);
6207 }
6208 }
6209
6210 void removeCallbacks(Runnable action) {
6211 final HandlerAction handlerAction = new HandlerAction();
6212 handlerAction.action = action;
6213
6214 synchronized (mActions) {
6215 final ArrayList<HandlerAction> actions = mActions;
6216
6217 while (actions.remove(handlerAction)) {
6218 // Keep going
6219 }
6220 }
6221 }
6222
6223 void executeActions(Handler handler) {
6224 synchronized (mActions) {
6225 final ArrayList<HandlerAction> actions = mActions;
6226 final int count = actions.size();
6227
6228 for (int i = 0; i < count; i++) {
6229 final HandlerAction handlerAction = actions.get(i);
6230 handler.postDelayed(handlerAction.action, handlerAction.delay);
6231 }
6232
Romain Guy15df6702009-08-17 20:17:30 -07006233 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006234 }
6235 }
6236
6237 private static class HandlerAction {
6238 Runnable action;
6239 long delay;
6240
6241 @Override
6242 public boolean equals(Object o) {
6243 if (this == o) return true;
6244 if (o == null || getClass() != o.getClass()) return false;
6245
6246 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006247 return !(action != null ? !action.equals(that.action) : that.action != null);
6248
6249 }
6250
6251 @Override
6252 public int hashCode() {
6253 int result = action != null ? action.hashCode() : 0;
6254 result = 31 * result + (int) (delay ^ (delay >>> 32));
6255 return result;
6256 }
6257 }
6258 }
6259
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006260 /**
6261 * Class for managing the accessibility interaction connection
6262 * based on the global accessibility state.
6263 */
6264 final class AccessibilityInteractionConnectionManager
6265 implements AccessibilityStateChangeListener {
6266 public void onAccessibilityStateChanged(boolean enabled) {
6267 if (enabled) {
6268 ensureConnection();
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006269 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6270 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6271 View focusedView = mView.findFocus();
6272 if (focusedView != null && focusedView != mView) {
6273 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6274 }
6275 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006276 } else {
6277 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006278 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006279 }
6280 }
6281
6282 public void ensureConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006283 if (mAttachInfo != null) {
6284 final boolean registered =
6285 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
6286 if (!registered) {
6287 mAttachInfo.mAccessibilityWindowId =
6288 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6289 new AccessibilityInteractionConnection(ViewRootImpl.this));
6290 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006291 }
6292 }
6293
6294 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006295 final boolean registered =
6296 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006297 if (registered) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006298 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006299 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6300 }
6301 }
6302 }
6303
6304 /**
6305 * This class is an interface this ViewAncestor provides to the
6306 * AccessibilityManagerService to the latter can interact with
6307 * the view hierarchy in this ViewAncestor.
6308 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006309 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006310 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006311 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006312
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006313 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6314 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006315 }
6316
Svetoslav Ganov42138042012-03-20 11:51:39 -07006317 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006318 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006319 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006320 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006321 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6322 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006323 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006324 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006325 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6326 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006327 } else {
6328 // We cannot make the call and notify the caller so it does not wait.
6329 try {
6330 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6331 } catch (RemoteException re) {
6332 /* best effort - ignore */
6333 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006334 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006335 }
6336
Svetoslav Ganov42138042012-03-20 11:51:39 -07006337 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006338 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006339 Bundle arguments, int interactionId,
6340 IAccessibilityInteractionConnectionCallback callback, int flags,
6341 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006342 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6343 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006344 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006345 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006346 interactionId, callback, flags, interogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006347 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006348 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006349 try {
6350 callback.setPerformAccessibilityActionResult(false, interactionId);
6351 } catch (RemoteException re) {
6352 /* best effort - ignore */
6353 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006354 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006355 }
6356
Svetoslav Ganov42138042012-03-20 11:51:39 -07006357 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006358 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
6359 String viewId, int interactionId,
6360 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006361 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006362 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6363 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006364 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006365 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
6366 viewId, interactionId, callback, flags, interrogatingPid,
6367 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006368 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006369 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006370 try {
6371 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6372 } catch (RemoteException re) {
6373 /* best effort - ignore */
6374 }
6375 }
6376 }
6377
Svetoslav Ganov42138042012-03-20 11:51:39 -07006378 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006379 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006380 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006381 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006382 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6383 if (viewRootImpl != null && viewRootImpl.mView != null) {
6384 viewRootImpl.getAccessibilityInteractionController()
6385 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006386 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6387 spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006388 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006389 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006390 try {
6391 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6392 } catch (RemoteException re) {
6393 /* best effort - ignore */
6394 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006395 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006396 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006397
Svetoslav Ganov42138042012-03-20 11:51:39 -07006398 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006399 public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
Svetoslav Ganov86783472012-06-06 21:12:20 -07006400 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006401 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006402 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6403 if (viewRootImpl != null && viewRootImpl.mView != null) {
6404 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006405 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006406 flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006407 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006408 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006409 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006410 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006411 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006412 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006413 }
6414 }
6415 }
6416
Svetoslav Ganov42138042012-03-20 11:51:39 -07006417 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006418 public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
Svetoslav Ganov42138042012-03-20 11:51:39 -07006419 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006420 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006421 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6422 if (viewRootImpl != null && viewRootImpl.mView != null) {
6423 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07006424 .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006425 callback, flags, interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006426 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006427 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006428 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006429 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006430 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006431 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006432 }
6433 }
6434 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006435 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006436
Svetoslav Ganova0156172011-06-26 17:55:44 -07006437 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006438 public View mSource;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006439
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006440 public void run() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006441 if (mSource != null) {
6442 mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
6443 mSource.resetAccessibilityStateChanged();
6444 mSource = null;
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006445 }
6446 }
6447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006448}