blob: ec25b64ca84b2c54599315c632c7d6246cb51409 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Romain Guy6b7bd242010-10-06 19:49:23 -070019import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070020import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070021import android.app.ActivityManagerNative;
22import android.content.ClipDescription;
23import android.content.ComponentCallbacks;
Dianne Hackbornc68c9132011-07-29 01:25:18 -070024import android.content.ComponentCallbacks2;
Romain Guy6b7bd242010-10-06 19:49:23 -070025import android.content.Context;
26import android.content.pm.PackageManager;
27import android.content.res.CompatibilityInfo;
28import android.content.res.Configuration;
29import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.graphics.Canvas;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080031import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070033import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070034import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070035import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.graphics.Rect;
37import android.graphics.Region;
Romain Guy6b7bd242010-10-06 19:49:23 -070038import android.media.AudioManager;
39import android.os.Binder;
40import android.os.Bundle;
41import android.os.Debug;
42import android.os.Handler;
43import android.os.LatencyTimer;
44import android.os.Looper;
45import android.os.Message;
46import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070048import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070049import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070050import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070052import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.util.EventLog;
Romain Guy6b7bd242010-10-06 19:49:23 -070054import android.util.Log;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070055import android.util.Pool;
56import android.util.Poolable;
57import android.util.PoolableManager;
58import android.util.Pools;
Chet Haase949dbf72010-08-11 18:41:06 -070059import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.util.SparseArray;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080061import android.util.TypedValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070063import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8bd69612011-08-23 13:40:30 -070064import android.view.accessibility.AccessibilityInteractionClient;
svetoslavganov75986cf2009-05-14 22:28:01 -070065import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070066import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
67import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganov02107852011-10-03 17:06:56 -070068import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070069import android.view.accessibility.IAccessibilityInteractionConnection;
70import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080071import android.view.animation.AccelerateDecelerateInterpolator;
72import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.view.inputmethod.InputConnection;
74import android.view.inputmethod.InputMethodManager;
75import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070076
Joe Onorato86f67862010-11-05 18:57:34 -070077import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070078import com.android.internal.view.BaseSurfaceHolder;
79import com.android.internal.view.IInputMethodCallback;
80import com.android.internal.view.IInputMethodSession;
81import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import java.io.IOException;
84import java.io.OutputStream;
Romain Guy65b345f2011-07-27 18:51:50 -070085import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070086import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import java.util.ArrayList;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070088import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090/**
91 * The top of a view hierarchy, implementing the needed protocol between View
92 * and the WindowManager. This is for the most part an internal implementation
93 * detail of {@link WindowManagerImpl}.
94 *
95 * {@hide}
96 */
Romain Guy812ccbe2010-06-01 14:07:24 -070097@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Dianne Hackborn6dd005b2011-07-18 13:22:50 -070098public final class ViewRootImpl extends Handler implements ViewParent,
Dianne Hackborn0f761d62010-11-30 22:06:10 -080099 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700100 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700102 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 /** @noinspection PointlessBooleanExpression*/
104 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
105 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800106 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
108 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
109 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
110 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700111 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700112 private static final boolean DEBUG_FPS = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 private static final boolean WATCH_POINTER = false;
114
Romain Guy59a12ca2011-06-09 17:48:21 -0700115 /**
116 * Set this system property to true to force the view hierarchy to render
117 * at 60 Hz. This can be used to measure the potential framerate.
118 */
119 private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
120
Michael Chan53071d62009-05-13 17:29:48 -0700121 private static final boolean MEASURE_LATENCY = false;
122 private static LatencyTimer lt;
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
125 * Maximum time we allow the user to roll the trackball enough to generate
126 * a key event, before resetting the counters.
127 */
128 static final int MAX_TRACKBALL_DELAY = 250;
129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 static IWindowSession sWindowSession;
131
132 static final Object mStaticInit = new Object();
133 static boolean mInitialized = false;
134
135 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
136
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800137 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
138 static boolean sFirstDrawComplete = false;
139
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800140 static final ArrayList<ComponentCallbacks> sConfigCallbacks
141 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 long mLastTrackballTime = 0;
144 final TrackballAxis mTrackballAxisX = new TrackballAxis();
145 final TrackballAxis mTrackballAxisY = new TrackballAxis();
146
Jeff Browncb1404e2011-01-15 18:14:15 -0800147 int mLastJoystickXDirection;
148 int mLastJoystickYDirection;
149 int mLastJoystickXKeyCode;
150 int mLastJoystickYKeyCode;
151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700153
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800154 final TypedValue mTmpValue = new TypedValue();
155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 final InputMethodCallback mInputMethodCallback;
157 final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
158 int mPendingEventSeq = 0;
Romain Guy8506ab42009-06-11 17:35:47 -0700159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 final Thread mThread;
161
162 final WindowLeaked mLocation;
163
164 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
165
166 final W mWindow;
167
Dianne Hackborn180c4842011-09-13 12:39:25 -0700168 final int mTargetSdkVersion;
169
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700170 int mSeq;
171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 View mView;
173 View mFocusedView;
174 View mRealFocusedView; // this is not set to null in touch mode
175 int mViewVisibility;
176 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700177 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Dianne Hackbornce418e62011-03-01 14:31:38 -0800179 // Set to true if the owner of this window is in the stopped state,
180 // so the window should no longer be active.
181 boolean mStopped = false;
182
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700183 boolean mLastInCompatMode = false;
184
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700185 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700186 BaseSurfaceHolder mSurfaceHolder;
187 boolean mIsCreating;
188 boolean mDrawingAllowed;
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 final Region mTransparentRegion;
191 final Region mPreviousTransparentRegion;
192
193 int mWidth;
194 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800195 Rect mDirty;
196 final Rect mCurrentDirty = new Rect();
197 final Rect mPreviousDirty = new Rect();
Romain Guybb93d552009-03-24 21:04:15 -0700198 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700199
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700200 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
202 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700203 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700204 InputQueue.Callback mInputQueueCallback;
205 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700206 FallbackEventHandler mFallbackEventHandler;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 final Rect mTempRect; // used in the transaction to not thrash the heap.
209 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
211 boolean mTraversalScheduled;
Jeff Brown4e91a182011-04-07 11:38:09 -0700212 long mLastTraversalFinishedTimeNanos;
213 long mLastDrawDurationNanos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 boolean mWillDrawSoon;
215 boolean mLayoutRequested;
216 boolean mFirst;
217 boolean mReportNextDraw;
218 boolean mFullRedrawNeeded;
219 boolean mNewSurfaceNeeded;
220 boolean mHasHadWindowFocus;
221 boolean mLastWasImTarget;
Chet Haase1f4786b2011-11-02 10:51:52 -0700222 InputEventMessage mPendingInputEvents = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223
224 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700225 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
227 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700228 // Surface can never be reassigned or cleared (use Surface.clear()).
229 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
231 boolean mAdded;
232 boolean mAddedTouchMode;
233
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700234 CompatibilityInfoHolder mCompatibilityInfo;
235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 /*package*/ int mAddNesting;
237
238 // These are accessed by multiple threads.
239 final Rect mWinFrame; // frame given by window manager.
240
241 final Rect mPendingVisibleInsets = new Rect();
242 final Rect mPendingContentInsets = new Rect();
243 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
244 = new ViewTreeObserver.InternalInsetsInfo();
245
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700246 final Configuration mLastConfiguration = new Configuration();
247 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700248
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800249 class ResizedInfo {
250 Rect coveredInsets;
251 Rect visibleInsets;
252 Configuration newConfig;
253 }
254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 boolean mScrollMayChange;
256 int mSoftInputMode;
257 View mLastScrolledFocus;
258 int mScrollY;
259 int mCurScrollY;
260 Scroller mScroller;
Romain Guy7d70fbf2011-05-24 17:40:25 -0700261 HardwareLayer mResizeBuffer;
262 long mResizeBufferStartTime;
263 int mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800264 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700265 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700266
Romain Guy8506ab42009-06-11 17:35:47 -0700267 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268
Christopher Tatea53146c2010-09-07 11:57:52 -0700269 /* Drag/drop */
270 ClipDescription mDragDescription;
271 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800272 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700273 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700274 final PointF mLastTouchPoint = new PointF();
Romain Guy59a12ca2011-06-09 17:48:21 -0700275
276 private boolean mProfileRendering;
277 private Thread mRenderProfiler;
278 private volatile boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700279
Chet Haase2f2022a2011-10-11 06:41:59 -0700280 // Variables to track frames per second, enabled via DEBUG_FPS flag
281 private long mFpsStartTime = -1;
282 private long mFpsPrevTime = -1;
283 private int mFpsNumFrames;
284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 /**
286 * see {@link #playSoundEffect(int)}
287 */
288 AudioManager mAudioManager;
289
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700290 final AccessibilityManager mAccessibilityManager;
291
Gilles Debunne5ac84422011-10-19 09:35:58 -0700292 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700293
294 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
295
Svetoslav Ganova0156172011-06-26 17:55:44 -0700296 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700297
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700298 private final int mDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700299
Jeff Brown21bc5c92011-02-28 18:27:14 -0800300 /**
301 * Consistency verifier for debugging purposes.
302 */
303 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
304 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
305 new InputEventConsistencyVerifier(this, 0) : null;
306
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700307 public static IWindowSession getWindowSession(Looper mainLooper) {
308 synchronized (mStaticInit) {
309 if (!mInitialized) {
310 try {
311 InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
Dianne Hackborn44bc17c2011-04-20 18:18:51 -0700312 sWindowSession = Display.getWindowManager().openSession(
313 imm.getClient(), imm.getInputContext());
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700314 mInitialized = true;
315 } catch (RemoteException e) {
316 }
317 }
318 return sWindowSession;
319 }
320 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700321
322 static final class SystemUiVisibilityInfo {
323 int seq;
324 int globalVisibility;
325 int localValue;
326 int localChanges;
327 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700328
Dianne Hackborn6dd005b2011-07-18 13:22:50 -0700329 public ViewRootImpl(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 super();
331
Romain Guy812ccbe2010-06-01 14:07:24 -0700332 if (MEASURE_LATENCY) {
333 if (lt == null) {
334 lt = new LatencyTimer(100, 1000);
335 }
Michael Chan53071d62009-05-13 17:29:48 -0700336 }
337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 // Initialize the statics when this class is first instantiated. This is
339 // done here instead of in the static block because Zygote does not
340 // allow the spawning of threads.
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700341 getWindowSession(context.getMainLooper());
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 mInputMethodCallback = new InputMethodCallback(this);
355 mViewVisibility = View.GONE;
356 mTransparentRegion = new Region();
357 mPreviousTransparentRegion = new Region();
358 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700360 mAccessibilityManager = AccessibilityManager.getInstance(context);
361 mAccessibilityInteractionConnectionManager =
362 new AccessibilityInteractionConnectionManager();
363 mAccessibilityManager.addAccessibilityStateChangeListener(
364 mAccessibilityInteractionConnectionManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
366 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700367 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700368 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Romain Guy59a12ca2011-06-09 17:48:21 -0700369 mProfileRendering = Boolean.parseBoolean(
370 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
372
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800373 public static void addFirstDrawHandler(Runnable callback) {
374 synchronized (sFirstDrawHandlers) {
375 if (!sFirstDrawComplete) {
376 sFirstDrawHandlers.add(callback);
377 }
378 }
379 }
380
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800381 public static void addConfigCallback(ComponentCallbacks callback) {
382 synchronized (sConfigCallbacks) {
383 sConfigCallbacks.add(callback);
384 }
385 }
386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 // FIXME for perf testing only
388 private boolean mProfile = false;
389
390 /**
391 * Call this to profile the next traversal call.
392 * FIXME for perf testing only. Remove eventually
393 */
394 public void profile() {
395 mProfile = true;
396 }
397
398 /**
399 * Indicates whether we are in touch mode. Calling this method triggers an IPC
400 * call and should be avoided whenever possible.
401 *
402 * @return True, if the device is in touch mode, false otherwise.
403 *
404 * @hide
405 */
406 static boolean isInTouchMode() {
407 if (mInitialized) {
408 try {
409 return sWindowSession.getInTouchMode();
410 } catch (RemoteException e) {
411 }
412 }
413 return false;
414 }
415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 /**
417 * We have one child
418 */
Romain Guye4d01122010-06-16 18:44:05 -0700419 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 synchronized (this) {
421 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700422 mView = view;
Joe Onorato86f67862010-11-05 18:57:34 -0700423 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700424 mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700425 attrs = mWindowAttributes;
Romain Guye4d01122010-06-16 18:44:05 -0700426
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700427 if (view instanceof RootViewSurfaceTaker) {
428 mSurfaceHolderCallback =
429 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
430 if (mSurfaceHolderCallback != null) {
431 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700432 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700433 }
434 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800435
Romain Guy856d4e12011-10-14 15:47:55 -0700436 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
437 mTranslator = compatibilityInfo.getTranslator();
438
Romain Guy1aec9a22011-01-05 09:37:12 -0800439 // If the application owns the surface, don't enable hardware acceleration
440 if (mSurfaceHolder == null) {
441 enableHardwareAcceleration(attrs);
442 }
443
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700444 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700445 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700446 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700447 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700448 attrs.backup();
449 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700450 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700451 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
452
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700453 if (!compatibilityInfo.supportsScreen()) {
454 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700455 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700456 }
457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 mSoftInputMode = attrs.softInputMode;
459 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700460 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700462 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700463 mAttachInfo.mApplicationScale =
464 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 if (panelParentView != null) {
466 mAttachInfo.mPanelParentWindowToken
467 = panelParentView.getApplicationWindowToken();
468 }
469 mAdded = true;
470 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 // Schedule the first layout -before- adding to the window
473 // manager, to make sure we do the relayout before receiving
474 // any other events from the system.
475 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700476 if ((mWindowAttributes.inputFeatures
477 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
478 mInputChannel = new InputChannel();
479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700481 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700482 res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700483 getHostVisibility(), mAttachInfo.mContentInsets,
484 mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 } catch (RemoteException e) {
486 mAdded = false;
487 mView = null;
488 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700489 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700490 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 unscheduleTraversals();
492 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700493 } finally {
494 if (restore) {
495 attrs.restore();
496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700498
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700499 if (mTranslator != null) {
500 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700501 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 mPendingContentInsets.set(mAttachInfo.mContentInsets);
503 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800504 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 if (res < WindowManagerImpl.ADD_OKAY) {
506 mView = null;
507 mAttachInfo.mRootView = null;
508 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700509 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 unscheduleTraversals();
511 switch (res) {
512 case WindowManagerImpl.ADD_BAD_APP_TOKEN:
513 case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
514 throw new WindowManagerImpl.BadTokenException(
515 "Unable to add window -- token " + attrs.token
516 + " is not valid; is your activity running?");
517 case WindowManagerImpl.ADD_NOT_APP_TOKEN:
518 throw new WindowManagerImpl.BadTokenException(
519 "Unable to add window -- token " + attrs.token
520 + " is not for an application");
521 case WindowManagerImpl.ADD_APP_EXITING:
522 throw new WindowManagerImpl.BadTokenException(
523 "Unable to add window -- app for token " + attrs.token
524 + " is exiting");
525 case WindowManagerImpl.ADD_DUPLICATE_ADD:
526 throw new WindowManagerImpl.BadTokenException(
527 "Unable to add window -- window " + mWindow
528 + " has already been added");
529 case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
530 // Silently ignore -- we would have just removed it
531 // right away, anyway.
532 return;
533 case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
534 throw new WindowManagerImpl.BadTokenException(
535 "Unable to add window " + mWindow +
536 " -- another window of this type already exists");
537 case WindowManagerImpl.ADD_PERMISSION_DENIED:
538 throw new WindowManagerImpl.BadTokenException(
539 "Unable to add window " + mWindow +
540 " -- permission denied for this window type");
541 }
542 throw new RuntimeException(
543 "Unable to add window -- unknown error code " + res);
544 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700545
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700546 if (view instanceof RootViewSurfaceTaker) {
547 mInputQueueCallback =
548 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
549 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700550 if (mInputChannel != null) {
551 if (mInputQueueCallback != null) {
552 mInputQueue = new InputQueue(mInputChannel);
553 mInputQueueCallback.onInputQueueCreated(mInputQueue);
554 } else {
555 InputQueue.registerInputChannel(mInputChannel, mInputHandler,
556 Looper.myQueue());
557 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700558 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 view.assignParent(this);
561 mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
562 mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700563
564 if (mAccessibilityManager.isEnabled()) {
565 mAccessibilityInteractionConnectionManager.ensureConnection();
566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568 }
569 }
570
Romain Guy6d7475d2011-07-27 16:28:21 -0700571 private void destroyHardwareResources() {
Romain Guy65b345f2011-07-27 18:51:50 -0700572 if (mAttachInfo.mHardwareRenderer != null) {
573 if (mAttachInfo.mHardwareRenderer.isEnabled()) {
574 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
575 }
576 mAttachInfo.mHardwareRenderer.destroy(false);
Romain Guy6d7475d2011-07-27 16:28:21 -0700577 }
Romain Guy65b345f2011-07-27 18:51:50 -0700578 }
579
580 void destroyHardwareLayers() {
581 if (mThread != Thread.currentThread()) {
582 if (mAttachInfo.mHardwareRenderer != null &&
583 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700584 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700585 }
586 } else {
587 if (mAttachInfo.mHardwareRenderer != null &&
588 mAttachInfo.mHardwareRenderer.isEnabled()) {
589 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
590 }
591 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700592 }
593
Romain Guy529b60a2010-08-03 18:05:47 -0700594 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800595 mAttachInfo.mHardwareAccelerated = false;
596 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800597
Romain Guy856d4e12011-10-14 15:47:55 -0700598 // Don't enable hardware acceleration when the application is in compatibility mode
599 if (mTranslator != null) return;
600
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800601 // Try to enable hardware acceleration if requested
Jim Miller1b365922011-03-09 19:38:07 -0800602 final boolean hardwareAccelerated =
603 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
604
Romain Guy566c3312011-03-21 18:21:28 -0700605 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700606 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700607 return;
608 }
609
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700610 // Persistent processes (including the system) should not do
611 // accelerated rendering on low-end devices. In that case,
612 // sRendererDisabled will be set. In addition, the system process
613 // itself should never do accelerated rendering. In that case, both
614 // sRendererDisabled and sSystemRendererDisabled are set. When
615 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
616 // can be used by code on the system process to escape that and enable
617 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800618
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700619 final boolean fakeHwAccelerated = (attrs.privateFlags &
620 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
621 final boolean forceHwAccelerated = (attrs.privateFlags &
622 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800623
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700624 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
625 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800626 // Don't enable hardware acceleration when we're not on the main thread
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700627 if (!HardwareRenderer.sSystemRendererDisabled
628 && Looper.getMainLooper() != Looper.myLooper()) {
Jim Miller1b365922011-03-09 19:38:07 -0800629 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800630 + "acceleration outside of the main thread, aborting");
631 return;
632 }
633
Romain Guye4d01122010-06-16 18:44:05 -0700634 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700635 if (mAttachInfo.mHardwareRenderer != null) {
636 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy4caa4ed2010-08-25 14:46:24 -0700637 }
Romain Guyb051e892010-09-28 19:09:36 -0700638 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800639 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
640 = mAttachInfo.mHardwareRenderer != null;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700641 } else if (fakeHwAccelerated) {
642 // The window had wanted to use hardware acceleration, but this
643 // is not allowed in its process. By setting this flag, it can
644 // still render as if it was accelerated. This is basically for
645 // the preview windows the window manager shows for launching
646 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700647 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700648 }
649 }
650 }
651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 public View getView() {
653 return mView;
654 }
655
656 final WindowLeaked getLocation() {
657 return mLocation;
658 }
659
660 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
661 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700662 int oldSoftInputMode = mWindowAttributes.softInputMode;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700663 // preserve compatible window flag if exists.
664 int compatibleWindowFlag =
665 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Romain Guyf21c9b02011-09-06 16:56:54 -0700666 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700667 mWindowAttributes.flags |= compatibleWindowFlag;
668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 if (newView) {
670 mSoftInputMode = attrs.softInputMode;
671 requestLayout();
672 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700673 // Don't lose the mode we last auto-computed.
674 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
675 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
676 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
677 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
678 | (oldSoftInputMode
679 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 mWindowAttributesChanged = true;
682 scheduleTraversals();
683 }
684 }
685
686 void handleAppVisibility(boolean visible) {
687 if (mAppVisible != visible) {
688 mAppVisible = visible;
689 scheduleTraversals();
690 }
691 }
692
693 void handleGetNewSurface() {
694 mNewSurfaceNeeded = true;
695 mFullRedrawNeeded = true;
696 scheduleTraversals();
697 }
698
699 /**
700 * {@inheritDoc}
701 */
702 public void requestLayout() {
703 checkThread();
704 mLayoutRequested = true;
705 scheduleTraversals();
706 }
707
708 /**
709 * {@inheritDoc}
710 */
711 public boolean isLayoutRequested() {
712 return mLayoutRequested;
713 }
714
715 public void invalidateChild(View child, Rect dirty) {
716 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700717 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Chet Haase70d4ba12010-10-06 09:46:45 -0700718 if (dirty == null) {
719 // Fast invalidation for GL-enabled applications; GL must redraw everything
720 invalidate();
721 return;
722 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700723 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700725 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700726 if (mCurScrollY != 0) {
Romain Guy1e095972009-07-07 11:22:45 -0700727 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700728 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700729 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700730 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700731 }
Romain Guy1e095972009-07-07 11:22:45 -0700732 if (mAttachInfo.mScalingRequired) {
733 dirty.inset(-1, -1);
734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 }
Chet Haasedaf98e92011-01-10 14:10:36 -0800736 if (!mDirty.isEmpty() && !mDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700737 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800738 mAttachInfo.mIgnoreDirtyState = true;
739 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 mDirty.union(dirty);
741 if (!mWillDrawSoon) {
742 scheduleTraversals();
743 }
744 }
Romain Guy0d9275e2010-10-26 14:22:30 -0700745
746 void invalidate() {
747 mDirty.set(0, 0, mWidth, mHeight);
748 scheduleTraversals();
749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750
Dianne Hackbornce418e62011-03-01 14:31:38 -0800751 void setStopped(boolean stopped) {
752 if (mStopped != stopped) {
753 mStopped = stopped;
754 if (!stopped) {
755 scheduleTraversals();
756 }
757 }
758 }
759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 public ViewParent getParent() {
761 return null;
762 }
763
764 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
765 invalidateChild(null, dirty);
766 return null;
767 }
768
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700769 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 if (child != mView) {
771 throw new RuntimeException("child is not mine, honest!");
772 }
773 // Note: don't apply scroll offset, because we want to know its
774 // visibility in the virtual canvas being given to the view hierarchy.
775 return r.intersect(0, 0, mWidth, mHeight);
776 }
777
778 public void bringChildToFront(View child) {
779 }
780
781 public void scheduleTraversals() {
782 if (!mTraversalScheduled) {
783 mTraversalScheduled = true;
Jeff Brown4e91a182011-04-07 11:38:09 -0700784
Romain Guy1c90f032011-05-24 14:59:50 -0700785 //noinspection ConstantConditions
Jeff Brown4e91a182011-04-07 11:38:09 -0700786 if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) {
787 final long now = System.nanoTime();
788 Log.d(TAG, "Latency: Scheduled traversal, it has been "
789 + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f)
790 + "ms since the last traversal finished.");
791 }
792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 sendEmptyMessage(DO_TRAVERSAL);
794 }
795 }
796
797 public void unscheduleTraversals() {
798 if (mTraversalScheduled) {
799 mTraversalScheduled = false;
800 removeMessages(DO_TRAVERSAL);
801 }
802 }
803
804 int getHostVisibility() {
805 return mAppVisible ? mView.getVisibility() : View.GONE;
806 }
Romain Guy8506ab42009-06-11 17:35:47 -0700807
Romain Guy7d70fbf2011-05-24 17:40:25 -0700808 void disposeResizeBuffer() {
809 if (mResizeBuffer != null) {
810 mResizeBuffer.destroy();
811 mResizeBuffer = null;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800812 }
813 }
814
Chet Haasecca2c982011-05-20 14:34:18 -0700815 /**
816 * Add LayoutTransition to the list of transitions to be started in the next traversal.
817 * This list will be cleared after the transitions on the list are start()'ed. These
818 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
819 * happens during the layout phase of traversal, which we want to complete before any of the
820 * animations are started (because those animations may side-effect properties that layout
821 * depends upon, like the bounding rectangles of the affected views). So we add the transition
822 * to the list and it is started just prior to starting the drawing phase of traversal.
823 *
824 * @param transition The LayoutTransition to be started on the next traversal.
825 *
826 * @hide
827 */
828 public void requestTransitionStart(LayoutTransition transition) {
829 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
830 if (mPendingTransitions == null) {
831 mPendingTransitions = new ArrayList<LayoutTransition>();
832 }
833 mPendingTransitions.add(transition);
834 }
835 }
836
Chet Haase1f4786b2011-11-02 10:51:52 -0700837 private void processInputEvents(boolean outOfOrder) {
838 while (mPendingInputEvents != null) {
839 handleMessage(mPendingInputEvents.mMessage);
840 InputEventMessage tmpMessage = mPendingInputEvents;
841 mPendingInputEvents = mPendingInputEvents.mNext;
842 tmpMessage.recycle();
843 if (outOfOrder) {
844 removeMessages(PROCESS_INPUT_EVENTS);
845 }
846 }
847 }
848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 private void performTraversals() {
850 // cache mView since it is used so much below...
851 final View host = mView;
852
Chet Haase1f4786b2011-11-02 10:51:52 -0700853 processInputEvents(true);
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 if (DBG) {
856 System.out.println("======================================");
857 System.out.println("performTraversals");
858 host.debug();
859 }
860
861 if (host == null || !mAdded)
862 return;
863
864 mTraversalScheduled = false;
865 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800866 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 boolean fullRedrawNeeded = mFullRedrawNeeded;
868 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700869 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 WindowManager.LayoutParams lp = mWindowAttributes;
871
872 int desiredWindowWidth;
873 int desiredWindowHeight;
874 int childWidthMeasureSpec;
875 int childHeightMeasureSpec;
876
877 final View.AttachInfo attachInfo = mAttachInfo;
878
879 final int viewVisibility = getHostVisibility();
880 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
881 || mNewSurfaceNeeded;
882
883 WindowManager.LayoutParams params = null;
Romain Guyf21c9b02011-09-06 16:56:54 -0700884 int windowAttributesChanges = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 if (mWindowAttributesChanged) {
886 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700887 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 params = lp;
Romain Guyf21c9b02011-09-06 16:56:54 -0700889 windowAttributesChanges = mWindowAttributesChangesFlag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700891 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
892 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
893 params = lp;
894 fullRedrawNeeded = true;
895 mLayoutRequested = true;
896 if (mLastInCompatMode) {
897 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
898 mLastInCompatMode = false;
899 } else {
900 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
901 mLastInCompatMode = true;
902 }
903 }
Romain Guyf21c9b02011-09-06 16:56:54 -0700904
905 mWindowAttributesChangesFlag = 0;
906
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700907 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 if (mFirst) {
909 fullRedrawNeeded = true;
910 mLayoutRequested = true;
911
Dianne Hackborna239c842011-06-01 12:28:20 -0700912 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
913 // NOTE -- system code, won't try to do compat mode.
914 Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
Jeff Brownbc68a592011-07-25 12:58:12 -0700915 Point size = new Point();
916 disp.getRealSize(size);
917 desiredWindowWidth = size.x;
918 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -0700919 } else {
920 DisplayMetrics packageMetrics =
921 mView.getContext().getResources().getDisplayMetrics();
922 desiredWindowWidth = packageMetrics.widthPixels;
923 desiredWindowHeight = packageMetrics.heightPixels;
924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925
926 // For the very first time, tell the view hierarchy that it
927 // is attached to the window. Note that at this point the surface
928 // object is not initialized to its backing store, but soon it
929 // will be (assuming the window is visible).
930 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -0800931 // We used to use the following condition to choose 32 bits drawing caches:
932 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
933 // However, windows are now always 32 bits by default, so choose 32 bits
934 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 attachInfo.mHasWindowFocus = false;
936 attachInfo.mWindowVisibility = viewVisibility;
937 attachInfo.mRecomputeGlobalAttributes = false;
938 attachInfo.mKeepScreenOn = false;
Joe Onorato664644d2011-01-23 17:53:23 -0800939 attachInfo.mSystemUiVisibility = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700941 mLastConfiguration.setTo(host.getResources().getConfiguration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 host.dispatchAttachedToWindow(attachInfo, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -0700944
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -0700945 host.fitSystemWindows(mAttachInfo.mContentInsets);
946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700948 desiredWindowWidth = frame.width();
949 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700951 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700952 "View " + host + " resized to: " + frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 fullRedrawNeeded = true;
954 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800955 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957 }
958
959 if (viewVisibilityChanged) {
960 attachInfo.mWindowVisibility = viewVisibility;
961 host.dispatchWindowVisibilityChanged(viewVisibility);
962 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -0700963 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 }
965 if (viewVisibility == View.GONE) {
966 // After making a window gone, we will count it as being
967 // shown for the first time the next time it gets focus.
968 mHasHadWindowFocus = false;
969 }
970 }
971
972 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -0700973
Dianne Hackbornce418e62011-03-01 14:31:38 -0800974 if (mLayoutRequested && !mStopped) {
Romain Guy15df6702009-08-17 20:17:30 -0700975 // Execute enqueued actions on every layout in case a view that was detached
976 // enqueued an action after being detached
977 getRunQueue().executeActions(attachInfo.mHandler);
978
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800979 final Resources res = mView.getContext().getResources();
980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 // make sure touch mode code executes by setting cached value
983 // to opposite of the added touch mode.
984 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -0700985 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 } else {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -0700987 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -0700990 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
992 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
993 + mAttachInfo.mVisibleInsets);
994 }
995 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
996 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800997 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998
Dianne Hackborna239c842011-06-01 12:28:20 -0700999 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1000 // NOTE -- system code, won't try to do compat mode.
1001 Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
Jeff Brownbc68a592011-07-25 12:58:12 -07001002 Point size = new Point();
1003 disp.getRealSize(size);
1004 desiredWindowWidth = size.x;
1005 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001006 } else {
1007 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1008 desiredWindowWidth = packageMetrics.widthPixels;
1009 desiredWindowHeight = packageMetrics.heightPixels;
1010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 }
1012 }
1013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 // Ask host how big it wants to be
Jeff Brownc5ed5912010-07-14 18:48:53 -07001015 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 "Measuring " + host + " in display " + desiredWindowWidth
1017 + "x" + desiredWindowHeight + "...");
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001018
1019 boolean goodMeasure = false;
Adam Powella3e3c532011-06-22 11:21:54 -07001020 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001021 // On large screens, we don't want to allow dialogs to just
1022 // stretch to fill the entire width of the screen to display
1023 // one line of text. First try doing the layout at a smaller
1024 // size to see if it will fit.
1025 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1026 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1027 int baseSize = 0;
1028 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1029 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1030 }
1031 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001032 if (baseSize != 0 && desiredWindowWidth > baseSize) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001033 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1034 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
1035 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1036 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
Dianne Hackborn189ee182010-12-02 21:48:53 -08001037 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1038 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001039 goodMeasure = true;
1040 } else {
1041 // Didn't fit in that size... try expanding a bit.
1042 baseSize = (baseSize+desiredWindowWidth)/2;
1043 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1044 + baseSize);
Dianne Hackborn189ee182010-12-02 21:48:53 -08001045 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001046 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1047 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
Dianne Hackborn189ee182010-12-02 21:48:53 -08001048 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1049 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001050 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1051 goodMeasure = true;
1052 }
1053 }
1054 }
1055 }
1056
1057 if (!goodMeasure) {
1058 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1059 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
1060 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Adam Powellaa0b92c2010-12-13 22:38:53 -08001061 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1062 windowSizeMayChange = true;
1063 }
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065
1066 if (DBG) {
1067 System.out.println("======================================");
1068 System.out.println("performTraversals -- after measure");
1069 host.debug();
1070 }
1071 }
1072
Romain Guy6e81e572011-01-25 12:52:58 -08001073 if (attachInfo.mRecomputeGlobalAttributes && host.mAttachInfo != null) {
Joe Onorato664644d2011-01-23 17:53:23 -08001074 //Log.i(TAG, "Computing view hierarchy attributes!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 attachInfo.mRecomputeGlobalAttributes = false;
Joe Onorato664644d2011-01-23 17:53:23 -08001076 boolean oldScreenOn = attachInfo.mKeepScreenOn;
1077 int oldVis = attachInfo.mSystemUiVisibility;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001078 boolean oldHasSystemUiListeners = attachInfo.mHasSystemUiListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 attachInfo.mKeepScreenOn = false;
Joe Onorato664644d2011-01-23 17:53:23 -08001080 attachInfo.mSystemUiVisibility = 0;
1081 attachInfo.mHasSystemUiListeners = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 host.dispatchCollectViewAttributes(0);
Joe Onorato14782f72011-01-25 19:53:17 -08001083 if (attachInfo.mKeepScreenOn != oldScreenOn
1084 || attachInfo.mSystemUiVisibility != oldVis
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001085 || attachInfo.mHasSystemUiListeners != oldHasSystemUiListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 }
1088 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001089 if (attachInfo.mForceReportNewAttributes) {
1090 attachInfo.mForceReportNewAttributes = false;
1091 params = lp;
1092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093
1094 if (mFirst || attachInfo.mViewVisibilityChanged) {
1095 attachInfo.mViewVisibilityChanged = false;
1096 int resizeMode = mSoftInputMode &
1097 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1098 // If we are in auto resize mode, then we need to determine
1099 // what mode to use now.
1100 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1101 final int N = attachInfo.mScrollContainers.size();
1102 for (int i=0; i<N; i++) {
1103 if (attachInfo.mScrollContainers.get(i).isShown()) {
1104 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1105 }
1106 }
1107 if (resizeMode == 0) {
1108 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1109 }
1110 if ((lp.softInputMode &
1111 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1112 lp.softInputMode = (lp.softInputMode &
1113 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1114 resizeMode;
1115 params = lp;
1116 }
1117 }
1118 }
Romain Guy8506ab42009-06-11 17:35:47 -07001119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
1121 if (!PixelFormat.formatHasAlpha(params.format)) {
1122 params.format = PixelFormat.TRANSLUCENT;
1123 }
1124 }
1125
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001126 boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001127 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001128 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1129 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1130 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1131 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132
1133 final boolean computesInternalInsets =
1134 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
Romain Guy812ccbe2010-06-01 14:07:24 -07001135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 boolean insetsPending = false;
1137 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001138
1139 if (mFirst || windowShouldResize || insetsChanged ||
1140 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141
1142 if (viewVisibility == View.VISIBLE) {
1143 // If this window is giving internal insets to the window
1144 // manager, and it is being added or changing its visibility,
1145 // then we want to first give the window manager "fake"
1146 // insets to cause it to effectively ignore the content of
1147 // the window during layout. This avoids it briefly causing
1148 // other windows to resize/move based on the raw frame of the
1149 // window, waiting until we can finish laying out this window
1150 // and get back to the window manager with the ultimately
1151 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001152 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 }
1154
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001155 if (mSurfaceHolder != null) {
1156 mSurfaceHolder.mSurfaceLock.lock();
1157 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001158 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001159
Romain Guyc361da82010-10-25 15:29:10 -07001160 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 boolean contentInsetsChanged = false;
Romain Guy13922e02009-05-12 17:56:14 -07001162 boolean visibleInsetsChanged;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001163 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 int fl = 0;
1167 if (params != null) {
1168 fl = params.flags;
1169 if (attachInfo.mKeepScreenOn) {
1170 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1171 }
Joe Onorato14782f72011-01-25 19:53:17 -08001172 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001173 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001175 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001176 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1177 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001178 }
Romain Guy2a83f002011-01-18 18:28:21 -08001179
1180 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001181 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 if (params != null) {
1184 params.flags = fl;
1185 }
1186
1187 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
1188 + " content=" + mPendingContentInsets.toShortString()
1189 + " visible=" + mPendingVisibleInsets.toShortString()
1190 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001191
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001192 if (mPendingConfiguration.seq != 0) {
1193 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1194 + mPendingConfiguration);
1195 updateConfiguration(mPendingConfiguration, !mFirst);
1196 mPendingConfiguration.seq = 0;
1197 }
1198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 contentInsetsChanged = !mPendingContentInsets.equals(
1200 mAttachInfo.mContentInsets);
1201 visibleInsetsChanged = !mPendingVisibleInsets.equals(
1202 mAttachInfo.mVisibleInsets);
1203 if (contentInsetsChanged) {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001204 if (mWidth > 0 && mHeight > 0 &&
1205 mSurface != null && mSurface.isValid() &&
1206 !mAttachInfo.mTurnOffWindowResizeAnim &&
1207 mAttachInfo.mHardwareRenderer != null &&
1208 mAttachInfo.mHardwareRenderer.isEnabled() &&
1209 mAttachInfo.mHardwareRenderer.validate() &&
1210 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1211
1212 disposeResizeBuffer();
1213
1214 boolean completed = false;
1215 HardwareCanvas canvas = null;
1216 try {
1217 if (mResizeBuffer == null) {
1218 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1219 mWidth, mHeight, false);
1220 } else if (mResizeBuffer.getWidth() != mWidth ||
1221 mResizeBuffer.getHeight() != mHeight) {
1222 mResizeBuffer.resize(mWidth, mHeight);
1223 }
1224 canvas = mResizeBuffer.start(mAttachInfo.mHardwareCanvas);
1225 canvas.setViewport(mWidth, mHeight);
1226 canvas.onPreDraw(null);
1227 final int restoreCount = canvas.save();
1228
1229 canvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
1230
1231 int yoff;
1232 final boolean scrolling = mScroller != null
1233 && mScroller.computeScrollOffset();
1234 if (scrolling) {
1235 yoff = mScroller.getCurrY();
1236 mScroller.abortAnimation();
1237 } else {
1238 yoff = mScrollY;
1239 }
1240
1241 canvas.translate(0, -yoff);
1242 if (mTranslator != null) {
1243 mTranslator.translateCanvas(canvas);
1244 }
1245
1246 mView.draw(canvas);
1247
1248 mResizeBufferStartTime = SystemClock.uptimeMillis();
1249 mResizeBufferDuration = mView.getResources().getInteger(
1250 com.android.internal.R.integer.config_mediumAnimTime);
1251 completed = true;
1252
1253 canvas.restoreToCount(restoreCount);
1254 } catch (OutOfMemoryError e) {
1255 Log.w(TAG, "Not enough memory for content change anim buffer", e);
1256 } finally {
1257 if (canvas != null) {
1258 canvas.onPostDraw();
1259 }
1260 if (mResizeBuffer != null) {
1261 mResizeBuffer.end(mAttachInfo.mHardwareCanvas);
1262 if (!completed) {
1263 mResizeBuffer.destroy();
1264 mResizeBuffer = null;
1265 }
1266 }
1267 }
1268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 mAttachInfo.mContentInsets.set(mPendingContentInsets);
1270 host.fitSystemWindows(mAttachInfo.mContentInsets);
1271 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1272 + mAttachInfo.mContentInsets);
1273 }
1274 if (visibleInsetsChanged) {
1275 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1276 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1277 + mAttachInfo.mVisibleInsets);
1278 }
1279
1280 if (!hadSurface) {
1281 if (mSurface.isValid()) {
1282 // If we are creating a new surface, then we need to
1283 // completely redraw it. Also, when we get to the
1284 // point of drawing it we will hold off and schedule
1285 // a new traversal instead. This is so we can tell the
1286 // window manager about all of the windows being displayed
1287 // before actually drawing them, so it can display then
1288 // all at once.
1289 newSurface = true;
1290 fullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001291 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001292
Romain Guyb051e892010-09-28 19:09:36 -07001293 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001294 try {
1295 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
1296 } catch (Surface.OutOfResourcesException e) {
1297 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1298 try {
1299 if (!sWindowSession.outOfMemory(mWindow)) {
1300 Slog.w(TAG, "No processes killed for memory; killing self");
1301 Process.killProcess(Process.myPid());
1302 }
1303 } catch (RemoteException ex) {
1304 }
1305 mLayoutRequested = true; // ask wm for a new surface next time.
1306 return;
1307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 }
1309 }
1310 } else if (!mSurface.isValid()) {
1311 // If the surface has been removed, then reset the scroll
1312 // positions.
1313 mLastScrolledFocus = null;
1314 mScrollY = mCurScrollY = 0;
1315 if (mScroller != null) {
1316 mScroller.abortAnimation();
1317 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001318 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001319 // Our surface is gone
1320 if (mAttachInfo.mHardwareRenderer != null &&
1321 mAttachInfo.mHardwareRenderer.isEnabled()) {
1322 mAttachInfo.mHardwareRenderer.destroy(true);
1323 }
Romain Guy2a83f002011-01-18 18:28:21 -08001324 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1325 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001326 fullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001327 try {
1328 mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
1329 } catch (Surface.OutOfResourcesException e) {
1330 Log.e(TAG, "OutOfResourcesException updating HW surface", e);
1331 try {
1332 if (!sWindowSession.outOfMemory(mWindow)) {
1333 Slog.w(TAG, "No processes killed for memory; killing self");
1334 Process.killProcess(Process.myPid());
1335 }
1336 } catch (RemoteException ex) {
1337 }
1338 mLayoutRequested = true; // ask wm for a new surface next time.
1339 return;
1340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 }
1342 } catch (RemoteException e) {
1343 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001346 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347
1348 attachInfo.mWindowLeft = frame.left;
1349 attachInfo.mWindowTop = frame.top;
1350
1351 // !!FIXME!! This next section handles the case where we did not get the
1352 // window size we asked for. We should avoid this by getting a maximum size from
1353 // the window session beforehand.
1354 mWidth = frame.width();
1355 mHeight = frame.height();
1356
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001357 if (mSurfaceHolder != null) {
1358 // The app owns the surface; tell it about what is going on.
1359 if (mSurface.isValid()) {
1360 // XXX .copyFrom() doesn't work!
1361 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1362 mSurfaceHolder.mSurface = mSurface;
1363 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001364 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001365 mSurfaceHolder.mSurfaceLock.unlock();
1366 if (mSurface.isValid()) {
1367 if (!hadSurface) {
1368 mSurfaceHolder.ungetCallbacks();
1369
1370 mIsCreating = true;
1371 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1372 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1373 if (callbacks != null) {
1374 for (SurfaceHolder.Callback c : callbacks) {
1375 c.surfaceCreated(mSurfaceHolder);
1376 }
1377 }
1378 surfaceChanged = true;
1379 }
1380 if (surfaceChanged) {
1381 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1382 lp.format, mWidth, mHeight);
1383 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1384 if (callbacks != null) {
1385 for (SurfaceHolder.Callback c : callbacks) {
1386 c.surfaceChanged(mSurfaceHolder, lp.format,
1387 mWidth, mHeight);
1388 }
1389 }
1390 }
1391 mIsCreating = false;
1392 } else if (hadSurface) {
1393 mSurfaceHolder.ungetCallbacks();
1394 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1395 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1396 if (callbacks != null) {
1397 for (SurfaceHolder.Callback c : callbacks) {
1398 c.surfaceDestroyed(mSurfaceHolder);
1399 }
1400 }
1401 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001402 try {
1403 mSurfaceHolder.mSurface = new Surface();
1404 } finally {
1405 mSurfaceHolder.mSurfaceLock.unlock();
1406 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001407 }
1408 }
Romain Guy53389bd2010-09-07 17:16:32 -07001409
Chet Haase40e03832011-10-06 08:34:13 -07001410 if (mAttachInfo.mHardwareRenderer != null &&
1411 mAttachInfo.mHardwareRenderer.isEnabled()) {
1412 if (hwInitialized || windowShouldResize ||
1413 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1414 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1415 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1416 if (!hwInitialized) {
1417 mAttachInfo.mHardwareRenderer.invalidate(mHolder);
1418 }
Romain Guy03985752011-07-11 15:33:51 -07001419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 }
1421
Dianne Hackbornce418e62011-03-01 14:31:38 -08001422 if (!mStopped) {
1423 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
1424 (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
1425 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1426 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
1427 childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1428 childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
1429
1430 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1431 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1432 + " mHeight=" + mHeight
1433 + " measuredHeight=" + host.getMeasuredHeight()
1434 + " coveredInsetsChanged=" + contentInsetsChanged);
1435
1436 // Ask host how big it wants to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001438
1439 // Implementation of weights from WindowManager.LayoutParams
1440 // We just grow the dimensions as needed and re-measure if
1441 // needs be
1442 int width = host.getMeasuredWidth();
1443 int height = host.getMeasuredHeight();
1444 boolean measureAgain = false;
1445
1446 if (lp.horizontalWeight > 0.0f) {
1447 width += (int) ((mWidth - width) * lp.horizontalWeight);
1448 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1449 MeasureSpec.EXACTLY);
1450 measureAgain = true;
1451 }
1452 if (lp.verticalWeight > 0.0f) {
1453 height += (int) ((mHeight - height) * lp.verticalWeight);
1454 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1455 MeasureSpec.EXACTLY);
1456 measureAgain = true;
1457 }
1458
1459 if (measureAgain) {
1460 if (DEBUG_LAYOUT) Log.v(TAG,
1461 "And hey let's measure once more: width=" + width
1462 + " height=" + height);
1463 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1464 }
1465
1466 mLayoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 }
1469 }
1470
Dianne Hackbornce418e62011-03-01 14:31:38 -08001471 final boolean didLayout = mLayoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 boolean triggerGlobalLayoutListener = didLayout
1473 || attachInfo.mRecomputeGlobalAttributes;
1474 if (didLayout) {
1475 mLayoutRequested = false;
1476 mScrollMayChange = true;
1477 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001478 TAG, "Laying out " + host + " to (" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08001479 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
Romain Guy13922e02009-05-12 17:56:14 -07001480 long startTime = 0L;
Romain Guy5429e1d2010-09-07 12:38:00 -07001481 if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 startTime = SystemClock.elapsedRealtime();
1483 }
Dianne Hackborn189ee182010-12-02 21:48:53 -08001484 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485
Joe Onorato43a17652011-04-06 19:22:23 -07001486 if (false && ViewDebug.consistencyCheckEnabled) {
Romain Guy13922e02009-05-12 17:56:14 -07001487 if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
1488 throw new IllegalStateException("The view hierarchy is an inconsistent state,"
1489 + "please refer to the logs with the tag "
1490 + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
1491 }
1492 }
1493
Romain Guy5429e1d2010-09-07 12:38:00 -07001494 if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
1496 }
1497
1498 // By this point all views have been sized and positionned
1499 // We can compute the transparent area
1500
1501 if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
1502 // start out transparent
1503 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1504 host.getLocationInWindow(mTmpLocation);
1505 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1506 mTmpLocation[0] + host.mRight - host.mLeft,
1507 mTmpLocation[1] + host.mBottom - host.mTop);
1508
1509 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001510 if (mTranslator != null) {
1511 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1512 }
1513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1515 mPreviousTransparentRegion.set(mTransparentRegion);
1516 // reconfigure window manager
1517 try {
1518 sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
1519 } catch (RemoteException e) {
1520 }
1521 }
1522 }
1523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 if (DBG) {
1525 System.out.println("======================================");
1526 System.out.println("performTraversals -- after setFrame");
1527 host.debug();
1528 }
1529 }
1530
1531 if (triggerGlobalLayoutListener) {
1532 attachInfo.mRecomputeGlobalAttributes = false;
1533 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001534
1535 if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
1536 postSendWindowContentChangedCallback();
1537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 }
1539
1540 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001541 // Clear the original insets.
1542 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1543 insets.reset();
1544
1545 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001547
1548 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1550 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001551
1552 // Translate insets to screen coordinates if needed.
1553 final Rect contentInsets;
1554 final Rect visibleInsets;
1555 final Region touchableRegion;
1556 if (mTranslator != null) {
1557 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1558 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1559 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1560 } else {
1561 contentInsets = insets.contentInsets;
1562 visibleInsets = insets.visibleInsets;
1563 touchableRegion = insets.touchableRegion;
1564 }
1565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 try {
1567 sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001568 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 } catch (RemoteException e) {
1570 }
1571 }
1572 }
Romain Guy8506ab42009-06-11 17:35:47 -07001573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 if (mFirst) {
1575 // handle first focus request
1576 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1577 + mView.hasFocus());
1578 if (mView != null) {
1579 if (!mView.hasFocus()) {
1580 mView.requestFocus(View.FOCUS_FORWARD);
1581 mFocusedView = mRealFocusedView = mView.findFocus();
1582 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
1583 + mFocusedView);
1584 } else {
1585 mRealFocusedView = mView.findFocus();
1586 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
1587 + mRealFocusedView);
1588 }
1589 }
1590 }
1591
1592 mFirst = false;
1593 mWillDrawSoon = false;
1594 mNewSurfaceNeeded = false;
1595 mViewVisibility = viewVisibility;
1596
1597 if (mAttachInfo.mHasWindowFocus) {
1598 final boolean imTarget = WindowManager.LayoutParams
1599 .mayUseInputMethod(mWindowAttributes.flags);
1600 if (imTarget != mLastWasImTarget) {
1601 mLastWasImTarget = imTarget;
1602 InputMethodManager imm = InputMethodManager.peekInstance();
1603 if (imm != null && imTarget) {
1604 imm.startGettingWindowFocus(mView);
1605 imm.onWindowFocus(mView, mView.findFocus(),
1606 mWindowAttributes.softInputMode,
1607 !mHasHadWindowFocus, mWindowAttributes.flags);
1608 }
1609 }
1610 }
Romain Guy8506ab42009-06-11 17:35:47 -07001611
Romain Guyea835032011-07-28 19:24:37 -07001612 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1613 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614
Chet Haase61158c62011-09-06 22:19:45 -07001615 if (!cancelDraw && !newSurface) {
Chet Haased56c6952011-09-07 08:46:23 -07001616 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1617 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1618 mPendingTransitions.get(i).startChangingAnimations();
1619 }
1620 mPendingTransitions.clear();
1621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 mFullRedrawNeeded = false;
Jeff Brown4e91a182011-04-07 11:38:09 -07001623
1624 final long drawStartTime;
1625 if (ViewDebug.DEBUG_LATENCY) {
1626 drawStartTime = System.nanoTime();
1627 }
1628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 draw(fullRedrawNeeded);
1630
Jeff Brown4e91a182011-04-07 11:38:09 -07001631 if (ViewDebug.DEBUG_LATENCY) {
1632 mLastDrawDurationNanos = System.nanoTime() - drawStartTime;
1633 }
1634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
1636 || mReportNextDraw) {
1637 if (LOCAL_LOGV) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001638 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 }
1640 mReportNextDraw = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001641 if (mSurfaceHolder != null && mSurface.isValid()) {
1642 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
1643 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1644 if (callbacks != null) {
1645 for (SurfaceHolder.Callback c : callbacks) {
1646 if (c instanceof SurfaceHolder.Callback2) {
1647 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
1648 mSurfaceHolder);
1649 }
1650 }
1651 }
1652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 try {
1654 sWindowSession.finishDrawing(mWindow);
1655 } catch (RemoteException e) {
1656 }
1657 }
1658 } else {
Chet Haased56c6952011-09-07 08:46:23 -07001659 // End any pending transitions on this non-visible window
1660 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1661 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1662 mPendingTransitions.get(i).endChangingAnimations();
1663 }
1664 mPendingTransitions.clear();
1665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 // We were supposed to report when we are done drawing. Since we canceled the
1667 // draw, remember it here.
1668 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
1669 mReportNextDraw = true;
1670 }
1671 if (fullRedrawNeeded) {
1672 mFullRedrawNeeded = true;
1673 }
Chet Haase61158c62011-09-06 22:19:45 -07001674
Romain Guyea835032011-07-28 19:24:37 -07001675 if (viewVisibility == View.VISIBLE) {
1676 // Try again
1677 scheduleTraversals();
1678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 }
1680 }
1681
1682 public void requestTransparentRegion(View child) {
1683 // the test below should not fail unless someone is messing with us
1684 checkThread();
1685 if (mView == child) {
1686 mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
1687 // Need to make sure we re-evaluate the window attributes next
1688 // time around, to ensure the window has the correct format.
1689 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07001690 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07001691 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693 }
1694
1695 /**
1696 * Figures out the measure spec for the root view in a window based on it's
1697 * layout params.
1698 *
1699 * @param windowSize
1700 * The available width or height of the window
1701 *
1702 * @param rootDimension
1703 * The layout params for one dimension (width or height) of the
1704 * window.
1705 *
1706 * @return The measure spec to use to measure the root view.
1707 */
1708 private int getRootMeasureSpec(int windowSize, int rootDimension) {
1709 int measureSpec;
1710 switch (rootDimension) {
1711
Romain Guy980a9382010-01-08 15:06:28 -08001712 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 // Window can't resize. Force root view to be windowSize.
1714 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
1715 break;
1716 case ViewGroup.LayoutParams.WRAP_CONTENT:
1717 // Window can resize. Set max size for root view.
1718 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
1719 break;
1720 default:
1721 // Window wants to be an exact size. Force root view to be that size.
1722 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
1723 break;
1724 }
1725 return measureSpec;
1726 }
1727
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001728 int mHardwareYOffset;
1729 int mResizeAlpha;
1730 final Paint mResizePaint = new Paint();
1731
Romain Guy7d70fbf2011-05-24 17:40:25 -07001732 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001733 canvas.translate(0, -mHardwareYOffset);
1734 }
1735
Romain Guy7d70fbf2011-05-24 17:40:25 -07001736 public void onHardwarePostDraw(HardwareCanvas canvas) {
1737 if (mResizeBuffer != null) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001738 mResizePaint.setAlpha(mResizeAlpha);
Romain Guy7d70fbf2011-05-24 17:40:25 -07001739 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001740 }
1741 }
1742
Chet Haaseed30fd82011-04-22 16:18:45 -07001743 /**
1744 * @hide
1745 */
1746 void outputDisplayList(View view) {
1747 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
Chet Haaseed30fd82011-04-22 16:18:45 -07001748 DisplayList displayList = view.getDisplayList();
1749 if (displayList != null) {
Romain Guy59a12ca2011-06-09 17:48:21 -07001750 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
1751 }
1752 }
1753 }
1754
1755 /**
1756 * @see #PROPERTY_PROFILE_RENDERING
1757 */
1758 private void profileRendering(boolean enabled) {
1759 if (mProfileRendering) {
1760 mRenderProfilingEnabled = enabled;
1761 if (mRenderProfiler == null) {
1762 mRenderProfiler = new Thread(new Runnable() {
1763 @Override
1764 public void run() {
1765 Log.d(TAG, "Starting profiling thread");
1766 while (mRenderProfilingEnabled) {
1767 mAttachInfo.mHandler.post(new Runnable() {
1768 @Override
1769 public void run() {
1770 mDirty.set(0, 0, mWidth, mHeight);
1771 scheduleTraversals();
1772 }
1773 });
1774 try {
1775 // TODO: This should use vsync when we get an API
1776 Thread.sleep(15);
1777 } catch (InterruptedException e) {
1778 Log.d(TAG, "Exiting profiling thread");
1779 }
1780 }
1781 }
1782 }, "Rendering Profiler");
1783 mRenderProfiler.start();
1784 } else {
1785 mRenderProfiler.interrupt();
1786 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07001787 }
1788 }
1789 }
1790
Chet Haase2f2022a2011-10-11 06:41:59 -07001791 /**
1792 * Called from draw() when DEBUG_FPS is enabled
1793 */
1794 private void trackFPS() {
1795 // Tracks frames per second drawn. First value in a series of draws may be bogus
1796 // because it down not account for the intervening idle time
1797 long nowTime = System.currentTimeMillis();
1798 if (mFpsStartTime < 0) {
1799 mFpsStartTime = mFpsPrevTime = nowTime;
1800 mFpsNumFrames = 0;
1801 } else {
1802 ++mFpsNumFrames;
1803 String thisHash = Integer.toHexString(System.identityHashCode(this));
1804 long frameTime = nowTime - mFpsPrevTime;
1805 long totalTime = nowTime - mFpsStartTime;
1806 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
1807 mFpsPrevTime = nowTime;
1808 if (totalTime > 1000) {
1809 float fps = (float) mFpsNumFrames * 1000 / totalTime;
1810 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
1811 mFpsStartTime = nowTime;
1812 mFpsNumFrames = 0;
1813 }
1814 }
1815 }
1816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 private void draw(boolean fullRedrawNeeded) {
1818 Surface surface = mSurface;
1819 if (surface == null || !surface.isValid()) {
1820 return;
1821 }
1822
Chet Haase2f2022a2011-10-11 06:41:59 -07001823 if (DEBUG_FPS) {
1824 trackFPS();
1825 }
1826
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08001827 if (!sFirstDrawComplete) {
1828 synchronized (sFirstDrawHandlers) {
1829 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07001830 final int count = sFirstDrawHandlers.size();
1831 for (int i = 0; i< count; i++) {
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08001832 post(sFirstDrawHandlers.get(i));
1833 }
1834 }
1835 }
Romain Guy59a12ca2011-06-09 17:48:21 -07001836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 scrollToRectOrFocus(null, false);
1838
1839 if (mAttachInfo.mViewScrollChanged) {
1840 mAttachInfo.mViewScrollChanged = false;
1841 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
1842 }
Romain Guy8506ab42009-06-11 17:35:47 -07001843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001845 boolean animating = mScroller != null && mScroller.computeScrollOffset();
1846 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 yoff = mScroller.getCurrY();
1848 } else {
1849 yoff = mScrollY;
1850 }
1851 if (mCurScrollY != yoff) {
1852 mCurScrollY = yoff;
1853 fullRedrawNeeded = true;
1854 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001855 float appScale = mAttachInfo.mApplicationScale;
1856 boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001858 int resizeAlpha = 0;
Romain Guy7d70fbf2011-05-24 17:40:25 -07001859 if (mResizeBuffer != null) {
1860 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
1861 if (deltaTime < mResizeBufferDuration) {
1862 float amt = deltaTime/(float) mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001863 amt = mResizeInterpolator.getInterpolation(amt);
1864 animating = true;
1865 resizeAlpha = 255 - (int)(amt*255);
1866 } else {
Romain Guy7d70fbf2011-05-24 17:40:25 -07001867 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001868 }
1869 }
1870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001872 if (mSurfaceHolder != null) {
1873 // The app owns the surface, we won't draw.
1874 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001875 if (animating) {
1876 if (mScroller != null) {
1877 mScroller.abortAnimation();
1878 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001879 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001880 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001881 return;
1882 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07001883
1884 if (fullRedrawNeeded) {
1885 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07001886 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07001887 }
Chet Haasead4f7032011-06-22 09:18:31 -07001888
Romain Guyb051e892010-09-28 19:09:36 -07001889 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guyfd507262010-10-10 15:42:49 -07001890 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy101e2ae2010-10-11 12:41:21 -07001891 mIsAnimating = false;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001892 mHardwareYOffset = yoff;
1893 mResizeAlpha = resizeAlpha;
Romain Guy7d7b5492011-01-24 16:33:45 -08001894
1895 mCurrentDirty.set(dirty);
1896 mCurrentDirty.union(mPreviousDirty);
1897 mPreviousDirty.set(dirty);
1898 dirty.setEmpty();
1899
Romain Guyf90f8172011-01-25 22:53:24 -08001900 Rect currentDirty = mCurrentDirty;
1901 if (animating) {
1902 currentDirty = null;
1903 }
1904
Romain Guy50d133e2011-08-12 15:25:28 -07001905 if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty)) {
1906 mPreviousDirty.set(0, 0, mWidth, mHeight);
1907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001909
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001910 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 mFullRedrawNeeded = true;
1912 scheduleTraversals();
1913 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 return;
1916 }
1917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001919 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 + mWindowAttributes.getTitle()
1921 + ": dirty={" + dirty.left + "," + dirty.top
1922 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001923 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
1924 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 }
1926
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001927 if (!dirty.isEmpty() || mIsAnimating) {
1928 Canvas canvas;
1929 try {
1930 int left = dirty.left;
1931 int top = dirty.top;
1932 int right = dirty.right;
1933 int bottom = dirty.bottom;
Romain Guyfea12b82011-01-27 15:36:40 -08001934
Jeff Brown4e91a182011-04-07 11:38:09 -07001935 final long lockCanvasStartTime;
1936 if (ViewDebug.DEBUG_LATENCY) {
1937 lockCanvasStartTime = System.nanoTime();
1938 }
1939
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001940 canvas = surface.lockCanvas(dirty);
Romain Guy5bcdff42009-05-14 21:27:18 -07001941
Jeff Brown4e91a182011-04-07 11:38:09 -07001942 if (ViewDebug.DEBUG_LATENCY) {
1943 long now = System.nanoTime();
1944 Log.d(TAG, "Latency: Spent "
1945 + ((now - lockCanvasStartTime) * 0.000001f)
1946 + "ms waiting for surface.lockCanvas()");
1947 }
1948
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001949 if (left != dirty.left || top != dirty.top || right != dirty.right ||
1950 bottom != dirty.bottom) {
1951 mAttachInfo.mIgnoreDirtyState = true;
1952 }
1953
1954 // TODO: Do this in native
1955 canvas.setDensity(mDensity);
1956 } catch (Surface.OutOfResourcesException e) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001957 Log.e(TAG, "OutOfResourcesException locking surface", e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001958 try {
1959 if (!sWindowSession.outOfMemory(mWindow)) {
1960 Slog.w(TAG, "No processes killed for memory; killing self");
1961 Process.killProcess(Process.myPid());
1962 }
1963 } catch (RemoteException ex) {
1964 }
Dianne Hackborn83a6f452011-01-27 17:17:19 -08001965 mLayoutRequested = true; // ask wm for a new surface next time.
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001966 return;
1967 } catch (IllegalArgumentException e) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001968 Log.e(TAG, "IllegalArgumentException locking surface", e);
Dianne Hackborndb773c52011-03-04 16:43:41 -08001969 // Don't assume this is due to out of memory, it could be
1970 // something else, and if it is something else then we could
1971 // kill stuff (or ourself) for no reason.
Dianne Hackborn83a6f452011-01-27 17:17:19 -08001972 mLayoutRequested = true; // ask wm for a new surface next time.
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001973 return;
Romain Guy5bcdff42009-05-14 21:27:18 -07001974 }
1975
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001976 try {
1977 if (!dirty.isEmpty() || mIsAnimating) {
1978 long startTime = 0L;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001980 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001981 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001982 + canvas.getWidth() + ", h=" + canvas.getHeight());
1983 //canvas.drawARGB(255, 255, 0, 0);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001984 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985
Romain Guy5429e1d2010-09-07 12:38:00 -07001986 if (ViewDebug.DEBUG_PROFILE_DRAWING) {
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001987 startTime = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001989
1990 // If this bitmap's format includes an alpha channel, we
1991 // need to clear it before drawing so that the child will
1992 // properly re-composite its drawing on a transparent
1993 // background. This automatically respects the clip/dirty region
1994 // or
1995 // If we are applying an offset, we need to clear the area
1996 // where the offset doesn't appear to avoid having garbage
1997 // left in the blank areas.
1998 if (!canvas.isOpaque() || yoff != 0) {
1999 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2000 }
2001
2002 dirty.setEmpty();
2003 mIsAnimating = false;
2004 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
2005 mView.mPrivateFlags |= View.DRAWN;
2006
2007 if (DEBUG_DRAW) {
2008 Context cxt = mView.getContext();
2009 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2010 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2011 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2012 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002013 try {
2014 canvas.translate(0, -yoff);
2015 if (mTranslator != null) {
2016 mTranslator.translateCanvas(canvas);
2017 }
2018 canvas.setScreenDensity(scalingRequired
2019 ? DisplayMetrics.DENSITY_DEVICE : 0);
Romain Guy02ccac62011-06-24 13:20:23 -07002020 mAttachInfo.mSetIgnoreDirtyState = false;
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002021 mView.draw(canvas);
2022 } finally {
Romain Guy02ccac62011-06-24 13:20:23 -07002023 if (!mAttachInfo.mSetIgnoreDirtyState) {
Chet Haasead4f7032011-06-22 09:18:31 -07002024 // Only clear the flag if it was not set during the mView.draw() call
2025 mAttachInfo.mIgnoreDirtyState = false;
2026 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002027 }
2028
Joe Onorato43a17652011-04-06 19:22:23 -07002029 if (false && ViewDebug.consistencyCheckEnabled) {
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002030 mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
2031 }
2032
Romain Guy5429e1d2010-09-07 12:38:00 -07002033 if (ViewDebug.DEBUG_PROFILE_DRAWING) {
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002034 EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
2035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 }
2037
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002038 } finally {
2039 surface.unlockCanvasAndPost(canvas);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 }
2042
2043 if (LOCAL_LOGV) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002044 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 }
Romain Guy8506ab42009-06-11 17:35:47 -07002046
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002047 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 mFullRedrawNeeded = true;
2049 scheduleTraversals();
2050 }
2051 }
2052
2053 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2054 final View.AttachInfo attachInfo = mAttachInfo;
2055 final Rect ci = attachInfo.mContentInsets;
2056 final Rect vi = attachInfo.mVisibleInsets;
2057 int scrollY = 0;
2058 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 if (vi.left > ci.left || vi.top > ci.top
2061 || vi.right > ci.right || vi.bottom > ci.bottom) {
2062 // We'll assume that we aren't going to change the scroll
2063 // offset, since we want to avoid that unless it is actually
2064 // going to make the focus visible... otherwise we scroll
2065 // all over the place.
2066 scrollY = mScrollY;
2067 // We can be called for two different situations: during a draw,
2068 // to update the scroll position if the focus has changed (in which
2069 // case 'rectangle' is null), or in response to a
2070 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2071 // is non-null and we just want to scroll to whatever that
2072 // rectangle is).
2073 View focus = mRealFocusedView;
Romain Guye8b16522009-07-14 13:06:42 -07002074
2075 // When in touch mode, focus points to the previously focused view,
2076 // which may have been removed from the view hierarchy. The following
Joe Onoratob71193b2009-11-24 18:34:42 -05002077 // line checks whether the view is still in our hierarchy.
2078 if (focus == null || focus.mAttachInfo != mAttachInfo) {
Romain Guye8b16522009-07-14 13:06:42 -07002079 mRealFocusedView = null;
2080 return false;
2081 }
2082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 if (focus != mLastScrolledFocus) {
2084 // If the focus has changed, then ignore any requests to scroll
2085 // to a rectangle; first we want to make sure the entire focus
2086 // view is visible.
2087 rectangle = null;
2088 }
2089 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2090 + " rectangle=" + rectangle + " ci=" + ci
2091 + " vi=" + vi);
2092 if (focus == mLastScrolledFocus && !mScrollMayChange
2093 && rectangle == null) {
2094 // Optimization: if the focus hasn't changed since last
2095 // time, and no layout has happened, then just leave things
2096 // as they are.
2097 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2098 + mScrollY + " vi=" + vi.toShortString());
2099 } else if (focus != null) {
2100 // We need to determine if the currently focused view is
2101 // within the visible part of the window and, if not, apply
2102 // a pan so it can be seen.
2103 mLastScrolledFocus = focus;
2104 mScrollMayChange = false;
2105 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2106 // Try to find the rectangle from the focus view.
2107 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2108 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2109 + mView.getWidth() + " h=" + mView.getHeight()
2110 + " ci=" + ci.toShortString()
2111 + " vi=" + vi.toShortString());
2112 if (rectangle == null) {
2113 focus.getFocusedRect(mTempRect);
2114 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2115 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002116 if (mView instanceof ViewGroup) {
2117 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2118 focus, mTempRect);
2119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2121 "Focus in window: focusRect="
2122 + mTempRect.toShortString()
2123 + " visRect=" + mVisRect.toShortString());
2124 } else {
2125 mTempRect.set(rectangle);
2126 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2127 "Request scroll to rect: "
2128 + mTempRect.toShortString()
2129 + " visRect=" + mVisRect.toShortString());
2130 }
2131 if (mTempRect.intersect(mVisRect)) {
2132 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2133 "Focus window visible rect: "
2134 + mTempRect.toShortString());
2135 if (mTempRect.height() >
2136 (mView.getHeight()-vi.top-vi.bottom)) {
2137 // If the focus simply is not going to fit, then
2138 // best is probably just to leave things as-is.
2139 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2140 "Too tall; leaving scrollY=" + scrollY);
2141 } else if ((mTempRect.top-scrollY) < vi.top) {
2142 scrollY -= vi.top - (mTempRect.top-scrollY);
2143 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2144 "Top covered; scrollY=" + scrollY);
2145 } else if ((mTempRect.bottom-scrollY)
2146 > (mView.getHeight()-vi.bottom)) {
2147 scrollY += (mTempRect.bottom-scrollY)
2148 - (mView.getHeight()-vi.bottom);
2149 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2150 "Bottom covered; scrollY=" + scrollY);
2151 }
2152 handled = true;
2153 }
2154 }
2155 }
2156 }
Romain Guy8506ab42009-06-11 17:35:47 -07002157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 if (scrollY != mScrollY) {
2159 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2160 + mScrollY + " , new=" + scrollY);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002161 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 if (mScroller == null) {
2163 mScroller = new Scroller(mView.getContext());
2164 }
2165 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2166 } else if (mScroller != null) {
2167 mScroller.abortAnimation();
2168 }
2169 mScrollY = scrollY;
2170 }
Romain Guy8506ab42009-06-11 17:35:47 -07002171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 return handled;
2173 }
Romain Guy8506ab42009-06-11 17:35:47 -07002174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 public void requestChildFocus(View child, View focused) {
2176 checkThread();
2177 if (mFocusedView != focused) {
2178 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
2179 scheduleTraversals();
2180 }
2181 mFocusedView = mRealFocusedView = focused;
2182 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
2183 + mFocusedView);
2184 }
2185
2186 public void clearChildFocus(View child) {
2187 checkThread();
2188
2189 View oldFocus = mFocusedView;
2190
2191 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
2192 mFocusedView = mRealFocusedView = null;
2193 if (mView != null && !mView.hasFocus()) {
2194 // If a view gets the focus, the listener will be invoked from requestChildFocus()
2195 if (!mView.requestFocus(View.FOCUS_FORWARD)) {
2196 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
2197 }
2198 } else if (oldFocus != null) {
2199 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
2200 }
2201 }
2202
2203
2204 public void focusableViewAvailable(View v) {
2205 checkThread();
2206
Romain Guy1c90f032011-05-24 14:59:50 -07002207 if (mView != null) {
2208 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002210 } else {
2211 // the one case where will transfer focus away from the current one
2212 // is if the current view is a view group that prefers to give focus
2213 // to its children first AND the view is a descendant of it.
2214 mFocusedView = mView.findFocus();
2215 boolean descendantsHaveDibsOnFocus =
2216 (mFocusedView instanceof ViewGroup) &&
2217 (((ViewGroup) mFocusedView).getDescendantFocusability() ==
2218 ViewGroup.FOCUS_AFTER_DESCENDANTS);
2219 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
2220 // If a view gets the focus, the listener will be invoked from requestChildFocus()
2221 v.requestFocus();
2222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002223 }
2224 }
2225 }
2226
2227 public void recomputeViewAttributes(View child) {
2228 checkThread();
2229 if (mView == child) {
2230 mAttachInfo.mRecomputeGlobalAttributes = true;
2231 if (!mWillDrawSoon) {
2232 scheduleTraversals();
2233 }
2234 }
2235 }
2236
2237 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002238 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002239 if (mAttachInfo.mHardwareRenderer != null &&
2240 mAttachInfo.mHardwareRenderer.isEnabled()) {
2241 mAttachInfo.mHardwareRenderer.validate();
2242 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243 mView.dispatchDetachedFromWindow();
2244 }
2245
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002246 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2247 mAccessibilityManager.removeAccessibilityStateChangeListener(
2248 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002249 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 mView = null;
2252 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07002253 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254
Romain Guy29d89972010-09-22 16:10:57 -07002255 destroyHardwareRenderer();
Romain Guy4caa4ed2010-08-25 14:46:24 -07002256
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002257 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258
Jeff Browncc4f7db2011-08-30 20:34:48 -07002259 if (mInputQueueCallback != null && mInputQueue != null) {
2260 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
2261 mInputQueueCallback = null;
2262 mInputQueue = null;
2263 } else if (mInputChannel != null) {
2264 InputQueue.unregisterInputChannel(mInputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -07002265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 try {
2267 sWindowSession.remove(mWindow);
2268 } catch (RemoteException e) {
2269 }
Jeff Brown349703e2010-06-22 01:27:15 -07002270
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002271 // Dispose the input channel after removing the window so the Window Manager
2272 // doesn't interpret the input channel being closed as an abnormal termination.
2273 if (mInputChannel != null) {
2274 mInputChannel.dispose();
2275 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 }
Romain Guy8506ab42009-06-11 17:35:47 -07002278
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002279 void updateConfiguration(Configuration config, boolean force) {
2280 if (DEBUG_CONFIGURATION) Log.v(TAG,
2281 "Applying new config to window "
2282 + mWindowAttributes.getTitle()
2283 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002284
2285 CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
2286 if (ci != null) {
2287 config = new Configuration(config);
2288 ci.applyToConfiguration(config);
2289 }
2290
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002291 synchronized (sConfigCallbacks) {
2292 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2293 sConfigCallbacks.get(i).onConfigurationChanged(config);
2294 }
2295 }
2296 if (mView != null) {
2297 // At this point the resources have been updated to
2298 // have the most recent config, whatever that is. Use
2299 // the on in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002300 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002301 if (force || mLastConfiguration.diff(config) != 0) {
2302 mLastConfiguration.setTo(config);
2303 mView.dispatchConfigurationChanged(config);
2304 }
2305 }
2306 }
2307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 /**
2309 * Return true if child is an ancestor of parent, (or equal to the parent).
2310 */
2311 private static boolean isViewDescendantOf(View child, View parent) {
2312 if (child == parent) {
2313 return true;
2314 }
2315
2316 final ViewParent theParent = child.getParent();
2317 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2318 }
2319
Romain Guycdb86672010-03-18 18:54:50 -07002320 private static void forceLayout(View view) {
2321 view.forceLayout();
2322 if (view instanceof ViewGroup) {
2323 ViewGroup group = (ViewGroup) view;
2324 final int count = group.getChildCount();
2325 for (int i = 0; i < count; i++) {
2326 forceLayout(group.getChildAt(i));
2327 }
2328 }
2329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002330
2331 public final static int DO_TRAVERSAL = 1000;
2332 public final static int DIE = 1001;
2333 public final static int RESIZED = 1002;
2334 public final static int RESIZED_REPORT = 1003;
2335 public final static int WINDOW_FOCUS_CHANGED = 1004;
2336 public final static int DISPATCH_KEY = 1005;
2337 public final static int DISPATCH_POINTER = 1006;
2338 public final static int DISPATCH_TRACKBALL = 1007;
2339 public final static int DISPATCH_APP_VISIBILITY = 1008;
2340 public final static int DISPATCH_GET_NEW_SURFACE = 1009;
2341 public final static int FINISHED_EVENT = 1010;
2342 public final static int DISPATCH_KEY_FROM_IME = 1011;
2343 public final static int FINISH_INPUT_CONNECTION = 1012;
2344 public final static int CHECK_FOCUS = 1013;
Dianne Hackbornffa42482009-09-23 22:20:11 -07002345 public final static int CLOSE_SYSTEM_DIALOGS = 1014;
Christopher Tatea53146c2010-09-07 11:57:52 -07002346 public final static int DISPATCH_DRAG_EVENT = 1015;
Chris Tate91e9bb32010-10-12 12:58:43 -07002347 public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
Joe Onorato664644d2011-01-23 17:53:23 -08002348 public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
Joe Onorato10f41262011-01-24 13:16:08 -08002349 public final static int DISPATCH_GENERIC_MOTION = 1018;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002350 public final static int UPDATE_CONFIGURATION = 1019;
Dianne Hackbornf741e672011-06-09 17:50:36 -07002351 public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1020;
2352 public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021;
2353 public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022;
Svetoslav Ganov02107852011-10-03 17:06:56 -07002354 public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 1023;
Chet Haase1f4786b2011-11-02 10:51:52 -07002355 public final static int PROCESS_INPUT_EVENTS = 1024;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356
2357 @Override
Romain Guyf9284692011-07-13 18:46:21 -07002358 public String getMessageName(Message message) {
2359 switch (message.what) {
2360 case DO_TRAVERSAL:
2361 return "DO_TRAVERSAL";
2362 case DIE:
2363 return "DIE";
2364 case RESIZED:
2365 return "RESIZED";
2366 case RESIZED_REPORT:
2367 return "RESIZED_REPORT";
2368 case WINDOW_FOCUS_CHANGED:
2369 return "WINDOW_FOCUS_CHANGED";
2370 case DISPATCH_KEY:
2371 return "DISPATCH_KEY";
2372 case DISPATCH_POINTER:
2373 return "DISPATCH_POINTER";
2374 case DISPATCH_TRACKBALL:
2375 return "DISPATCH_TRACKBALL";
2376 case DISPATCH_APP_VISIBILITY:
2377 return "DISPATCH_APP_VISIBILITY";
2378 case DISPATCH_GET_NEW_SURFACE:
2379 return "DISPATCH_GET_NEW_SURFACE";
2380 case FINISHED_EVENT:
2381 return "FINISHED_EVENT";
2382 case DISPATCH_KEY_FROM_IME:
2383 return "DISPATCH_KEY_FROM_IME";
2384 case FINISH_INPUT_CONNECTION:
2385 return "FINISH_INPUT_CONNECTION";
2386 case CHECK_FOCUS:
2387 return "CHECK_FOCUS";
2388 case CLOSE_SYSTEM_DIALOGS:
2389 return "CLOSE_SYSTEM_DIALOGS";
2390 case DISPATCH_DRAG_EVENT:
2391 return "DISPATCH_DRAG_EVENT";
2392 case DISPATCH_DRAG_LOCATION_EVENT:
2393 return "DISPATCH_DRAG_LOCATION_EVENT";
2394 case DISPATCH_SYSTEM_UI_VISIBILITY:
2395 return "DISPATCH_SYSTEM_UI_VISIBILITY";
2396 case DISPATCH_GENERIC_MOTION:
2397 return "DISPATCH_GENERIC_MOTION";
2398 case UPDATE_CONFIGURATION:
2399 return "UPDATE_CONFIGURATION";
2400 case DO_PERFORM_ACCESSIBILITY_ACTION:
2401 return "DO_PERFORM_ACCESSIBILITY_ACTION";
2402 case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
2403 return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
2404 case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
2405 return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
Svetoslav Ganov02107852011-10-03 17:06:56 -07002406 case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
2407 return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
Chet Haase1f4786b2011-11-02 10:51:52 -07002408 case PROCESS_INPUT_EVENTS:
2409 return "PROCESS_INPUT_EVENTS";
Romain Guyf9284692011-07-13 18:46:21 -07002410 }
2411 return super.getMessageName(message);
2412 }
2413
2414 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 public void handleMessage(Message msg) {
2416 switch (msg.what) {
2417 case View.AttachInfo.INVALIDATE_MSG:
2418 ((View) msg.obj).invalidate();
2419 break;
2420 case View.AttachInfo.INVALIDATE_RECT_MSG:
2421 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
2422 info.target.invalidate(info.left, info.top, info.right, info.bottom);
2423 info.release();
2424 break;
2425 case DO_TRAVERSAL:
2426 if (mProfile) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07002427 Debug.startMethodTracing("ViewAncestor");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 }
2429
Jeff Brown4e91a182011-04-07 11:38:09 -07002430 final long traversalStartTime;
2431 if (ViewDebug.DEBUG_LATENCY) {
2432 traversalStartTime = System.nanoTime();
2433 mLastDrawDurationNanos = 0;
2434 }
2435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002436 performTraversals();
2437
Jeff Brown4e91a182011-04-07 11:38:09 -07002438 if (ViewDebug.DEBUG_LATENCY) {
2439 long now = System.nanoTime();
2440 Log.d(TAG, "Latency: Spent "
2441 + ((now - traversalStartTime) * 0.000001f)
2442 + "ms in performTraversals(), with "
2443 + (mLastDrawDurationNanos * 0.000001f)
2444 + "ms of that time in draw()");
2445 mLastTraversalFinishedTimeNanos = now;
2446 }
2447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 if (mProfile) {
2449 Debug.stopMethodTracing();
2450 mProfile = false;
2451 }
2452 break;
2453 case FINISHED_EVENT:
2454 handleFinishedEvent(msg.arg1, msg.arg2 != 0);
2455 break;
2456 case DISPATCH_KEY:
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002457 deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458 break;
Jeff Brown3915bb82010-11-05 15:02:16 -07002459 case DISPATCH_POINTER:
2460 deliverPointerEvent((MotionEvent) msg.obj, msg.arg1 != 0);
2461 break;
2462 case DISPATCH_TRACKBALL:
2463 deliverTrackballEvent((MotionEvent) msg.obj, msg.arg1 != 0);
2464 break;
Jeff Browncb1404e2011-01-15 18:14:15 -08002465 case DISPATCH_GENERIC_MOTION:
2466 deliverGenericMotionEvent((MotionEvent) msg.obj, msg.arg1 != 0);
2467 break;
Chet Haase1f4786b2011-11-02 10:51:52 -07002468 case PROCESS_INPUT_EVENTS:
2469 processInputEvents(false);
2470 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 case DISPATCH_APP_VISIBILITY:
2472 handleAppVisibility(msg.arg1 != 0);
2473 break;
2474 case DISPATCH_GET_NEW_SURFACE:
2475 handleGetNewSurface();
2476 break;
2477 case RESIZED:
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002478 ResizedInfo ri = (ResizedInfo)msg.obj;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002481 && mPendingContentInsets.equals(ri.coveredInsets)
Dianne Hackbornd49258f2010-03-26 00:44:29 -07002482 && mPendingVisibleInsets.equals(ri.visibleInsets)
2483 && ((ResizedInfo)msg.obj).newConfig == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002484 break;
2485 }
2486 // fall through...
2487 case RESIZED_REPORT:
2488 if (mAdded) {
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002489 Configuration config = ((ResizedInfo)msg.obj).newConfig;
2490 if (config != null) {
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002491 updateConfiguration(config, false);
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 mWinFrame.left = 0;
2494 mWinFrame.right = msg.arg1;
2495 mWinFrame.top = 0;
2496 mWinFrame.bottom = msg.arg2;
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002497 mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
2498 mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002499 if (msg.what == RESIZED_REPORT) {
2500 mReportNextDraw = true;
2501 }
Romain Guycdb86672010-03-18 18:54:50 -07002502
2503 if (mView != null) {
2504 forceLayout(mView);
2505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 requestLayout();
2507 }
2508 break;
2509 case WINDOW_FOCUS_CHANGED: {
2510 if (mAdded) {
2511 boolean hasWindowFocus = msg.arg1 != 0;
2512 mAttachInfo.mHasWindowFocus = hasWindowFocus;
Romain Guy59a12ca2011-06-09 17:48:21 -07002513
2514 profileRendering(hasWindowFocus);
2515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 if (hasWindowFocus) {
2517 boolean inTouchMode = msg.arg2 != 0;
Romain Guy2d4cff62010-04-09 15:39:00 -07002518 ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519
Romain Guyc361da82010-10-25 15:29:10 -07002520 if (mAttachInfo.mHardwareRenderer != null &&
2521 mSurface != null && mSurface.isValid()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08002522 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08002523 try {
2524 mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
2525 mAttachInfo, mHolder);
2526 } catch (Surface.OutOfResourcesException e) {
2527 Log.e(TAG, "OutOfResourcesException locking surface", e);
2528 try {
2529 if (!sWindowSession.outOfMemory(mWindow)) {
2530 Slog.w(TAG, "No processes killed for memory; killing self");
2531 Process.killProcess(Process.myPid());
2532 }
2533 } catch (RemoteException ex) {
2534 }
2535 // Retry in a bit.
2536 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
2537 return;
2538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002539 }
2540 }
Romain Guy8506ab42009-06-11 17:35:47 -07002541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 mLastWasImTarget = WindowManager.LayoutParams
2543 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07002544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 InputMethodManager imm = InputMethodManager.peekInstance();
2546 if (mView != null) {
2547 if (hasWindowFocus && imm != null && mLastWasImTarget) {
2548 imm.startGettingWindowFocus(mView);
2549 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002550 mAttachInfo.mKeyDispatchState.reset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002551 mView.dispatchWindowFocusChanged(hasWindowFocus);
2552 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 // Note: must be done after the focus change callbacks,
2555 // so all of the view state is set up correctly.
2556 if (hasWindowFocus) {
2557 if (imm != null && mLastWasImTarget) {
2558 imm.onWindowFocus(mView, mView.findFocus(),
2559 mWindowAttributes.softInputMode,
2560 !mHasHadWindowFocus, mWindowAttributes.flags);
2561 }
2562 // Clear the forward bit. We can just do this directly, since
2563 // the window manager doesn't care about it.
2564 mWindowAttributes.softInputMode &=
2565 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2566 ((WindowManager.LayoutParams)mView.getLayoutParams())
2567 .softInputMode &=
2568 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2569 mHasHadWindowFocus = true;
2570 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002571
2572 if (hasWindowFocus && mView != null) {
2573 sendAccessibilityEvents();
2574 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002575 }
2576 } break;
2577 case DIE:
Dianne Hackborn94d69142009-09-28 22:14:42 -07002578 doDie();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07002580 case DISPATCH_KEY_FROM_IME: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002581 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07002582 TAG, "Dispatching key "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002583 + msg.obj + " from IME to " + mView);
The Android Open Source Project10592532009-03-18 17:39:46 -07002584 KeyEvent event = (KeyEvent)msg.obj;
2585 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
2586 // The IME is trying to say this event is from the
2587 // system! Bad bad bad!
Romain Guy1c90f032011-05-24 14:59:50 -07002588 //noinspection UnusedAssignment
Romain Guy812ccbe2010-06-01 14:07:24 -07002589 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project10592532009-03-18 17:39:46 -07002590 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002591 deliverKeyEventPostIme((KeyEvent)msg.obj, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002592 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002593 case FINISH_INPUT_CONNECTION: {
2594 InputMethodManager imm = InputMethodManager.peekInstance();
2595 if (imm != null) {
2596 imm.reportFinishInputConnection((InputConnection)msg.obj);
2597 }
2598 } break;
2599 case CHECK_FOCUS: {
2600 InputMethodManager imm = InputMethodManager.peekInstance();
2601 if (imm != null) {
2602 imm.checkFocus();
2603 }
2604 } break;
Dianne Hackbornffa42482009-09-23 22:20:11 -07002605 case CLOSE_SYSTEM_DIALOGS: {
2606 if (mView != null) {
2607 mView.onCloseSystemDialogs((String)msg.obj);
2608 }
2609 } break;
Chris Tate91e9bb32010-10-12 12:58:43 -07002610 case DISPATCH_DRAG_EVENT:
2611 case DISPATCH_DRAG_LOCATION_EVENT: {
Christopher Tate7fb8b562011-01-20 13:46:41 -08002612 DragEvent event = (DragEvent)msg.obj;
2613 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
2614 handleDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07002615 } break;
Joe Onorato664644d2011-01-23 17:53:23 -08002616 case DISPATCH_SYSTEM_UI_VISIBILITY: {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07002617 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
Joe Onorato664644d2011-01-23 17:53:23 -08002618 } break;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002619 case UPDATE_CONFIGURATION: {
2620 Configuration config = (Configuration)msg.obj;
2621 if (config.isOtherSeqNewer(mLastConfiguration)) {
2622 config = mLastConfiguration;
2623 }
2624 updateConfiguration(config, false);
2625 } break;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002626 case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
Svetoslav Ganov601ad802011-06-09 14:47:38 -07002627 if (mView != null) {
2628 getAccessibilityInteractionController()
2629 .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
2630 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002631 } break;
2632 case DO_PERFORM_ACCESSIBILITY_ACTION: {
Svetoslav Ganov601ad802011-06-09 14:47:38 -07002633 if (mView != null) {
2634 getAccessibilityInteractionController()
2635 .perfromAccessibilityActionUiThread(msg);
2636 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002637 } break;
2638 case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
Svetoslav Ganov601ad802011-06-09 14:47:38 -07002639 if (mView != null) {
2640 getAccessibilityInteractionController()
2641 .findAccessibilityNodeInfoByViewIdUiThread(msg);
2642 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002643 } break;
Svetoslav Ganov02107852011-10-03 17:06:56 -07002644 case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
Svetoslav Ganov601ad802011-06-09 14:47:38 -07002645 if (mView != null) {
2646 getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07002647 .findAccessibilityNodeInfosByTextUiThread(msg);
Svetoslav Ganov601ad802011-06-09 14:47:38 -07002648 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002649 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 }
2651 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002652
Romain Guy1c90f032011-05-24 14:59:50 -07002653 private void startInputEvent(InputQueue.FinishedCallback finishedCallback) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07002654 if (mFinishedCallback != null) {
2655 Slog.w(TAG, "Received a new input event from the input queue but there is "
2656 + "already an unfinished input event in progress.");
2657 }
2658
Jeff Brown4e91a182011-04-07 11:38:09 -07002659 if (ViewDebug.DEBUG_LATENCY) {
2660 mInputEventReceiveTimeNanos = System.nanoTime();
2661 mInputEventDeliverTimeNanos = 0;
2662 mInputEventDeliverPostImeTimeNanos = 0;
2663 }
2664
Jeff Brown93ed4e32010-09-23 13:51:48 -07002665 mFinishedCallback = finishedCallback;
2666 }
2667
Jeff Brown4e91a182011-04-07 11:38:09 -07002668 private void finishInputEvent(InputEvent event, boolean handled) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07002669 if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished");
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002670
Jeff Brown4e91a182011-04-07 11:38:09 -07002671 if (mFinishedCallback == null) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07002672 Slog.w(TAG, "Attempted to tell the input queue that the current input event "
2673 + "is finished but there is no input event actually in progress.");
Jeff Brown4e91a182011-04-07 11:38:09 -07002674 return;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002675 }
Jeff Brown4e91a182011-04-07 11:38:09 -07002676
2677 if (ViewDebug.DEBUG_LATENCY) {
2678 final long now = System.nanoTime();
2679 final long eventTime = event.getEventTimeNano();
2680 final StringBuilder msg = new StringBuilder();
2681 msg.append("Latency: Spent ");
2682 msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f);
2683 msg.append("ms processing ");
2684 if (event instanceof KeyEvent) {
2685 final KeyEvent keyEvent = (KeyEvent)event;
2686 msg.append("key event, action=");
2687 msg.append(KeyEvent.actionToString(keyEvent.getAction()));
2688 } else {
2689 final MotionEvent motionEvent = (MotionEvent)event;
2690 msg.append("motion event, action=");
2691 msg.append(MotionEvent.actionToString(motionEvent.getAction()));
2692 msg.append(", historySize=");
2693 msg.append(motionEvent.getHistorySize());
2694 }
2695 msg.append(", handled=");
2696 msg.append(handled);
2697 msg.append(", received at +");
2698 msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f);
2699 if (mInputEventDeliverTimeNanos != 0) {
2700 msg.append("ms, delivered at +");
2701 msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f);
2702 }
2703 if (mInputEventDeliverPostImeTimeNanos != 0) {
2704 msg.append("ms, delivered post IME at +");
2705 msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f);
2706 }
2707 msg.append("ms, finished at +");
2708 msg.append((now - eventTime) * 0.000001f);
2709 msg.append("ms.");
2710 Log.d(TAG, msg.toString());
2711 }
2712
2713 mFinishedCallback.finished(handled);
2714 mFinishedCallback = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002715 }
2716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 /**
2718 * Something in the current window tells us we need to change the touch mode. For
2719 * example, we are not in touch mode, and the user touches the screen.
2720 *
2721 * If the touch mode has changed, tell the window manager, and handle it locally.
2722 *
2723 * @param inTouchMode Whether we want to be in touch mode.
2724 * @return True if the touch mode changed and focus changed was changed as a result
2725 */
2726 boolean ensureTouchMode(boolean inTouchMode) {
2727 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
2728 + "touch mode is " + mAttachInfo.mInTouchMode);
2729 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
2730
2731 // tell the window manager
2732 try {
2733 sWindowSession.setInTouchMode(inTouchMode);
2734 } catch (RemoteException e) {
2735 throw new RuntimeException(e);
2736 }
2737
2738 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07002739 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 }
2741
2742 /**
2743 * Ensure that the touch mode for this window is set, and if it is changing,
2744 * take the appropriate action.
2745 * @param inTouchMode Whether we want to be in touch mode.
2746 * @return True if the touch mode changed and focus changed was changed as a result
2747 */
Romain Guy2d4cff62010-04-09 15:39:00 -07002748 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002749 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
2750 + "touch mode is " + mAttachInfo.mInTouchMode);
2751
2752 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
2753
2754 mAttachInfo.mInTouchMode = inTouchMode;
2755 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
2756
Romain Guy2d4cff62010-04-09 15:39:00 -07002757 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002758 }
2759
2760 private boolean enterTouchMode() {
2761 if (mView != null) {
2762 if (mView.hasFocus()) {
2763 // note: not relying on mFocusedView here because this could
2764 // be when the window is first being added, and mFocused isn't
2765 // set yet.
2766 final View focused = mView.findFocus();
2767 if (focused != null && !focused.isFocusableInTouchMode()) {
2768
2769 final ViewGroup ancestorToTakeFocus =
2770 findAncestorToTakeFocusInTouchMode(focused);
2771 if (ancestorToTakeFocus != null) {
2772 // there is an ancestor that wants focus after its descendants that
2773 // is focusable in touch mode.. give it focus
2774 return ancestorToTakeFocus.requestFocus();
2775 } else {
2776 // nothing appropriate to have focus in touch mode, clear it out
2777 mView.unFocus();
2778 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
2779 mFocusedView = null;
2780 return true;
2781 }
2782 }
2783 }
2784 }
2785 return false;
2786 }
2787
2788
2789 /**
2790 * Find an ancestor of focused that wants focus after its descendants and is
2791 * focusable in touch mode.
2792 * @param focused The currently focused view.
2793 * @return An appropriate view, or null if no such view exists.
2794 */
2795 private ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
2796 ViewParent parent = focused.getParent();
2797 while (parent instanceof ViewGroup) {
2798 final ViewGroup vgParent = (ViewGroup) parent;
2799 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2800 && vgParent.isFocusableInTouchMode()) {
2801 return vgParent;
2802 }
2803 if (vgParent.isRootNamespace()) {
2804 return null;
2805 } else {
2806 parent = vgParent.getParent();
2807 }
2808 }
2809 return null;
2810 }
2811
2812 private boolean leaveTouchMode() {
2813 if (mView != null) {
2814 if (mView.hasFocus()) {
2815 // i learned the hard way to not trust mFocusedView :)
2816 mFocusedView = mView.findFocus();
2817 if (!(mFocusedView instanceof ViewGroup)) {
2818 // some view has focus, let it keep it
2819 return false;
2820 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
2821 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2822 // some view group has focus, and doesn't prefer its children
2823 // over itself for focus, so let them keep it.
2824 return false;
2825 }
2826 }
2827
2828 // find the best view to give focus to in this brave new non-touch-mode
2829 // world
2830 final View focused = focusSearch(null, View.FOCUS_DOWN);
2831 if (focused != null) {
2832 return focused.requestFocus(View.FOCUS_DOWN);
2833 }
2834 }
2835 return false;
2836 }
2837
Jeff Brown3915bb82010-11-05 15:02:16 -07002838 private void deliverPointerEvent(MotionEvent event, boolean sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07002839 if (ViewDebug.DEBUG_LATENCY) {
2840 mInputEventDeliverTimeNanos = System.nanoTime();
2841 }
2842
Jeff Brown7564d622011-07-14 19:14:22 -07002843 final boolean isTouchEvent = event.isTouchEvent();
Jeff Brown21bc5c92011-02-28 18:27:14 -08002844 if (mInputEventConsistencyVerifier != null) {
Jeff Brown7564d622011-07-14 19:14:22 -07002845 if (isTouchEvent) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002846 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
2847 } else {
2848 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
2849 }
2850 }
2851
Jeff Brown3915bb82010-11-05 15:02:16 -07002852 // If there is no view, then the event will not be handled.
2853 if (mView == null || !mAdded) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002854 finishMotionEvent(event, sendDone, false);
Jeff Brown3915bb82010-11-05 15:02:16 -07002855 return;
2856 }
2857
2858 // Translate the pointer event for compatibility, if needed.
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002859 if (mTranslator != null) {
2860 mTranslator.translateEventInScreenToAppWindow(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 }
2862
Jeff Brown7564d622011-07-14 19:14:22 -07002863 // Enter touch mode on down or scroll.
2864 final int action = event.getAction();
2865 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
Jeff Brown3915bb82010-11-05 15:02:16 -07002866 ensureTouchMode(true);
2867 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002868
Jeff Brown3915bb82010-11-05 15:02:16 -07002869 // Offset the scroll position.
2870 if (mCurScrollY != 0) {
2871 event.offsetLocation(0, mCurScrollY);
2872 }
2873 if (MEASURE_LATENCY) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002874 lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
Jeff Brown3915bb82010-11-05 15:02:16 -07002875 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002876
Jeff Brown3915bb82010-11-05 15:02:16 -07002877 // Remember the touch position for possible drag-initiation.
Jeff Brown7564d622011-07-14 19:14:22 -07002878 if (isTouchEvent) {
2879 mLastTouchPoint.x = event.getRawX();
2880 mLastTouchPoint.y = event.getRawY();
2881 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002882
2883 // Dispatch touch to view hierarchy.
Jeff Brown33bbfd22011-02-24 20:55:35 -08002884 boolean handled = mView.dispatchPointerEvent(event);
Jeff Brown3915bb82010-11-05 15:02:16 -07002885 if (MEASURE_LATENCY) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002886 lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
Jeff Brown3915bb82010-11-05 15:02:16 -07002887 }
2888 if (handled) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002889 finishMotionEvent(event, sendDone, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07002890 return;
2891 }
2892
Jeff Brown3915bb82010-11-05 15:02:16 -07002893 // Pointer event was unhandled.
Jeff Brown33bbfd22011-02-24 20:55:35 -08002894 finishMotionEvent(event, sendDone, false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002895 }
2896
Jeff Brown33bbfd22011-02-24 20:55:35 -08002897 private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) {
Jeff Brown3915bb82010-11-05 15:02:16 -07002898 event.recycle();
2899 if (sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07002900 finishInputEvent(event, handled);
Jeff Brown3915bb82010-11-05 15:02:16 -07002901 }
Romain Guy1c90f032011-05-24 14:59:50 -07002902 //noinspection ConstantConditions
Jeff Brown33bbfd22011-02-24 20:55:35 -08002903 if (LOCAL_LOGV || WATCH_POINTER) {
2904 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
2905 Log.i(TAG, "Done dispatching!");
2906 }
2907 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002908 }
2909
2910 private void deliverTrackballEvent(MotionEvent event, boolean sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07002911 if (ViewDebug.DEBUG_LATENCY) {
2912 mInputEventDeliverTimeNanos = System.nanoTime();
2913 }
2914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
2916
Jeff Brown21bc5c92011-02-28 18:27:14 -08002917 if (mInputEventConsistencyVerifier != null) {
2918 mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
2919 }
2920
Jeff Brown3915bb82010-11-05 15:02:16 -07002921 // If there is no view, then the event will not be handled.
2922 if (mView == null || !mAdded) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002923 finishMotionEvent(event, sendDone, false);
Jeff Brown3915bb82010-11-05 15:02:16 -07002924 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 }
2926
Jeff Brown3915bb82010-11-05 15:02:16 -07002927 // Deliver the trackball event to the view.
2928 if (mView.dispatchTrackballEvent(event)) {
2929 // If we reach this, we delivered a trackball event to mView and
2930 // mView consumed it. Because we will not translate the trackball
2931 // event into a key event, touch mode will not exit, so we exit
2932 // touch mode here.
2933 ensureTouchMode(false);
2934
Jeff Brown33bbfd22011-02-24 20:55:35 -08002935 finishMotionEvent(event, sendDone, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07002936 mLastTrackballTime = Integer.MIN_VALUE;
2937 return;
2938 }
2939
2940 // Translate the trackball event into DPAD keys and try to deliver those.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002941 final TrackballAxis x = mTrackballAxisX;
2942 final TrackballAxis y = mTrackballAxisY;
2943
2944 long curTime = SystemClock.uptimeMillis();
Jeff Brown3915bb82010-11-05 15:02:16 -07002945 if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002946 // It has been too long since the last movement,
2947 // so restart at the beginning.
2948 x.reset(0);
2949 y.reset(0);
2950 mLastTrackballTime = curTime;
2951 }
2952
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002953 final int action = event.getAction();
Jeff Brown49ed71d2010-12-06 17:13:33 -08002954 final int metaState = event.getMetaState();
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002955 switch (action) {
2956 case MotionEvent.ACTION_DOWN:
2957 x.reset(2);
2958 y.reset(2);
2959 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002960 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
2961 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2962 InputDevice.SOURCE_KEYBOARD), false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002963 break;
2964 case MotionEvent.ACTION_UP:
2965 x.reset(2);
2966 y.reset(2);
2967 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002968 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
2969 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2970 InputDevice.SOURCE_KEYBOARD), false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002971 break;
2972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002974 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
2975 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
2976 + " move=" + event.getX()
2977 + " / Y=" + y.position + " step="
2978 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
2979 + " move=" + event.getY());
2980 final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
2981 final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002983 // Generate DPAD events based on the trackball movement.
2984 // We pick the axis that has moved the most as the direction of
2985 // the DPAD. When we generate DPAD events for one axis, then the
2986 // other axis is reset -- we don't want to perform DPAD jumps due
2987 // to slight movements in the trackball when making major movements
2988 // along the other axis.
2989 int keycode = 0;
2990 int movement = 0;
2991 float accel = 1;
2992 if (xOff > yOff) {
2993 movement = x.generate((2/event.getXPrecision()));
2994 if (movement != 0) {
2995 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
2996 : KeyEvent.KEYCODE_DPAD_LEFT;
2997 accel = x.acceleration;
2998 y.reset(2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003000 } else if (yOff > 0) {
3001 movement = y.generate((2/event.getYPrecision()));
3002 if (movement != 0) {
3003 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
3004 : KeyEvent.KEYCODE_DPAD_UP;
3005 accel = y.acceleration;
3006 x.reset(2);
3007 }
3008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003010 if (keycode != 0) {
3011 if (movement < 0) movement = -movement;
3012 int accelMovement = (int)(movement * accel);
3013 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
3014 + " accelMovement=" + accelMovement
3015 + " accel=" + accel);
3016 if (accelMovement > movement) {
3017 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
3018 + keycode);
3019 movement--;
Jeff Brown49ed71d2010-12-06 17:13:33 -08003020 int repeatCount = accelMovement - movement;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003021 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003022 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
3023 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3024 InputDevice.SOURCE_KEYBOARD), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003025 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003026 while (movement > 0) {
3027 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
3028 + keycode);
3029 movement--;
3030 curTime = SystemClock.uptimeMillis();
3031 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003032 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
3033 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3034 InputDevice.SOURCE_KEYBOARD), false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003035 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003036 KeyEvent.ACTION_UP, keycode, 0, metaState,
3037 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3038 InputDevice.SOURCE_KEYBOARD), false);
3039 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003040 mLastTrackballTime = curTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003042
3043 // Unfortunately we can't tell whether the application consumed the keys, so
3044 // we always consider the trackball event handled.
Jeff Brown33bbfd22011-02-24 20:55:35 -08003045 finishMotionEvent(event, sendDone, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 }
3047
Jeff Browncb1404e2011-01-15 18:14:15 -08003048 private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07003049 if (ViewDebug.DEBUG_LATENCY) {
3050 mInputEventDeliverTimeNanos = System.nanoTime();
3051 }
3052
Jeff Brown21bc5c92011-02-28 18:27:14 -08003053 if (mInputEventConsistencyVerifier != null) {
3054 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
3055 }
3056
Jeff Browncb1404e2011-01-15 18:14:15 -08003057 final int source = event.getSource();
3058 final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
3059
3060 // If there is no view, then the event will not be handled.
3061 if (mView == null || !mAdded) {
3062 if (isJoystick) {
3063 updateJoystickDirection(event, false);
3064 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08003065 finishMotionEvent(event, sendDone, false);
Jeff Browncb1404e2011-01-15 18:14:15 -08003066 return;
3067 }
3068
3069 // Deliver the event to the view.
3070 if (mView.dispatchGenericMotionEvent(event)) {
Jeff Browncb1404e2011-01-15 18:14:15 -08003071 if (isJoystick) {
3072 updateJoystickDirection(event, false);
3073 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08003074 finishMotionEvent(event, sendDone, true);
Jeff Browncb1404e2011-01-15 18:14:15 -08003075 return;
3076 }
3077
3078 if (isJoystick) {
3079 // Translate the joystick event into DPAD keys and try to deliver those.
3080 updateJoystickDirection(event, true);
Jeff Brown33bbfd22011-02-24 20:55:35 -08003081 finishMotionEvent(event, sendDone, true);
Jeff Browncb1404e2011-01-15 18:14:15 -08003082 } else {
Jeff Brown33bbfd22011-02-24 20:55:35 -08003083 finishMotionEvent(event, sendDone, false);
Jeff Browncb1404e2011-01-15 18:14:15 -08003084 }
3085 }
3086
3087 private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) {
3088 final long time = event.getEventTime();
3089 final int metaState = event.getMetaState();
3090 final int deviceId = event.getDeviceId();
3091 final int source = event.getSource();
Jeff Brown6f2fba42011-02-19 01:08:02 -08003092
3093 int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
3094 if (xDirection == 0) {
3095 xDirection = joystickAxisValueToDirection(event.getX());
3096 }
3097
3098 int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
3099 if (yDirection == 0) {
3100 yDirection = joystickAxisValueToDirection(event.getY());
3101 }
Jeff Browncb1404e2011-01-15 18:14:15 -08003102
3103 if (xDirection != mLastJoystickXDirection) {
3104 if (mLastJoystickXKeyCode != 0) {
3105 deliverKeyEvent(new KeyEvent(time, time,
3106 KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
3107 deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
3108 mLastJoystickXKeyCode = 0;
3109 }
3110
3111 mLastJoystickXDirection = xDirection;
3112
3113 if (xDirection != 0 && synthesizeNewKeys) {
3114 mLastJoystickXKeyCode = xDirection > 0
3115 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
3116 deliverKeyEvent(new KeyEvent(time, time,
3117 KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
3118 deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
3119 }
3120 }
3121
3122 if (yDirection != mLastJoystickYDirection) {
3123 if (mLastJoystickYKeyCode != 0) {
3124 deliverKeyEvent(new KeyEvent(time, time,
3125 KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
3126 deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
3127 mLastJoystickYKeyCode = 0;
3128 }
3129
3130 mLastJoystickYDirection = yDirection;
3131
3132 if (yDirection != 0 && synthesizeNewKeys) {
3133 mLastJoystickYKeyCode = yDirection > 0
3134 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
3135 deliverKeyEvent(new KeyEvent(time, time,
3136 KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
3137 deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
3138 }
3139 }
3140 }
3141
3142 private static int joystickAxisValueToDirection(float value) {
3143 if (value >= 0.5f) {
3144 return 1;
3145 } else if (value <= -0.5f) {
3146 return -1;
3147 } else {
3148 return 0;
3149 }
3150 }
3151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003153 * Returns true if the key is used for keyboard navigation.
3154 * @param keyEvent The key event.
3155 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08003157 private static boolean isNavigationKey(KeyEvent keyEvent) {
3158 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 case KeyEvent.KEYCODE_DPAD_LEFT:
3160 case KeyEvent.KEYCODE_DPAD_RIGHT:
3161 case KeyEvent.KEYCODE_DPAD_UP:
3162 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08003163 case KeyEvent.KEYCODE_DPAD_CENTER:
3164 case KeyEvent.KEYCODE_PAGE_UP:
3165 case KeyEvent.KEYCODE_PAGE_DOWN:
3166 case KeyEvent.KEYCODE_MOVE_HOME:
3167 case KeyEvent.KEYCODE_MOVE_END:
3168 case KeyEvent.KEYCODE_TAB:
3169 case KeyEvent.KEYCODE_SPACE:
3170 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 return true;
3172 }
3173 return false;
3174 }
3175
3176 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003177 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003178 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08003179 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08003181 private static boolean isTypingKey(KeyEvent keyEvent) {
3182 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 }
3184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003186 * 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 -08003187 * @param event The key event.
3188 * @return Whether this key event should be consumed (meaning the act of
3189 * leaving touch mode alone is considered the event).
3190 */
3191 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003192 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 if (!mAttachInfo.mInTouchMode) {
3194 return false;
3195 }
3196
Jeff Brown4e6319b2010-12-13 10:36:51 -08003197 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
3198 final int action = event.getAction();
3199 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 return false;
3201 }
3202
Jeff Brown4e6319b2010-12-13 10:36:51 -08003203 // Don't leave touch mode if the IME told us not to.
3204 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
3205 return false;
3206 }
3207
3208 // If the key can be used for keyboard navigation then leave touch mode
3209 // and select a focused view if needed (in ensureTouchMode).
3210 // When a new focused view is selected, we consume the navigation key because
3211 // navigation doesn't make much sense unless a view already has focus so
3212 // the key's purpose is to set focus.
3213 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003214 return ensureTouchMode(false);
3215 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08003216
3217 // If the key can be used for typing then leave touch mode
3218 // and select a focused view if needed (in ensureTouchMode).
3219 // Always allow the view to process the typing key.
3220 if (isTypingKey(event)) {
3221 ensureTouchMode(false);
3222 return false;
3223 }
3224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 return false;
3226 }
3227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 int enqueuePendingEvent(Object event, boolean sendDone) {
3229 int seq = mPendingEventSeq+1;
3230 if (seq < 0) seq = 0;
3231 mPendingEventSeq = seq;
3232 mPendingEvents.put(seq, event);
3233 return sendDone ? seq : -seq;
3234 }
3235
3236 Object retrievePendingEvent(int seq) {
3237 if (seq < 0) seq = -seq;
3238 Object event = mPendingEvents.get(seq);
3239 if (event != null) {
3240 mPendingEvents.remove(seq);
3241 }
3242 return event;
3243 }
Romain Guy8506ab42009-06-11 17:35:47 -07003244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07003246 if (ViewDebug.DEBUG_LATENCY) {
3247 mInputEventDeliverTimeNanos = System.nanoTime();
3248 }
3249
Jeff Brown21bc5c92011-02-28 18:27:14 -08003250 if (mInputEventConsistencyVerifier != null) {
3251 mInputEventConsistencyVerifier.onKeyEvent(event, 0);
3252 }
3253
Jeff Brown3915bb82010-11-05 15:02:16 -07003254 // If there is no view, then the event will not be handled.
3255 if (mView == null || !mAdded) {
3256 finishKeyEvent(event, sendDone, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 return;
3258 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003259
3260 if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
3261
3262 // Perform predispatching before the IME.
3263 if (mView.dispatchKeyEventPreIme(event)) {
3264 finishKeyEvent(event, sendDone, true);
3265 return;
3266 }
3267
3268 // Dispatch to the IME before propagating down the view hierarchy.
3269 // The IME will eventually call back into handleFinishedEvent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 if (mLastWasImTarget) {
3271 InputMethodManager imm = InputMethodManager.peekInstance();
Jeff Brown3915bb82010-11-05 15:02:16 -07003272 if (imm != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 int seq = enqueuePendingEvent(event, sendDone);
3274 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
3275 + seq + " event=" + event);
Jeff Brown3915bb82010-11-05 15:02:16 -07003276 imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 return;
3278 }
3279 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003280
3281 // Not dispatching to IME, continue with post IME actions.
3282 deliverKeyEventPostIme(event, sendDone);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 }
3284
Jeff Brown3915bb82010-11-05 15:02:16 -07003285 private void handleFinishedEvent(int seq, boolean handled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
3287 if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
3288 + " handled=" + handled + " event=" + event);
3289 if (event != null) {
3290 final boolean sendDone = seq >= 0;
Jeff Brown3915bb82010-11-05 15:02:16 -07003291 if (handled) {
3292 finishKeyEvent(event, sendDone, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 } else {
Jeff Brown3915bb82010-11-05 15:02:16 -07003294 deliverKeyEventPostIme(event, sendDone);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 }
3296 }
3297 }
Romain Guy8506ab42009-06-11 17:35:47 -07003298
Jeff Brown3915bb82010-11-05 15:02:16 -07003299 private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07003300 if (ViewDebug.DEBUG_LATENCY) {
3301 mInputEventDeliverPostImeTimeNanos = System.nanoTime();
3302 }
3303
Jeff Brown3915bb82010-11-05 15:02:16 -07003304 // If the view went away, then the event will not be handled.
3305 if (mView == null || !mAdded) {
3306 finishKeyEvent(event, sendDone, false);
3307 return;
3308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309
Jeff Brown3915bb82010-11-05 15:02:16 -07003310 // If the key's purpose is to exit touch mode then we consume it and consider it handled.
3311 if (checkForLeavingTouchModeAndConsume(event)) {
3312 finishKeyEvent(event, sendDone, true);
3313 return;
3314 }
Romain Guy8506ab42009-06-11 17:35:47 -07003315
Jeff Brown90655042010-12-02 13:50:46 -08003316 // Make sure the fallback event policy sees all keys that will be delivered to the
3317 // view hierarchy.
3318 mFallbackEventHandler.preDispatchKeyEvent(event);
3319
Jeff Brown3915bb82010-11-05 15:02:16 -07003320 // Deliver the key to the view hierarchy.
3321 if (mView.dispatchKeyEvent(event)) {
3322 finishKeyEvent(event, sendDone, true);
3323 return;
3324 }
Joe Onorato86f67862010-11-05 18:57:34 -07003325
Jeff Brownc1df9072010-12-21 16:38:50 -08003326 // If the Control modifier is held, try to interpret the key as a shortcut.
3327 if (event.getAction() == KeyEvent.ACTION_UP
3328 && event.isCtrlPressed()
3329 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3330 if (mView.dispatchKeyShortcutEvent(event)) {
3331 finishKeyEvent(event, sendDone, true);
3332 return;
3333 }
3334 }
3335
Jeff Brown3915bb82010-11-05 15:02:16 -07003336 // Apply the fallback event policy.
3337 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3338 finishKeyEvent(event, sendDone, true);
3339 return;
3340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341
Jeff Brown3915bb82010-11-05 15:02:16 -07003342 // Handle automatic focus changes.
3343 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3344 int direction = 0;
3345 switch (event.getKeyCode()) {
3346 case KeyEvent.KEYCODE_DPAD_LEFT:
Jeff Brown4e6319b2010-12-13 10:36:51 -08003347 if (event.hasNoModifiers()) {
3348 direction = View.FOCUS_LEFT;
3349 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003350 break;
3351 case KeyEvent.KEYCODE_DPAD_RIGHT:
Jeff Brown4e6319b2010-12-13 10:36:51 -08003352 if (event.hasNoModifiers()) {
3353 direction = View.FOCUS_RIGHT;
3354 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003355 break;
3356 case KeyEvent.KEYCODE_DPAD_UP:
Jeff Brown4e6319b2010-12-13 10:36:51 -08003357 if (event.hasNoModifiers()) {
3358 direction = View.FOCUS_UP;
3359 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003360 break;
3361 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08003362 if (event.hasNoModifiers()) {
3363 direction = View.FOCUS_DOWN;
3364 }
3365 break;
3366 case KeyEvent.KEYCODE_TAB:
3367 if (event.hasNoModifiers()) {
3368 direction = View.FOCUS_FORWARD;
3369 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3370 direction = View.FOCUS_BACKWARD;
3371 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003372 break;
3373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374
Jeff Brown3915bb82010-11-05 15:02:16 -07003375 if (direction != 0) {
3376 View focused = mView != null ? mView.findFocus() : null;
3377 if (focused != null) {
3378 View v = focused.focusSearch(direction);
3379 if (v != null && v != focused) {
3380 // do the math the get the interesting rect
3381 // of previous focused into the coord system of
3382 // newly focused view
3383 focused.getFocusedRect(mTempRect);
3384 if (mView instanceof ViewGroup) {
3385 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3386 focused, mTempRect);
3387 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3388 v, mTempRect);
3389 }
3390 if (v.requestFocus(direction, mTempRect)) {
3391 playSoundEffect(
3392 SoundEffectConstants.getContantForFocusDirection(direction));
3393 finishKeyEvent(event, sendDone, true);
3394 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 }
3396 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003397
3398 // Give the focused view a last chance to handle the dpad key.
3399 if (mView.dispatchUnhandledMove(focused, direction)) {
3400 finishKeyEvent(event, sendDone, true);
3401 return;
3402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 }
3404 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406
Jeff Brown3915bb82010-11-05 15:02:16 -07003407 // Key was unhandled.
3408 finishKeyEvent(event, sendDone, false);
3409 }
3410
3411 private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) {
3412 if (sendDone) {
Jeff Brown4e91a182011-04-07 11:38:09 -07003413 finishInputEvent(event, handled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 }
3415 }
3416
Christopher Tatea53146c2010-09-07 11:57:52 -07003417 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08003418 void setLocalDragState(Object obj) {
3419 mLocalDragState = obj;
3420 }
3421
Christopher Tatea53146c2010-09-07 11:57:52 -07003422 private void handleDragEvent(DragEvent event) {
3423 // From the root, only drag start/end/location are dispatched. entered/exited
3424 // are determined and dispatched by the viewgroup hierarchy, who then report
3425 // that back here for ultimate reporting back to the framework.
3426 if (mView != null && mAdded) {
3427 final int what = event.mAction;
3428
3429 if (what == DragEvent.ACTION_DRAG_EXITED) {
3430 // A direct EXITED event means that the window manager knows we've just crossed
3431 // a window boundary, so the current drag target within this one must have
3432 // just been exited. Send it the usual notifications and then we're done
3433 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07003434 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07003435 } else {
3436 // Cache the drag description when the operation starts, then fill it in
3437 // on subsequent calls as a convenience
3438 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07003439 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07003440 mDragDescription = event.mClipDescription;
3441 } else {
3442 event.mClipDescription = mDragDescription;
3443 }
3444
3445 // For events with a [screen] location, translate into window coordinates
3446 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
3447 mDragPoint.set(event.mX, event.mY);
3448 if (mTranslator != null) {
3449 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
3450 }
3451
3452 if (mCurScrollY != 0) {
3453 mDragPoint.offset(0, mCurScrollY);
3454 }
3455
3456 event.mX = mDragPoint.x;
3457 event.mY = mDragPoint.y;
3458 }
3459
3460 // Remember who the current drag target is pre-dispatch
3461 final View prevDragView = mCurrentDragView;
3462
3463 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07003464 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07003465
3466 // If we changed apparent drag target, tell the OS about it
3467 if (prevDragView != mCurrentDragView) {
3468 try {
3469 if (prevDragView != null) {
3470 sWindowSession.dragRecipientExited(mWindow);
3471 }
3472 if (mCurrentDragView != null) {
3473 sWindowSession.dragRecipientEntered(mWindow);
3474 }
3475 } catch (RemoteException e) {
3476 Slog.e(TAG, "Unable to note drag target change");
3477 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003478 }
Chris Tated4533f12010-10-19 15:15:08 -07003479
Christopher Tate407b4e92010-11-30 17:14:08 -08003480 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07003481 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08003482 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07003483 try {
3484 Log.i(TAG, "Reporting drop result: " + result);
3485 sWindowSession.reportDropResult(mWindow, result);
3486 } catch (RemoteException e) {
3487 Log.e(TAG, "Unable to report drop result");
3488 }
3489 }
Christopher Tate407b4e92010-11-30 17:14:08 -08003490
3491 // When the drag operation ends, release any local state object
3492 // that may have been in use
3493 if (what == DragEvent.ACTION_DRAG_ENDED) {
3494 setLocalDragState(null);
3495 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003496 }
3497 }
3498 event.recycle();
3499 }
3500
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003501 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
3502 if (mSeq != args.seq) {
3503 // The sequence has changed, so we need to update our value and make
3504 // sure to do a traversal afterward so the window manager is given our
3505 // most recent data.
3506 mSeq = args.seq;
3507 mAttachInfo.mForceReportNewAttributes = true;
3508 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08003509 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003510 if (mView == null) return;
3511 if (args.localChanges != 0) {
3512 if (mAttachInfo != null) {
3513 mAttachInfo.mSystemUiVisibility =
3514 (mAttachInfo.mSystemUiVisibility&~args.localChanges)
3515 | (args.localValue&args.localChanges);
3516 }
3517 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
3518 mAttachInfo.mRecomputeGlobalAttributes = true;
3519 scheduleTraversals();
3520 }
3521 mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
Joe Onorato664644d2011-01-23 17:53:23 -08003522 }
3523
Christopher Tate2c095f32010-10-04 14:13:40 -07003524 public void getLastTouchPoint(Point outLocation) {
3525 outLocation.x = (int) mLastTouchPoint.x;
3526 outLocation.y = (int) mLastTouchPoint.y;
3527 }
3528
Chris Tate9d1ab882010-11-02 15:55:39 -07003529 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07003530 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07003531 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07003532 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003533 }
3534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 private AudioManager getAudioManager() {
3536 if (mView == null) {
3537 throw new IllegalStateException("getAudioManager called when there is no mView");
3538 }
3539 if (mAudioManager == null) {
3540 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
3541 }
3542 return mAudioManager;
3543 }
3544
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003545 public AccessibilityInteractionController getAccessibilityInteractionController() {
3546 if (mView == null) {
3547 throw new IllegalStateException("getAccessibilityInteractionController"
3548 + " called when there is no mView");
3549 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07003550 if (mAccessibilityInteractionController == null) {
3551 mAccessibilityInteractionController = new AccessibilityInteractionController();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003552 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07003553 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003554 }
3555
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003556 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
3557 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003558
3559 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003560 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003561 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07003562 restore = true;
3563 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003564 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003565 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003566 if (params != null) {
3567 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003568 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003569 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07003570 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07003571 if (params != null && mOrigWindowType != params.type) {
3572 // For compatibility with old apps, don't crash here.
3573 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
3574 Slog.w(TAG, "Window type can not be changed after "
3575 + "the window is added; ignoring change of " + mView);
3576 params.type = mOrigWindowType;
3577 }
3578 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003579 int relayoutResult = sWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003580 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08003581 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
3582 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003583 viewVisibility, insetsPending, mWinFrame,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003584 mPendingContentInsets, mPendingVisibleInsets,
3585 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07003586 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003587 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07003588 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003589 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003590
3591 if (mTranslator != null) {
3592 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
3593 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
3594 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003595 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003596 return relayoutResult;
3597 }
Romain Guy8506ab42009-06-11 17:35:47 -07003598
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003599 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 * {@inheritDoc}
3601 */
3602 public void playSoundEffect(int effectId) {
3603 checkThread();
3604
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07003605 try {
3606 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003607
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07003608 switch (effectId) {
3609 case SoundEffectConstants.CLICK:
3610 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
3611 return;
3612 case SoundEffectConstants.NAVIGATION_DOWN:
3613 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
3614 return;
3615 case SoundEffectConstants.NAVIGATION_LEFT:
3616 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
3617 return;
3618 case SoundEffectConstants.NAVIGATION_RIGHT:
3619 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
3620 return;
3621 case SoundEffectConstants.NAVIGATION_UP:
3622 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
3623 return;
3624 default:
3625 throw new IllegalArgumentException("unknown effect id " + effectId +
3626 " not defined in " + SoundEffectConstants.class.getCanonicalName());
3627 }
3628 } catch (IllegalStateException e) {
3629 // Exception thrown by getAudioManager() when mView is null
3630 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
3631 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003632 }
3633 }
3634
3635 /**
3636 * {@inheritDoc}
3637 */
3638 public boolean performHapticFeedback(int effectId, boolean always) {
3639 try {
3640 return sWindowSession.performHapticFeedback(mWindow, effectId, always);
3641 } catch (RemoteException e) {
3642 return false;
3643 }
3644 }
3645
3646 /**
3647 * {@inheritDoc}
3648 */
3649 public View focusSearch(View focused, int direction) {
3650 checkThread();
3651 if (!(mView instanceof ViewGroup)) {
3652 return null;
3653 }
3654 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
3655 }
3656
3657 public void debug() {
3658 mView.debug();
3659 }
Romain Guy65b345f2011-07-27 18:51:50 -07003660
3661 public void dumpGfxInfo(PrintWriter pw, int[] info) {
3662 if (mView != null) {
3663 getGfxInfo(mView, info);
3664 } else {
3665 info[0] = info[1] = 0;
3666 }
3667 }
3668
3669 private void getGfxInfo(View view, int[] info) {
3670 DisplayList displayList = view.mDisplayList;
3671 info[0]++;
3672 if (displayList != null) {
3673 info[1] += displayList.getSize();
3674 }
3675
3676 if (view instanceof ViewGroup) {
3677 ViewGroup group = (ViewGroup) view;
3678
3679 int count = group.getChildCount();
3680 for (int i = 0; i < count; i++) {
3681 getGfxInfo(group.getChildAt(i), info);
3682 }
3683 }
3684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003685
3686 public void die(boolean immediate) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07003687 if (immediate) {
3688 doDie();
3689 } else {
3690 sendEmptyMessage(DIE);
3691 }
3692 }
3693
3694 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07003696 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003697 synchronized (this) {
Romain Guy16260e72011-09-01 14:26:11 -07003698 if (mAdded) {
3699 mAdded = false;
3700 dispatchDetachedFromWindow();
3701 }
3702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07003704 destroyHardwareRenderer();
3705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 int viewVisibility = mView.getVisibility();
3707 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
3708 if (mWindowAttributesChanged || viewVisibilityChanged) {
3709 // If layout params have been changed, first give them
3710 // to the window manager to make sure it has the correct
3711 // animation info.
3712 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003713 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
3714 & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715 sWindowSession.finishDrawing(mWindow);
3716 }
3717 } catch (RemoteException e) {
3718 }
3719 }
3720
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003721 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 }
3724 }
3725
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003726 public void requestUpdateConfiguration(Configuration config) {
3727 Message msg = obtainMessage(UPDATE_CONFIGURATION, config);
3728 sendMessage(msg);
3729 }
3730
Romain Guy29d89972010-09-22 16:10:57 -07003731 private void destroyHardwareRenderer() {
Romain Guyb051e892010-09-28 19:09:36 -07003732 if (mAttachInfo.mHardwareRenderer != null) {
3733 mAttachInfo.mHardwareRenderer.destroy(true);
3734 mAttachInfo.mHardwareRenderer = null;
Romain Guy29d89972010-09-22 16:10:57 -07003735 mAttachInfo.mHardwareAccelerated = false;
3736 }
3737 }
3738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 public void dispatchFinishedEvent(int seq, boolean handled) {
3740 Message msg = obtainMessage(FINISHED_EVENT);
3741 msg.arg1 = seq;
3742 msg.arg2 = handled ? 1 : 0;
3743 sendMessage(msg);
3744 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 public void dispatchResized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08003747 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003748 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
3749 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
3750 + " visibleInsets=" + visibleInsets.toShortString()
3751 + " reportDraw=" + reportDraw);
3752 Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003753 if (mTranslator != null) {
3754 mTranslator.translateRectInScreenToAppWindow(coveredInsets);
3755 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
3756 w *= mTranslator.applicationInvertedScale;
3757 h *= mTranslator.applicationInvertedScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003758 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003759 msg.arg1 = w;
3760 msg.arg2 = h;
Dianne Hackborne36d6e22010-02-17 19:46:25 -08003761 ResizedInfo ri = new ResizedInfo();
3762 ri.coveredInsets = new Rect(coveredInsets);
3763 ri.visibleInsets = new Rect(visibleInsets);
3764 ri.newConfig = newConfig;
3765 msg.obj = ri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766 sendMessage(msg);
3767 }
Chet Haase1f4786b2011-11-02 10:51:52 -07003768
Jeff Brown4e91a182011-04-07 11:38:09 -07003769 private long mInputEventReceiveTimeNanos;
3770 private long mInputEventDeliverTimeNanos;
3771 private long mInputEventDeliverPostImeTimeNanos;
Jeff Brown3915bb82010-11-05 15:02:16 -07003772 private InputQueue.FinishedCallback mFinishedCallback;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003773
3774 private final InputHandler mInputHandler = new InputHandler() {
Jeff Brown3915bb82010-11-05 15:02:16 -07003775 public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) {
Romain Guy1c90f032011-05-24 14:59:50 -07003776 startInputEvent(finishedCallback);
Jeff Brown92ff1dd2010-08-11 16:16:06 -07003777 dispatchKey(event, true);
Jeff Brown46b9ac02010-04-22 18:58:52 -07003778 }
3779
Jeff Brown3915bb82010-11-05 15:02:16 -07003780 public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
Romain Guy1c90f032011-05-24 14:59:50 -07003781 startInputEvent(finishedCallback);
Jeff Brown93ed4e32010-09-23 13:51:48 -07003782 dispatchMotion(event, true);
Jeff Brown46b9ac02010-04-22 18:58:52 -07003783 }
3784 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003785
Chet Haase1f4786b2011-11-02 10:51:52 -07003786 /**
3787 * Utility class used to queue up input events which are then handled during
3788 * performTraversals(). Doing it this way allows us to ensure that we are up to date with
3789 * all input events just prior to drawing, instead of placing those events on the regular
3790 * handler queue, potentially behind a drawing event.
3791 */
3792 static class InputEventMessage {
3793 Message mMessage;
3794 InputEventMessage mNext;
3795
3796 private static final Object sPoolSync = new Object();
3797 private static InputEventMessage sPool;
3798 private static int sPoolSize = 0;
3799
3800 private static final int MAX_POOL_SIZE = 10;
3801
3802 private InputEventMessage(Message m) {
3803 mMessage = m;
3804 mNext = null;
3805 }
3806
3807 /**
3808 * Return a new Message instance from the global pool. Allows us to
3809 * avoid allocating new objects in many cases.
3810 */
3811 public static InputEventMessage obtain(Message msg) {
3812 synchronized (sPoolSync) {
3813 if (sPool != null) {
3814 InputEventMessage m = sPool;
3815 sPool = m.mNext;
3816 m.mNext = null;
3817 sPoolSize--;
3818 m.mMessage = msg;
3819 return m;
3820 }
3821 }
3822 return new InputEventMessage(msg);
3823 }
3824
3825 /**
3826 * Return the message to the pool.
3827 */
3828 public void recycle() {
3829 mMessage.recycle();
3830 synchronized (sPoolSync) {
3831 if (sPoolSize < MAX_POOL_SIZE) {
3832 mNext = sPool;
3833 sPool = this;
3834 sPoolSize++;
3835 }
3836 }
3837
3838 }
3839 }
3840
3841 /**
3842 * Place the input event message at the end of the current pending list
3843 */
3844 private void enqueueInputEvent(Message msg, long when) {
3845 InputEventMessage inputMessage = InputEventMessage.obtain(msg);
3846 if (mPendingInputEvents == null) {
3847 mPendingInputEvents = inputMessage;
3848 } else {
3849 InputEventMessage currMessage = mPendingInputEvents;
3850 while (currMessage.mNext != null) {
3851 currMessage = currMessage.mNext;
3852 }
3853 currMessage.mNext = inputMessage;
3854 }
3855 sendEmptyMessageAtTime(PROCESS_INPUT_EVENTS, when);
3856 }
3857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 public void dispatchKey(KeyEvent event) {
Jeff Brown92ff1dd2010-08-11 16:16:06 -07003859 dispatchKey(event, false);
3860 }
3861
3862 private void dispatchKey(KeyEvent event, boolean sendDone) {
3863 //noinspection ConstantConditions
3864 if (false && event.getAction() == KeyEvent.ACTION_DOWN) {
3865 if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
Romain Guy812ccbe2010-06-01 14:07:24 -07003866 if (DBG) Log.d("keydisp", "===================================================");
3867 if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
3868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003869 debug();
3870
Romain Guy812ccbe2010-06-01 14:07:24 -07003871 if (DBG) Log.d("keydisp", "===================================================");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872 }
3873 }
3874
3875 Message msg = obtainMessage(DISPATCH_KEY);
3876 msg.obj = event;
Jeff Brown92ff1dd2010-08-11 16:16:06 -07003877 msg.arg1 = sendDone ? 1 : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878
3879 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07003880 TAG, "sending key " + event + " to " + mView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003881
Chet Haase1f4786b2011-11-02 10:51:52 -07003882 enqueueInputEvent(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003883 }
Jeff Brownc5ed5912010-07-14 18:48:53 -07003884
Jeff Brown93ed4e32010-09-23 13:51:48 -07003885 private void dispatchMotion(MotionEvent event, boolean sendDone) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07003886 int source = event.getSource();
3887 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003888 dispatchPointer(event, sendDone);
Jeff Brownc5ed5912010-07-14 18:48:53 -07003889 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003890 dispatchTrackball(event, sendDone);
Jeff Brownc5ed5912010-07-14 18:48:53 -07003891 } else {
Jeff Browncb1404e2011-01-15 18:14:15 -08003892 dispatchGenericMotion(event, sendDone);
Jeff Brownc5ed5912010-07-14 18:48:53 -07003893 }
3894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003895
Jeff Brown93ed4e32010-09-23 13:51:48 -07003896 private void dispatchPointer(MotionEvent event, boolean sendDone) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003897 Message msg = obtainMessage(DISPATCH_POINTER);
3898 msg.obj = event;
Jeff Brown93ed4e32010-09-23 13:51:48 -07003899 msg.arg1 = sendDone ? 1 : 0;
Chet Haase1f4786b2011-11-02 10:51:52 -07003900 enqueueInputEvent(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901 }
3902
Jeff Brown93ed4e32010-09-23 13:51:48 -07003903 private void dispatchTrackball(MotionEvent event, boolean sendDone) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003904 Message msg = obtainMessage(DISPATCH_TRACKBALL);
3905 msg.obj = event;
Jeff Brown93ed4e32010-09-23 13:51:48 -07003906 msg.arg1 = sendDone ? 1 : 0;
Chet Haase1f4786b2011-11-02 10:51:52 -07003907 enqueueInputEvent(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003908 }
Jeff Browncb1404e2011-01-15 18:14:15 -08003909
3910 private void dispatchGenericMotion(MotionEvent event, boolean sendDone) {
3911 Message msg = obtainMessage(DISPATCH_GENERIC_MOTION);
3912 msg.obj = event;
3913 msg.arg1 = sendDone ? 1 : 0;
Chet Haase1f4786b2011-11-02 10:51:52 -07003914 enqueueInputEvent(msg, event.getEventTime());
Jeff Browncb1404e2011-01-15 18:14:15 -08003915 }
3916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003917 public void dispatchAppVisibility(boolean visible) {
3918 Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
3919 msg.arg1 = visible ? 1 : 0;
3920 sendMessage(msg);
3921 }
3922
3923 public void dispatchGetNewSurface() {
3924 Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
3925 sendMessage(msg);
3926 }
3927
3928 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
3929 Message msg = Message.obtain();
3930 msg.what = WINDOW_FOCUS_CHANGED;
3931 msg.arg1 = hasFocus ? 1 : 0;
3932 msg.arg2 = inTouchMode ? 1 : 0;
3933 sendMessage(msg);
3934 }
3935
Dianne Hackbornffa42482009-09-23 22:20:11 -07003936 public void dispatchCloseSystemDialogs(String reason) {
3937 Message msg = Message.obtain();
3938 msg.what = CLOSE_SYSTEM_DIALOGS;
3939 msg.obj = reason;
3940 sendMessage(msg);
3941 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003942
3943 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07003944 final int what;
3945 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
3946 what = DISPATCH_DRAG_LOCATION_EVENT;
3947 removeMessages(what);
3948 } else {
3949 what = DISPATCH_DRAG_EVENT;
3950 }
3951 Message msg = obtainMessage(what, event);
Christopher Tatea53146c2010-09-07 11:57:52 -07003952 sendMessage(msg);
3953 }
3954
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003955 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
3956 int localValue, int localChanges) {
3957 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
3958 args.seq = seq;
3959 args.globalVisibility = globalVisibility;
3960 args.localValue = localValue;
3961 args.localChanges = localChanges;
3962 sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, args));
Joe Onorato664644d2011-01-23 17:53:23 -08003963 }
3964
svetoslavganov75986cf2009-05-14 22:28:01 -07003965 /**
3966 * The window is getting focus so if there is anything focused/selected
3967 * send an {@link AccessibilityEvent} to announce that.
3968 */
3969 private void sendAccessibilityEvents() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003970 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07003971 return;
3972 }
3973 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
3974 View focusedView = mView.findFocus();
3975 if (focusedView != null && focusedView != mView) {
3976 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
3977 }
3978 }
3979
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003980 /**
3981 * Post a callback to send a
3982 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07003983 * This event is send at most once every
3984 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003985 */
3986 private void postSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07003987 if (mSendWindowContentChangedAccessibilityEvent == null) {
3988 mSendWindowContentChangedAccessibilityEvent =
3989 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003990 }
Svetoslav Ganova0156172011-06-26 17:55:44 -07003991 if (!mSendWindowContentChangedAccessibilityEvent.mIsPending) {
3992 mSendWindowContentChangedAccessibilityEvent.mIsPending = true;
3993 postDelayed(mSendWindowContentChangedAccessibilityEvent,
3994 ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
3995 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003996 }
3997
3998 /**
3999 * Remove a posted callback to send a
4000 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
4001 */
4002 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07004003 if (mSendWindowContentChangedAccessibilityEvent != null) {
4004 removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004005 }
4006 }
4007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004008 public boolean showContextMenuForChild(View originalView) {
4009 return false;
4010 }
4011
Adam Powell6e346362010-07-23 10:18:23 -07004012 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
4013 return null;
4014 }
4015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004016 public void createContextMenu(ContextMenu menu) {
4017 }
4018
4019 public void childDrawableStateChanged(View child) {
4020 }
4021
Svetoslav Ganov736c2752011-04-22 18:30:36 -07004022 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
4023 if (mView == null) {
4024 return false;
4025 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004026 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07004027 return true;
4028 }
4029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004030 void checkThread() {
4031 if (mThread != Thread.currentThread()) {
4032 throw new CalledFromWrongThreadException(
4033 "Only the original thread that created a view hierarchy can touch its views.");
4034 }
4035 }
4036
4037 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07004038 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004039 }
4040
4041 public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
4042 boolean immediate) {
4043 return scrollToRectOrFocus(rectangle, immediate);
4044 }
Romain Guy8506ab42009-06-11 17:35:47 -07004045
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07004046 class TakenSurfaceHolder extends BaseSurfaceHolder {
4047 @Override
4048 public boolean onAllowLockCanvas() {
4049 return mDrawingAllowed;
4050 }
4051
4052 @Override
4053 public void onRelayoutContainer() {
4054 // Not currently interesting -- from changing between fixed and layout size.
4055 }
4056
4057 public void setFormat(int format) {
4058 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
4059 }
4060
4061 public void setType(int type) {
4062 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
4063 }
4064
4065 @Override
4066 public void onUpdateSurface() {
4067 // We take care of format and type changes on our own.
4068 throw new IllegalStateException("Shouldn't be here");
4069 }
4070
4071 public boolean isCreating() {
4072 return mIsCreating;
4073 }
4074
4075 @Override
4076 public void setFixedSize(int width, int height) {
4077 throw new UnsupportedOperationException(
4078 "Currently only support sizing from layout");
4079 }
4080
4081 public void setKeepScreenOn(boolean screenOn) {
4082 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
4083 }
4084 }
4085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004086 static class InputMethodCallback extends IInputMethodCallback.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004087 private WeakReference<ViewRootImpl> mViewAncestor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004089 public InputMethodCallback(ViewRootImpl viewAncestor) {
4090 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 }
Romain Guy8506ab42009-06-11 17:35:47 -07004092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004093 public void finishedEvent(int seq, boolean handled) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004094 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004095 if (viewAncestor != null) {
4096 viewAncestor.dispatchFinishedEvent(seq, handled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 }
4098 }
4099
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004100 public void sessionCreated(IInputMethodSession session) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004101 // Stub -- not for use in the client.
4102 }
4103 }
Romain Guy8506ab42009-06-11 17:35:47 -07004104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004105 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004106 private final WeakReference<ViewRootImpl> mViewAncestor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004108 W(ViewRootImpl viewAncestor) {
4109 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004110 }
4111
Romain Guyfb8b7632010-08-23 21:05:08 -07004112 public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
4113 boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004114 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004115 if (viewAncestor != null) {
4116 viewAncestor.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw,
4117 newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004118 }
4119 }
4120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004121 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004122 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004123 if (viewAncestor != null) {
4124 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 }
4126 }
4127
4128 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004129 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004130 if (viewAncestor != null) {
4131 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 }
4133 }
4134
4135 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004136 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004137 if (viewAncestor != null) {
4138 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 }
4140 }
4141
4142 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004143 try {
4144 return ActivityManagerNative.getDefault().checkPermission(
4145 permission, Binder.getCallingPid(), Binder.getCallingUid());
4146 } catch (RemoteException e) {
4147 return PackageManager.PERMISSION_DENIED;
4148 }
4149 }
4150
4151 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004152 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004153 if (viewAncestor != null) {
4154 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004155 if (view != null) {
4156 if (checkCallingPermission(Manifest.permission.DUMP) !=
4157 PackageManager.PERMISSION_GRANTED) {
4158 throw new SecurityException("Insufficient permissions to invoke"
4159 + " executeCommand() from pid=" + Binder.getCallingPid()
4160 + ", uid=" + Binder.getCallingUid());
4161 }
4162
4163 OutputStream clientStream = null;
4164 try {
4165 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
4166 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
4167 } catch (IOException e) {
4168 e.printStackTrace();
4169 } finally {
4170 if (clientStream != null) {
4171 try {
4172 clientStream.close();
4173 } catch (IOException e) {
4174 e.printStackTrace();
4175 }
4176 }
4177 }
4178 }
4179 }
4180 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07004181
Dianne Hackbornffa42482009-09-23 22:20:11 -07004182 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004183 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004184 if (viewAncestor != null) {
4185 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07004186 }
4187 }
4188
Marco Nelissenbf6956b2009-11-09 15:21:13 -08004189 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
4190 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07004191 if (sync) {
4192 try {
4193 sWindowSession.wallpaperOffsetsComplete(asBinder());
4194 } catch (RemoteException e) {
4195 }
4196 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07004197 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004198
Dianne Hackborn75804932009-10-20 20:15:20 -07004199 public void dispatchWallpaperCommand(String action, int x, int y,
4200 int z, Bundle extras, boolean sync) {
4201 if (sync) {
4202 try {
4203 sWindowSession.wallpaperCommandComplete(asBinder(), null);
4204 } catch (RemoteException e) {
4205 }
4206 }
4207 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004208
4209 /* Drag/drop */
4210 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004211 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004212 if (viewAncestor != null) {
4213 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004214 }
4215 }
Joe Onorato664644d2011-01-23 17:53:23 -08004216
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004217 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
4218 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004219 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004220 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004221 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
4222 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08004223 }
4224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004225 }
4226
4227 /**
4228 * Maintains state information for a single trackball axis, generating
4229 * discrete (DPAD) movements based on raw trackball motion.
4230 */
4231 static final class TrackballAxis {
4232 /**
4233 * The maximum amount of acceleration we will apply.
4234 */
4235 static final float MAX_ACCELERATION = 20;
Romain Guy8506ab42009-06-11 17:35:47 -07004236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004237 /**
4238 * The maximum amount of time (in milliseconds) between events in order
4239 * for us to consider the user to be doing fast trackball movements,
4240 * and thus apply an acceleration.
4241 */
4242 static final long FAST_MOVE_TIME = 150;
Romain Guy8506ab42009-06-11 17:35:47 -07004243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004244 /**
4245 * Scaling factor to the time (in milliseconds) between events to how
4246 * much to multiple/divide the current acceleration. When movement
4247 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4248 * FAST_MOVE_TIME it divides it.
4249 */
4250 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
Romain Guy8506ab42009-06-11 17:35:47 -07004251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 float position;
4253 float absPosition;
4254 float acceleration = 1;
4255 long lastMoveTime = 0;
4256 int step;
4257 int dir;
4258 int nonAccelMovement;
4259
4260 void reset(int _step) {
4261 position = 0;
4262 acceleration = 1;
4263 lastMoveTime = 0;
4264 step = _step;
4265 dir = 0;
4266 }
4267
4268 /**
4269 * Add trackball movement into the state. If the direction of movement
4270 * has been reversed, the state is reset before adding the
4271 * movement (so that you don't have to compensate for any previously
4272 * collected movement before see the result of the movement in the
4273 * new direction).
4274 *
4275 * @return Returns the absolute value of the amount of movement
4276 * collected so far.
4277 */
4278 float collect(float off, long time, String axis) {
4279 long normTime;
4280 if (off > 0) {
4281 normTime = (long)(off * FAST_MOVE_TIME);
4282 if (dir < 0) {
4283 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4284 position = 0;
4285 step = 0;
4286 acceleration = 1;
4287 lastMoveTime = 0;
4288 }
4289 dir = 1;
4290 } else if (off < 0) {
4291 normTime = (long)((-off) * FAST_MOVE_TIME);
4292 if (dir > 0) {
4293 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4294 position = 0;
4295 step = 0;
4296 acceleration = 1;
4297 lastMoveTime = 0;
4298 }
4299 dir = -1;
4300 } else {
4301 normTime = 0;
4302 }
Romain Guy8506ab42009-06-11 17:35:47 -07004303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004304 // The number of milliseconds between each movement that is
4305 // considered "normal" and will not result in any acceleration
4306 // or deceleration, scaled by the offset we have here.
4307 if (normTime > 0) {
4308 long delta = time - lastMoveTime;
4309 lastMoveTime = time;
4310 float acc = acceleration;
4311 if (delta < normTime) {
4312 // The user is scrolling rapidly, so increase acceleration.
4313 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4314 if (scale > 1) acc *= scale;
4315 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4316 + off + " normTime=" + normTime + " delta=" + delta
4317 + " scale=" + scale + " acc=" + acc);
4318 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4319 } else {
4320 // The user is scrolling slowly, so decrease acceleration.
4321 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4322 if (scale > 1) acc /= scale;
4323 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4324 + off + " normTime=" + normTime + " delta=" + delta
4325 + " scale=" + scale + " acc=" + acc);
4326 acceleration = acc > 1 ? acc : 1;
4327 }
4328 }
4329 position += off;
4330 return (absPosition = Math.abs(position));
4331 }
4332
4333 /**
4334 * Generate the number of discrete movement events appropriate for
4335 * the currently collected trackball movement.
4336 *
4337 * @param precision The minimum movement required to generate the
4338 * first discrete movement.
4339 *
4340 * @return Returns the number of discrete movements, either positive
4341 * or negative, or 0 if there is not enough trackball movement yet
4342 * for a discrete movement.
4343 */
4344 int generate(float precision) {
4345 int movement = 0;
4346 nonAccelMovement = 0;
4347 do {
4348 final int dir = position >= 0 ? 1 : -1;
4349 switch (step) {
4350 // If we are going to execute the first step, then we want
4351 // to do this as soon as possible instead of waiting for
4352 // a full movement, in order to make things look responsive.
4353 case 0:
4354 if (absPosition < precision) {
4355 return movement;
4356 }
4357 movement += dir;
4358 nonAccelMovement += dir;
4359 step = 1;
4360 break;
4361 // If we have generated the first movement, then we need
4362 // to wait for the second complete trackball motion before
4363 // generating the second discrete movement.
4364 case 1:
4365 if (absPosition < 2) {
4366 return movement;
4367 }
4368 movement += dir;
4369 nonAccelMovement += dir;
4370 position += dir > 0 ? -2 : 2;
4371 absPosition = Math.abs(position);
4372 step = 2;
4373 break;
4374 // After the first two, we generate discrete movements
4375 // consistently with the trackball, applying an acceleration
4376 // if the trackball is moving quickly. This is a simple
4377 // acceleration on top of what we already compute based
4378 // on how quickly the wheel is being turned, to apply
4379 // a longer increasing acceleration to continuous movement
4380 // in one direction.
4381 default:
4382 if (absPosition < 1) {
4383 return movement;
4384 }
4385 movement += dir;
4386 position += dir >= 0 ? -1 : 1;
4387 absPosition = Math.abs(position);
4388 float acc = acceleration;
4389 acc *= 1.1f;
4390 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4391 break;
4392 }
4393 } while (true);
4394 }
4395 }
4396
4397 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
4398 public CalledFromWrongThreadException(String msg) {
4399 super(msg);
4400 }
4401 }
4402
4403 private SurfaceHolder mHolder = new SurfaceHolder() {
4404 // we only need a SurfaceHolder for opengl. it would be nice
4405 // to implement everything else though, especially the callback
4406 // support (opengl doesn't make use of it right now, but eventually
4407 // will).
4408 public Surface getSurface() {
4409 return mSurface;
4410 }
4411
4412 public boolean isCreating() {
4413 return false;
4414 }
4415
4416 public void addCallback(Callback callback) {
4417 }
4418
4419 public void removeCallback(Callback callback) {
4420 }
4421
4422 public void setFixedSize(int width, int height) {
4423 }
4424
4425 public void setSizeFromLayout() {
4426 }
4427
4428 public void setFormat(int format) {
4429 }
4430
4431 public void setType(int type) {
4432 }
4433
4434 public void setKeepScreenOn(boolean screenOn) {
4435 }
4436
4437 public Canvas lockCanvas() {
4438 return null;
4439 }
4440
4441 public Canvas lockCanvas(Rect dirty) {
4442 return null;
4443 }
4444
4445 public void unlockCanvasAndPost(Canvas canvas) {
4446 }
4447 public Rect getSurfaceFrame() {
4448 return null;
4449 }
4450 };
4451
4452 static RunQueue getRunQueue() {
4453 RunQueue rq = sRunQueues.get();
4454 if (rq != null) {
4455 return rq;
4456 }
4457 rq = new RunQueue();
4458 sRunQueues.set(rq);
4459 return rq;
4460 }
Romain Guy8506ab42009-06-11 17:35:47 -07004461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004462 /**
4463 * @hide
4464 */
4465 static final class RunQueue {
4466 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
4467
4468 void post(Runnable action) {
4469 postDelayed(action, 0);
4470 }
4471
4472 void postDelayed(Runnable action, long delayMillis) {
4473 HandlerAction handlerAction = new HandlerAction();
4474 handlerAction.action = action;
4475 handlerAction.delay = delayMillis;
4476
4477 synchronized (mActions) {
4478 mActions.add(handlerAction);
4479 }
4480 }
4481
4482 void removeCallbacks(Runnable action) {
4483 final HandlerAction handlerAction = new HandlerAction();
4484 handlerAction.action = action;
4485
4486 synchronized (mActions) {
4487 final ArrayList<HandlerAction> actions = mActions;
4488
4489 while (actions.remove(handlerAction)) {
4490 // Keep going
4491 }
4492 }
4493 }
4494
4495 void executeActions(Handler handler) {
4496 synchronized (mActions) {
4497 final ArrayList<HandlerAction> actions = mActions;
4498 final int count = actions.size();
4499
4500 for (int i = 0; i < count; i++) {
4501 final HandlerAction handlerAction = actions.get(i);
4502 handler.postDelayed(handlerAction.action, handlerAction.delay);
4503 }
4504
Romain Guy15df6702009-08-17 20:17:30 -07004505 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004506 }
4507 }
4508
4509 private static class HandlerAction {
4510 Runnable action;
4511 long delay;
4512
4513 @Override
4514 public boolean equals(Object o) {
4515 if (this == o) return true;
4516 if (o == null || getClass() != o.getClass()) return false;
4517
4518 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004519 return !(action != null ? !action.equals(that.action) : that.action != null);
4520
4521 }
4522
4523 @Override
4524 public int hashCode() {
4525 int result = action != null ? action.hashCode() : 0;
4526 result = 31 * result + (int) (delay ^ (delay >>> 32));
4527 return result;
4528 }
4529 }
4530 }
4531
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004532 /**
4533 * Class for managing the accessibility interaction connection
4534 * based on the global accessibility state.
4535 */
4536 final class AccessibilityInteractionConnectionManager
4537 implements AccessibilityStateChangeListener {
4538 public void onAccessibilityStateChanged(boolean enabled) {
4539 if (enabled) {
4540 ensureConnection();
4541 } else {
4542 ensureNoConnection();
4543 }
4544 }
4545
4546 public void ensureConnection() {
4547 final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
4548 if (!registered) {
4549 mAttachInfo.mAccessibilityWindowId =
4550 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004551 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004552 }
4553 }
4554
4555 public void ensureNoConnection() {
4556 final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
4557 if (registered) {
4558 mAttachInfo.mAccessibilityWindowId = View.NO_ID;
4559 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
4560 }
4561 }
4562 }
4563
4564 /**
4565 * This class is an interface this ViewAncestor provides to the
4566 * AccessibilityManagerService to the latter can interact with
4567 * the view hierarchy in this ViewAncestor.
4568 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07004569 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004570 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004571 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004572
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07004573 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
4574 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004575 }
4576
Svetoslav Ganov02107852011-10-03 17:06:56 -07004577 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004578 int interactionId, IAccessibilityInteractionConnectionCallback callback,
4579 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004580 ViewRootImpl viewRootImpl = mViewRootImpl.get();
4581 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07004582 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07004583 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004584 interactionId, callback, interrogatingPid, interrogatingTid);
Svetoslav Ganov601ad802011-06-09 14:47:38 -07004585 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004586 }
4587
Svetoslav Ganov02107852011-10-03 17:06:56 -07004588 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004589 int interactionId, IAccessibilityInteractionConnectionCallback callback,
4590 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004591 ViewRootImpl viewRootImpl = mViewRootImpl.get();
4592 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07004593 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07004594 .performAccessibilityActionClientThread(accessibilityNodeId, action,
4595 interactionId, callback, interogatingPid, interrogatingTid);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004596 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004597 }
4598
4599 public void findAccessibilityNodeInfoByViewId(int viewId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004600 int interactionId, IAccessibilityInteractionConnectionCallback callback,
4601 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004602 ViewRootImpl viewRootImpl = mViewRootImpl.get();
4603 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07004604 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004605 .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback,
4606 interrogatingPid, interrogatingTid);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004607 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004608 }
4609
Svetoslav Ganov02107852011-10-03 17:06:56 -07004610 public void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004611 int interactionId, IAccessibilityInteractionConnectionCallback callback,
4612 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004613 ViewRootImpl viewRootImpl = mViewRootImpl.get();
4614 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07004615 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovf31aba72011-10-28 16:41:13 -07004616 .findAccessibilityNodeInfosByTextClientThread(text, accessibilityNodeId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004617 interactionId, callback, interrogatingPid, interrogatingTid);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004618 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004619 }
4620 }
4621
4622 /**
4623 * Class for managing accessibility interactions initiated from the system
4624 * and targeting the view hierarchy. A *ClientThread method is to be
4625 * called from the interaction connection this ViewAncestor gives the
4626 * system to talk to it and a corresponding *UiThread method that is executed
4627 * on the UI thread.
4628 */
4629 final class AccessibilityInteractionController {
4630 private static final int POOL_SIZE = 5;
4631
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004632 private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
4633 new ArrayList<AccessibilityNodeInfo>();
4634
4635 // Reusable poolable arguments for interacting with the view hierarchy
4636 // to fit more arguments than Message and to avoid sharing objects between
4637 // two messages since several threads can send messages concurrently.
4638 private final Pool<SomeArgs> mPool = Pools.synchronizedPool(Pools.finitePool(
4639 new PoolableManager<SomeArgs>() {
4640 public SomeArgs newInstance() {
4641 return new SomeArgs();
4642 }
4643
4644 public void onAcquired(SomeArgs info) {
4645 /* do nothing */
4646 }
4647
4648 public void onReleased(SomeArgs info) {
4649 info.clear();
4650 }
4651 }, POOL_SIZE)
4652 );
4653
4654 public class SomeArgs implements Poolable<SomeArgs> {
4655 private SomeArgs mNext;
4656 private boolean mIsPooled;
4657
4658 public Object arg1;
4659 public Object arg2;
4660 public int argi1;
4661 public int argi2;
4662 public int argi3;
4663
4664 public SomeArgs getNextPoolable() {
4665 return mNext;
4666 }
4667
4668 public boolean isPooled() {
4669 return mIsPooled;
4670 }
4671
4672 public void setNextPoolable(SomeArgs args) {
4673 mNext = args;
4674 }
4675
4676 public void setPooled(boolean isPooled) {
4677 mIsPooled = isPooled;
4678 }
4679
4680 private void clear() {
4681 arg1 = null;
4682 arg2 = null;
4683 argi1 = 0;
4684 argi2 = 0;
4685 argi3 = 0;
4686 }
4687 }
4688
Svetoslav Ganov02107852011-10-03 17:06:56 -07004689 public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
4690 long accessibilityNodeId, int interactionId,
4691 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
4692 long interrogatingTid) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004693 Message message = Message.obtain();
4694 message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -07004695 SomeArgs args = mPool.acquire();
4696 args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
4697 args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
4698 args.argi3 = interactionId;
4699 args.arg1 = callback;
4700 message.obj = args;
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004701 // If the interrogation is performed by the same thread as the main UI
4702 // thread in this process, set the message as a static reference so
4703 // after this call completes the same thread but in the interrogating
4704 // client can handle the message to generate the result.
4705 if (interrogatingPid == Process.myPid()
4706 && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
4707 message.setTarget(ViewRootImpl.this);
Svetoslav Ganov02107852011-10-03 17:06:56 -07004708 AccessibilityInteractionClient.getInstanceForThread(
4709 interrogatingTid).setSameThreadMessage(message);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004710 } else {
4711 sendMessage(message);
4712 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004713 }
4714
4715 public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004716 SomeArgs args = (SomeArgs) message.obj;
4717 final int accessibilityViewId = args.argi1;
4718 final int virtualDescendantId = args.argi2;
4719 final int interactionId = args.argi3;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004720 final IAccessibilityInteractionConnectionCallback callback =
Svetoslav Ganov02107852011-10-03 17:06:56 -07004721 (IAccessibilityInteractionConnectionCallback) args.arg1;
4722 mPool.release(args);
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004723 AccessibilityNodeInfo info = null;
4724 try {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004725 View target = findViewByAccessibilityId(accessibilityViewId);
4726 if (target != null && target.getVisibility() == View.VISIBLE) {
4727 AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
4728 if (provider != null) {
4729 info = provider.createAccessibilityNodeInfo(virtualDescendantId);
4730 } else if (virtualDescendantId == View.NO_ID) {
4731 info = target.createAccessibilityNodeInfo();
4732 }
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004733 }
4734 } finally {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004735 try {
4736 callback.setFindAccessibilityNodeInfoResult(info, interactionId);
4737 } catch (RemoteException re) {
4738 /* ignore - the other side will time out */
4739 }
4740 }
4741 }
4742
4743 public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004744 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
4745 long interrogatingTid) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004746 Message message = Message.obtain();
4747 message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
4748 message.arg1 = viewId;
4749 message.arg2 = interactionId;
4750 message.obj = callback;
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004751 // If the interrogation is performed by the same thread as the main UI
4752 // thread in this process, set the message as a static reference so
4753 // after this call completes the same thread but in the interrogating
4754 // client can handle the message to generate the result.
4755 if (interrogatingPid == Process.myPid()
4756 && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
4757 message.setTarget(ViewRootImpl.this);
Svetoslav Ganov02107852011-10-03 17:06:56 -07004758 AccessibilityInteractionClient.getInstanceForThread(
4759 interrogatingTid).setSameThreadMessage(message);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004760 } else {
4761 sendMessage(message);
4762 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004763 }
4764
4765 public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
4766 final int viewId = message.arg1;
4767 final int interactionId = message.arg2;
4768 final IAccessibilityInteractionConnectionCallback callback =
4769 (IAccessibilityInteractionConnectionCallback) message.obj;
4770
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004771 AccessibilityNodeInfo info = null;
4772 try {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004773 View root = ViewRootImpl.this.mView;
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004774 View target = root.findViewById(viewId);
Svetoslav Ganov0b0a41d2011-09-07 18:06:03 -07004775 if (target != null && target.getVisibility() == View.VISIBLE) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004776 info = target.createAccessibilityNodeInfo();
4777 }
4778 } finally {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004779 try {
4780 callback.setFindAccessibilityNodeInfoResult(info, interactionId);
4781 } catch (RemoteException re) {
4782 /* ignore - the other side will time out */
4783 }
4784 }
4785 }
4786
Svetoslav Ganov02107852011-10-03 17:06:56 -07004787 public void findAccessibilityNodeInfosByTextClientThread(String text,
4788 long accessibilityNodeId, int interactionId,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004789 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
4790 long interrogatingTid) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004791 Message message = Message.obtain();
Svetoslav Ganov02107852011-10-03 17:06:56 -07004792 message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004793 SomeArgs args = mPool.acquire();
4794 args.arg1 = text;
Svetoslav Ganov02107852011-10-03 17:06:56 -07004795 args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
4796 args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
4797 args.argi3 = interactionId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004798 args.arg2 = callback;
4799 message.obj = args;
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004800 // If the interrogation is performed by the same thread as the main UI
4801 // thread in this process, set the message as a static reference so
4802 // after this call completes the same thread but in the interrogating
4803 // client can handle the message to generate the result.
4804 if (interrogatingPid == Process.myPid()
4805 && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
4806 message.setTarget(ViewRootImpl.this);
Svetoslav Ganov02107852011-10-03 17:06:56 -07004807 AccessibilityInteractionClient.getInstanceForThread(
4808 interrogatingTid).setSameThreadMessage(message);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004809 } else {
4810 sendMessage(message);
4811 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004812 }
4813
Svetoslav Ganov02107852011-10-03 17:06:56 -07004814 public void findAccessibilityNodeInfosByTextUiThread(Message message) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004815 SomeArgs args = (SomeArgs) message.obj;
4816 final String text = (String) args.arg1;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004817 final int accessibilityViewId = args.argi1;
Svetoslav Ganov02107852011-10-03 17:06:56 -07004818 final int virtualDescendantId = args.argi2;
4819 final int interactionId = args.argi3;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004820 final IAccessibilityInteractionConnectionCallback callback =
4821 (IAccessibilityInteractionConnectionCallback) args.arg2;
4822 mPool.release(args);
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004823 List<AccessibilityNodeInfo> infos = null;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004824 try {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004825 View target = null;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004826 if (accessibilityViewId != View.NO_ID) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004827 target = findViewByAccessibilityId(accessibilityViewId);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004828 } else {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004829 target = ViewRootImpl.this.mView;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004830 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07004831 if (target != null && target.getVisibility() == View.VISIBLE) {
4832 AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
4833 if (provider != null) {
4834 infos = provider.findAccessibilityNodeInfosByText(text,
4835 virtualDescendantId);
4836 } else if (virtualDescendantId == View.NO_ID) {
4837 ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
4838 foundViews.clear();
4839 target.findViewsWithText(foundViews, text, View.FIND_VIEWS_WITH_TEXT
4840 | View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
4841 | View.FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS);
4842 if (!foundViews.isEmpty()) {
4843 infos = mTempAccessibilityNodeInfoList;
4844 infos.clear();
4845 final int viewCount = foundViews.size();
4846 for (int i = 0; i < viewCount; i++) {
4847 View foundView = foundViews.get(i);
4848 if (foundView.getVisibility() == View.VISIBLE) {
4849 provider = foundView.getAccessibilityNodeProvider();
4850 if (provider != null) {
4851 List<AccessibilityNodeInfo> infosFromProvider =
4852 provider.findAccessibilityNodeInfosByText(text,
4853 virtualDescendantId);
4854 if (infosFromProvider != null) {
4855 infos.addAll(infosFromProvider);
4856 }
4857 } else {
4858 infos.add(foundView.createAccessibilityNodeInfo());
4859 }
4860 }
4861 }
4862 }
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07004863 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07004864 }
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004865 } finally {
4866 try {
4867 callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
4868 } catch (RemoteException re) {
4869 /* ignore - the other side will time out */
4870 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004871 }
4872 }
4873
Svetoslav Ganov02107852011-10-03 17:06:56 -07004874 public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004875 int interactionId, IAccessibilityInteractionConnectionCallback callback,
4876 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004877 Message message = Message.obtain();
4878 message.what = DO_PERFORM_ACCESSIBILITY_ACTION;
Svetoslav Ganov02107852011-10-03 17:06:56 -07004879 message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
4880 message.arg2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004881 SomeArgs args = mPool.acquire();
Svetoslav Ganov02107852011-10-03 17:06:56 -07004882 args.argi1 = action;
4883 args.argi2 = interactionId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004884 args.arg1 = callback;
4885 message.obj = args;
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004886 // If the interrogation is performed by the same thread as the main UI
4887 // thread in this process, set the message as a static reference so
4888 // after this call completes the same thread but in the interrogating
4889 // client can handle the message to generate the result.
4890 if (interogatingPid == Process.myPid()
4891 && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
4892 message.setTarget(ViewRootImpl.this);
Svetoslav Ganov02107852011-10-03 17:06:56 -07004893 AccessibilityInteractionClient.getInstanceForThread(
4894 interrogatingTid).setSameThreadMessage(message);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07004895 } else {
4896 sendMessage(message);
4897 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004898 }
4899
4900 public void perfromAccessibilityActionUiThread(Message message) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004901 final int accessibilityViewId = message.arg1;
4902 final int virtualDescendantId = message.arg2;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004903 SomeArgs args = (SomeArgs) message.obj;
Svetoslav Ganov02107852011-10-03 17:06:56 -07004904 final int action = args.argi1;
4905 final int interactionId = args.argi2;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004906 final IAccessibilityInteractionConnectionCallback callback =
4907 (IAccessibilityInteractionConnectionCallback) args.arg1;
4908 mPool.release(args);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004909 boolean succeeded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004910 try {
Svetoslav Ganov02107852011-10-03 17:06:56 -07004911 View target = findViewByAccessibilityId(accessibilityViewId);
4912 if (target != null && target.getVisibility() == View.VISIBLE) {
4913 AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
4914 if (provider != null) {
4915 succeeded = provider.performAccessibilityAction(action,
4916 virtualDescendantId);
4917 } else if (virtualDescendantId == View.NO_ID) {
4918 switch (action) {
4919 case AccessibilityNodeInfo.ACTION_FOCUS: {
4920 if (!target.hasFocus()) {
4921 // Get out of touch mode since accessibility
4922 // wants to move focus around.
4923 ensureTouchMode(false);
4924 succeeded = target.requestFocus();
4925 }
4926 } break;
4927 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
4928 if (target.hasFocus()) {
4929 target.clearFocus();
4930 succeeded = !target.isFocused();
4931 }
4932 } break;
4933 case AccessibilityNodeInfo.ACTION_SELECT: {
4934 if (!target.isSelected()) {
4935 target.setSelected(true);
4936 succeeded = target.isSelected();
4937 }
4938 } break;
4939 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
4940 if (target.isSelected()) {
4941 target.setSelected(false);
4942 succeeded = !target.isSelected();
4943 }
4944 } break;
4945 }
4946 }
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07004947 }
4948 } finally {
4949 try {
4950 callback.setPerformAccessibilityActionResult(succeeded, interactionId);
4951 } catch (RemoteException re) {
4952 /* ignore - the other side will time out */
4953 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004954 }
4955 }
4956
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004957 private View findViewByAccessibilityId(int accessibilityId) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004958 View root = ViewRootImpl.this.mView;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004959 if (root == null) {
4960 return null;
4961 }
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07004962 View foundView = root.findViewByAccessibilityId(accessibilityId);
4963 if (foundView != null && foundView.getVisibility() != View.VISIBLE) {
Svetoslav Ganov0b0a41d2011-09-07 18:06:03 -07004964 return null;
4965 }
4966 return foundView;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004967 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004968 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004969
Svetoslav Ganova0156172011-06-26 17:55:44 -07004970 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
4971 public volatile boolean mIsPending;
4972
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004973 public void run() {
4974 if (mView != null) {
Svetoslav Ganov82e236d2011-09-29 19:31:06 -07004975 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Svetoslav Ganova0156172011-06-26 17:55:44 -07004976 mIsPending = false;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004977 }
4978 }
4979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004980}