blob: 04752832aea0ef66154720565721a87a466e32f9 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Romain Guy6b7bd242010-10-06 19:49:23 -070019import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070020import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070021import android.app.ActivityManagerNative;
22import android.content.ClipDescription;
23import android.content.ComponentCallbacks;
Dianne Hackbornc68c9132011-07-29 01:25:18 -070024import android.content.ComponentCallbacks2;
Romain Guy6b7bd242010-10-06 19:49:23 -070025import android.content.Context;
Romain Guy211370f2012-02-01 16:10:55 -080026import android.content.pm.ApplicationInfo;
Romain Guy6b7bd242010-10-06 19:49:23 -070027import android.content.pm.PackageManager;
28import android.content.res.CompatibilityInfo;
29import android.content.res.Configuration;
30import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Canvas;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080032import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070034import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070035import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070036import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Rect;
38import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070039import android.graphics.drawable.Drawable;
Romain Guy6b7bd242010-10-06 19:49:23 -070040import android.media.AudioManager;
41import android.os.Binder;
42import android.os.Bundle;
43import android.os.Debug;
44import android.os.Handler;
45import android.os.LatencyTimer;
46import android.os.Looper;
47import android.os.Message;
48import android.os.ParcelFileDescriptor;
Romain Guy7e4e5612012-03-05 14:37:29 -080049import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070051import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070052import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070053import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080054import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070056import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070057import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070058import android.util.Slog;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080059import android.util.TypedValue;
Jeff Browna175a5b2012-02-15 19:18:31 -080060import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070062import android.view.accessibility.AccessibilityEvent;
63import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070064import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
65import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganov02107852011-10-03 17:06:56 -070066import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070067import android.view.accessibility.IAccessibilityInteractionConnection;
68import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080069import android.view.animation.AccelerateDecelerateInterpolator;
70import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.view.inputmethod.InputConnection;
72import android.view.inputmethod.InputMethodManager;
73import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070074
Svetoslav Ganov42138042012-03-20 11:51:39 -070075import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070076import com.android.internal.os.SomeArgs;
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;
Romain Guy6b7bd242010-10-06 19:49:23 -070079import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import java.io.IOException;
82import java.io.OutputStream;
Romain Guy6b7bd242010-10-06 19:49:23 -070083import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070085import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087/**
88 * The top of a view hierarchy, implementing the needed protocol between View
89 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070090 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 *
92 * {@hide}
93 */
Romain Guy812ccbe2010-06-01 14:07:24 -070094@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -080095public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -080096 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -070097 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -070099 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 /** @noinspection PointlessBooleanExpression*/
101 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
102 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800103 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
105 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
106 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
107 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700108 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700109 private static final boolean DEBUG_FPS = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110
Romain Guy51e4d4d2012-03-15 18:30:47 -0700111 private static final boolean USE_RENDER_THREAD = false;
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700112
Romain Guy59a12ca2011-06-09 17:48:21 -0700113 /**
114 * Set this system property to true to force the view hierarchy to render
115 * at 60 Hz. This can be used to measure the potential framerate.
116 */
117 private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
118
Michael Chan53071d62009-05-13 17:29:48 -0700119 private static final boolean MEASURE_LATENCY = false;
120 private static LatencyTimer lt;
121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 /**
123 * Maximum time we allow the user to roll the trackball enough to generate
124 * a key event, before resetting the counters.
125 */
126 static final int MAX_TRACKBALL_DELAY = 250;
127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
129
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800130 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
131 static boolean sFirstDrawComplete = false;
132
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800133 static final ArrayList<ComponentCallbacks> sConfigCallbacks
134 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700135
Romain Guy211370f2012-02-01 16:10:55 -0800136 private static boolean sUseRenderThread = false;
137 private static boolean sRenderThreadQueried = false;
138 private static final Object[] sRenderThreadQueryLock = new Object[0];
139
Jeff Brown98365d72012-08-19 20:30:52 -0700140 final IWindowSession mWindowSession;
141 final Display mDisplay;
142
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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 final Thread mThread;
158
159 final WindowLeaked mLocation;
160
161 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
162
163 final W mWindow;
164
Dianne Hackborn180c4842011-09-13 12:39:25 -0700165 final int mTargetSdkVersion;
166
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700167 int mSeq;
168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 View mView;
170 View mFocusedView;
171 View mRealFocusedView; // this is not set to null in touch mode
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800172 View mOldFocusedView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700173
174 View mAccessibilityFocusedHost;
175 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 int mViewVisibility;
178 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700179 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Dianne Hackbornce418e62011-03-01 14:31:38 -0800181 // Set to true if the owner of this window is in the stopped state,
182 // so the window should no longer be active.
183 boolean mStopped = false;
184
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700185 boolean mLastInCompatMode = false;
186
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700187 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700188 BaseSurfaceHolder mSurfaceHolder;
189 boolean mIsCreating;
190 boolean mDrawingAllowed;
191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 final Region mTransparentRegion;
193 final Region mPreviousTransparentRegion;
194
195 int mWidth;
196 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800197 Rect mDirty;
198 final Rect mCurrentDirty = new Rect();
199 final Rect mPreviousDirty = new Rect();
Romain Guybb93d552009-03-24 21:04:15 -0700200 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700201
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700202 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
204 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700205 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700206 InputQueue.Callback mInputQueueCallback;
207 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700208 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800209 Choreographer mChoreographer;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 final Rect mTempRect; // used in the transaction to not thrash the heap.
212 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
214 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800215 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700217 /** Set to true while in performTraversals for detecting when die(true) is called from internal
218 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
219 boolean mIsInTraversal;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700220 boolean mFitSystemWindowsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 boolean mLayoutRequested;
222 boolean mFirst;
223 boolean mReportNextDraw;
224 boolean mFullRedrawNeeded;
225 boolean mNewSurfaceNeeded;
226 boolean mHasHadWindowFocus;
227 boolean mLastWasImTarget;
Dianne Hackborn12d3a942012-04-27 14:16:30 -0700228 boolean mWindowsAnimating;
Romain Guy1f59e5c2012-05-06 14:11:16 -0700229 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700230 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700231 int mClientWindowLayoutFlags;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800232
233 // Pool of queued input events.
234 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
235 private QueuedInputEvent mQueuedInputEventPool;
236 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800237
238 // Input event queue.
239 QueuedInputEvent mFirstPendingInputEvent;
240 QueuedInputEvent mCurrentInputEvent;
Jeff Brown96e942d2011-11-30 19:55:01 -0800241 boolean mProcessInputEventsScheduled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
243 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700244 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700247 // Surface can never be reassigned or cleared (use Surface.clear()).
248 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
250 boolean mAdded;
251 boolean mAddedTouchMode;
252
Jeff Brown98365d72012-08-19 20:30:52 -0700253 final CompatibilityInfoHolder mCompatibilityInfo;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 // These are accessed by multiple threads.
256 final Rect mWinFrame; // frame given by window manager.
257
258 final Rect mPendingVisibleInsets = new Rect();
259 final Rect mPendingContentInsets = new Rect();
260 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
261 = new ViewTreeObserver.InternalInsetsInfo();
262
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700263 final Rect mFitSystemWindowsInsets = new Rect();
264
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700265 final Configuration mLastConfiguration = new Configuration();
266 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 boolean mScrollMayChange;
269 int mSoftInputMode;
270 View mLastScrolledFocus;
271 int mScrollY;
272 int mCurScrollY;
273 Scroller mScroller;
Romain Guy7d70fbf2011-05-24 17:40:25 -0700274 HardwareLayer mResizeBuffer;
275 long mResizeBufferStartTime;
276 int mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800277 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700278 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700279
Romain Guy8506ab42009-06-11 17:35:47 -0700280 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281
Christopher Tatea53146c2010-09-07 11:57:52 -0700282 /* Drag/drop */
283 ClipDescription mDragDescription;
284 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800285 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700286 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700287 final PointF mLastTouchPoint = new PointF();
Romain Guy59a12ca2011-06-09 17:48:21 -0700288
289 private boolean mProfileRendering;
290 private Thread mRenderProfiler;
291 private volatile boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700292
Chet Haase2f2022a2011-10-11 06:41:59 -0700293 // Variables to track frames per second, enabled via DEBUG_FPS flag
294 private long mFpsStartTime = -1;
295 private long mFpsPrevTime = -1;
296 private int mFpsNumFrames;
297
Romain Guy51e4d4d2012-03-15 18:30:47 -0700298 private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>(24);
299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 /**
301 * see {@link #playSoundEffect(int)}
302 */
303 AudioManager mAudioManager;
304
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700305 final AccessibilityManager mAccessibilityManager;
306
Gilles Debunne5ac84422011-10-19 09:35:58 -0700307 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700308
309 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
310
Svetoslav Ganova0156172011-06-26 17:55:44 -0700311 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700312
Svetoslav Ganov42138042012-03-20 11:51:39 -0700313 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800314
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700315 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700316 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700317
Jeff Brown21bc5c92011-02-28 18:27:14 -0800318 /**
319 * Consistency verifier for debugging purposes.
320 */
321 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
322 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
323 new InputEventConsistencyVerifier(this, 0) : null;
324
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700325 static final class SystemUiVisibilityInfo {
326 int seq;
327 int globalVisibility;
328 int localValue;
329 int localChanges;
330 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700331
Jeff Brown98365d72012-08-19 20:30:52 -0700332 public ViewRootImpl(Context context, Display display) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 super();
334
Romain Guy812ccbe2010-06-01 14:07:24 -0700335 if (MEASURE_LATENCY) {
336 if (lt == null) {
337 lt = new LatencyTimer(100, 1000);
338 }
Michael Chan53071d62009-05-13 17:29:48 -0700339 }
340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 // Initialize the statics when this class is first instantiated. This is
342 // done here instead of in the static block because Zygote does not
343 // allow the spawning of threads.
Jeff Brown98365d72012-08-19 20:30:52 -0700344 mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
345 mDisplay = display;
346
347 CompatibilityInfoHolder cih = display.getCompatibilityInfo();
348 mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 mThread = Thread.currentThread();
351 mLocation = new WindowLeaked(null);
352 mLocation.fillInStackTrace();
353 mWidth = -1;
354 mHeight = -1;
355 mDirty = new Rect();
356 mTempRect = new Rect();
357 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700359 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700360 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mInputMethodCallback = new InputMethodCallback(this);
362 mViewVisibility = View.GONE;
363 mTransparentRegion = new Region();
364 mPreviousTransparentRegion = new Region();
365 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 mAdded = false;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700367 mAccessibilityManager = AccessibilityManager.getInstance(context);
368 mAccessibilityInteractionConnectionManager =
369 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800370 mAccessibilityManager.addAccessibilityStateChangeListener(
371 mAccessibilityInteractionConnectionManager);
Jeff Brown98365d72012-08-19 20:30:52 -0700372 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700374 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700375 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700376 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Romain Guy59a12ca2011-06-09 17:48:21 -0700377 mProfileRendering = Boolean.parseBoolean(
378 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
Jeff Brown96e942d2011-11-30 19:55:01 -0800379 mChoreographer = Choreographer.getInstance();
Romain Guy7e4e5612012-03-05 14:37:29 -0800380
381 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
382 mAttachInfo.mScreenOn = powerManager.isScreenOn();
Dianne Hackborna53de062012-05-08 18:53:51 -0700383 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 }
385
Romain Guy211370f2012-02-01 16:10:55 -0800386 /**
387 * @return True if the application requests the use of a separate render thread,
388 * false otherwise
389 */
390 private static boolean isRenderThreadRequested(Context context) {
Romain Guy51e4d4d2012-03-15 18:30:47 -0700391 if (USE_RENDER_THREAD) {
392 synchronized (sRenderThreadQueryLock) {
393 if (!sRenderThreadQueried) {
394 final PackageManager packageManager = context.getPackageManager();
395 final String packageName = context.getApplicationInfo().packageName;
396 try {
397 ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
398 PackageManager.GET_META_DATA);
399 if (applicationInfo.metaData != null) {
400 sUseRenderThread = applicationInfo.metaData.getBoolean(
401 "android.graphics.renderThread", false);
402 }
403 } catch (PackageManager.NameNotFoundException e) {
404 } finally {
405 sRenderThreadQueried = true;
Romain Guy211370f2012-02-01 16:10:55 -0800406 }
Romain Guy211370f2012-02-01 16:10:55 -0800407 }
Romain Guy51e4d4d2012-03-15 18:30:47 -0700408 return sUseRenderThread;
Romain Guy211370f2012-02-01 16:10:55 -0800409 }
Romain Guy51e4d4d2012-03-15 18:30:47 -0700410 } else {
411 return false;
Romain Guy211370f2012-02-01 16:10:55 -0800412 }
413 }
414
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800415 public static void addFirstDrawHandler(Runnable callback) {
416 synchronized (sFirstDrawHandlers) {
417 if (!sFirstDrawComplete) {
418 sFirstDrawHandlers.add(callback);
419 }
420 }
421 }
422
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800423 public static void addConfigCallback(ComponentCallbacks callback) {
424 synchronized (sConfigCallbacks) {
425 sConfigCallbacks.add(callback);
426 }
427 }
428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 // FIXME for perf testing only
430 private boolean mProfile = false;
431
432 /**
433 * Call this to profile the next traversal call.
434 * FIXME for perf testing only. Remove eventually
435 */
436 public void profile() {
437 mProfile = true;
438 }
439
440 /**
441 * Indicates whether we are in touch mode. Calling this method triggers an IPC
442 * call and should be avoided whenever possible.
443 *
444 * @return True, if the device is in touch mode, false otherwise.
445 *
446 * @hide
447 */
448 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700449 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
450 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700452 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 } catch (RemoteException e) {
454 }
455 }
456 return false;
457 }
458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 /**
460 * We have one child
461 */
Romain Guye4d01122010-06-16 18:44:05 -0700462 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 synchronized (this) {
464 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700465 mView = view;
Joe Onorato86f67862010-11-05 18:57:34 -0700466 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700467 mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700468 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700469 // Keep track of the actual window flags supplied by the client.
470 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700471
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700472 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700473
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700474 if (view instanceof RootViewSurfaceTaker) {
475 mSurfaceHolderCallback =
476 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
477 if (mSurfaceHolderCallback != null) {
478 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700479 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700480 }
481 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800482
Romain Guy856d4e12011-10-14 15:47:55 -0700483 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
484 mTranslator = compatibilityInfo.getTranslator();
485
Romain Guy1aec9a22011-01-05 09:37:12 -0800486 // If the application owns the surface, don't enable hardware acceleration
487 if (mSurfaceHolder == null) {
Romain Guy211370f2012-02-01 16:10:55 -0800488 enableHardwareAcceleration(mView.getContext(), attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800489 }
490
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700491 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700492 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700493 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700494 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700495 attrs.backup();
496 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700497 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700498 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
499
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700500 if (!compatibilityInfo.supportsScreen()) {
501 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700502 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700503 }
504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 mSoftInputMode = attrs.softInputMode;
506 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700507 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700509 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700510 mAttachInfo.mApplicationScale =
511 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 if (panelParentView != null) {
513 mAttachInfo.mPanelParentWindowToken
514 = panelParentView.getApplicationWindowToken();
515 }
516 mAdded = true;
517 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 // Schedule the first layout -before- adding to the window
520 // manager, to make sure we do the relayout before receiving
521 // any other events from the system.
522 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700523 if ((mWindowAttributes.inputFeatures
524 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
525 mInputChannel = new InputChannel();
526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700528 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700529 mAttachInfo.mRecomputeGlobalAttributes = true;
530 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700531 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
532 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700533 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 } catch (RemoteException e) {
535 mAdded = false;
536 mView = null;
537 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700538 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700539 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700541 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700543 } finally {
544 if (restore) {
545 attrs.restore();
546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700548
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700549 if (mTranslator != null) {
550 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 mPendingContentInsets.set(mAttachInfo.mContentInsets);
553 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800554 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700555 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 mView = null;
557 mAttachInfo.mRootView = null;
558 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700559 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700561 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700563 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
564 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
565 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 "Unable to add window -- token " + attrs.token
567 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700568 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
569 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 "Unable to add window -- token " + attrs.token
571 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700572 case WindowManagerGlobal.ADD_APP_EXITING:
573 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 "Unable to add window -- app for token " + attrs.token
575 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700576 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
577 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 "Unable to add window -- window " + mWindow
579 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700580 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 // Silently ignore -- we would have just removed it
582 // right away, anyway.
583 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700584 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
585 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 "Unable to add window " + mWindow +
587 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700588 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
589 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 "Unable to add window " + mWindow +
591 " -- permission denied for this window type");
592 }
593 throw new RuntimeException(
594 "Unable to add window -- unknown error code " + res);
595 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700596
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700597 if (view instanceof RootViewSurfaceTaker) {
598 mInputQueueCallback =
599 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
600 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700601 if (mInputChannel != null) {
602 if (mInputQueueCallback != null) {
603 mInputQueue = new InputQueue(mInputChannel);
604 mInputQueueCallback.onInputQueueCreated(mInputQueue);
605 } else {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800606 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
607 Looper.myLooper());
Jeff Browncc4f7db2011-08-30 20:34:48 -0700608 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700609 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700612 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
613 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700614
615 if (mAccessibilityManager.isEnabled()) {
616 mAccessibilityInteractionConnectionManager.ensureConnection();
617 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700618
619 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
620 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 }
623 }
624 }
625
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800626 void destroyHardwareResources() {
Romain Guy65b345f2011-07-27 18:51:50 -0700627 if (mAttachInfo.mHardwareRenderer != null) {
628 if (mAttachInfo.mHardwareRenderer.isEnabled()) {
629 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
630 }
631 mAttachInfo.mHardwareRenderer.destroy(false);
Romain Guy6d7475d2011-07-27 16:28:21 -0700632 }
Romain Guy65b345f2011-07-27 18:51:50 -0700633 }
634
Romain Guy31f2c2e2011-11-21 10:55:41 -0800635 void terminateHardwareResources() {
636 if (mAttachInfo.mHardwareRenderer != null) {
637 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
638 mAttachInfo.mHardwareRenderer.destroy(false);
639 }
640 }
641
Romain Guy65b345f2011-07-27 18:51:50 -0700642 void destroyHardwareLayers() {
643 if (mThread != Thread.currentThread()) {
644 if (mAttachInfo.mHardwareRenderer != null &&
645 mAttachInfo.mHardwareRenderer.isEnabled()) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700646 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
Romain Guy65b345f2011-07-27 18:51:50 -0700647 }
648 } else {
649 if (mAttachInfo.mHardwareRenderer != null &&
650 mAttachInfo.mHardwareRenderer.isEnabled()) {
651 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
652 }
653 }
Romain Guy6d7475d2011-07-27 16:28:21 -0700654 }
655
Romain Guy11cb6422012-09-21 00:39:43 -0700656 void pushHardwareLayerUpdate(HardwareLayer layer) {
657 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
658 mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
659 }
660 }
661
Chris Craik41ee4652012-05-31 15:05:57 -0700662 public boolean attachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700663 //noinspection SimplifiableIfStatement
Romain Guyba6be8a2012-04-23 18:22:09 -0700664 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Chris Craik41ee4652012-05-31 15:05:57 -0700665 return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
Romain Guyba6be8a2012-04-23 18:22:09 -0700666 }
Chris Craik41ee4652012-05-31 15:05:57 -0700667 return false;
Romain Guyba6be8a2012-04-23 18:22:09 -0700668 }
669
670 public void detachFunctor(int functor) {
Romain Guy527ee912012-06-11 13:24:30 -0700671 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyba6be8a2012-04-23 18:22:09 -0700672 mAttachInfo.mHardwareRenderer.detachFunctor(functor);
673 }
674 }
675
Romain Guy211370f2012-02-01 16:10:55 -0800676 private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800677 mAttachInfo.mHardwareAccelerated = false;
678 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800679
Romain Guy856d4e12011-10-14 15:47:55 -0700680 // Don't enable hardware acceleration when the application is in compatibility mode
681 if (mTranslator != null) return;
682
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800683 // Try to enable hardware acceleration if requested
Jim Miller1b365922011-03-09 19:38:07 -0800684 final boolean hardwareAccelerated =
685 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
686
Romain Guy566c3312011-03-21 18:21:28 -0700687 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700688 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700689 return;
690 }
691
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700692 // Persistent processes (including the system) should not do
693 // accelerated rendering on low-end devices. In that case,
694 // sRendererDisabled will be set. In addition, the system process
695 // itself should never do accelerated rendering. In that case, both
696 // sRendererDisabled and sSystemRendererDisabled are set. When
697 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
698 // can be used by code on the system process to escape that and enable
699 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800700
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700701 final boolean fakeHwAccelerated = (attrs.privateFlags &
702 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
703 final boolean forceHwAccelerated = (attrs.privateFlags &
704 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800705
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700706 if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
707 && forceHwAccelerated)) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800708 // Don't enable hardware acceleration when we're not on the main thread
Romain Guy211370f2012-02-01 16:10:55 -0800709 if (!HardwareRenderer.sSystemRendererDisabled &&
710 Looper.getMainLooper() != Looper.myLooper()) {
711 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
Romain Guyff26a0c2011-01-20 11:35:46 -0800712 + "acceleration outside of the main thread, aborting");
713 return;
714 }
715
Romain Guy51e4d4d2012-03-15 18:30:47 -0700716 final boolean renderThread = isRenderThreadRequested(context);
Romain Guy211370f2012-02-01 16:10:55 -0800717 if (renderThread) {
718 Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
719 }
720
Romain Guyb051e892010-09-28 19:09:36 -0700721 if (mAttachInfo.mHardwareRenderer != null) {
722 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy211370f2012-02-01 16:10:55 -0800723 }
724
725 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700726 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800727 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
728 = mAttachInfo.mHardwareRenderer != null;
Romain Guy211370f2012-02-01 16:10:55 -0800729
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700730 } else if (fakeHwAccelerated) {
731 // The window had wanted to use hardware acceleration, but this
732 // is not allowed in its process. By setting this flag, it can
733 // still render as if it was accelerated. This is basically for
734 // the preview windows the window manager shows for launching
735 // applications, so they will look more like the app being launched.
Dianne Hackborn07213e62011-08-24 20:05:39 -0700736 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700737 }
738 }
739 }
740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 public View getView() {
742 return mView;
743 }
744
745 final WindowLeaked getLocation() {
746 return mLocation;
747 }
748
749 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
750 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700751 int oldSoftInputMode = mWindowAttributes.softInputMode;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700752 // Keep track of the actual window flags supplied by the client.
753 mClientWindowLayoutFlags = attrs.flags;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700754 // preserve compatible window flag if exists.
755 int compatibleWindowFlag =
756 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
Craig Mautner3fe38c02012-05-03 17:28:09 -0700757 // transfer over system UI visibility values as they carry current state.
758 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
759 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Romain Guyf21c9b02011-09-06 16:56:54 -0700760 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700761 mWindowAttributes.flags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700762
763 applyKeepScreenOnFlag(mWindowAttributes);
764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 if (newView) {
766 mSoftInputMode = attrs.softInputMode;
767 requestLayout();
768 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700769 // Don't lose the mode we last auto-computed.
770 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
771 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
772 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
773 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
774 | (oldSoftInputMode
775 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 mWindowAttributesChanged = true;
778 scheduleTraversals();
779 }
780 }
781
782 void handleAppVisibility(boolean visible) {
783 if (mAppVisible != visible) {
784 mAppVisible = visible;
785 scheduleTraversals();
786 }
787 }
788
789 void handleGetNewSurface() {
790 mNewSurfaceNeeded = true;
791 mFullRedrawNeeded = true;
792 scheduleTraversals();
793 }
794
Romain Guybb9908b2012-03-08 11:14:07 -0800795 void handleScreenStateChange(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -0800796 if (on != mAttachInfo.mScreenOn) {
797 mAttachInfo.mScreenOn = on;
Romain Guybb9908b2012-03-08 11:14:07 -0800798 if (mView != null) {
799 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
800 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800801 if (on) {
802 mFullRedrawNeeded = true;
803 scheduleTraversals();
804 }
805 }
806 }
807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 /**
809 * {@inheritDoc}
810 */
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700811 public void requestFitSystemWindows() {
812 checkThread();
813 mFitSystemWindowsRequested = true;
814 scheduleTraversals();
815 }
816
817 /**
818 * {@inheritDoc}
819 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 public void requestLayout() {
821 checkThread();
822 mLayoutRequested = true;
823 scheduleTraversals();
824 }
825
826 /**
827 * {@inheritDoc}
828 */
829 public boolean isLayoutRequested() {
830 return mLayoutRequested;
831 }
832
Romain Guycfef1232012-02-23 13:50:37 -0800833 void invalidate() {
834 mDirty.set(0, 0, mWidth, mHeight);
835 scheduleTraversals();
836 }
837
Dianne Hackborna53de062012-05-08 18:53:51 -0700838 void invalidateWorld(View view) {
839 view.invalidate();
840 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700841 ViewGroup parent = (ViewGroup) view;
842 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700843 invalidateWorld(parent.getChildAt(i));
844 }
845 }
846 }
847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800849 invalidateChildInParent(null, dirty);
850 }
851
852 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700854 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800855
Chet Haase70d4ba12010-10-06 09:46:45 -0700856 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700857 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800858 return null;
Chet Haase05e91ed2012-07-03 14:17:57 -0700859 } else if (dirty.isEmpty()) {
860 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700861 }
Romain Guycfef1232012-02-23 13:50:37 -0800862
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700863 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700865 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700866 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800867 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700868 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700869 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700870 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700871 }
Romain Guy1e095972009-07-07 11:22:45 -0700872 if (mAttachInfo.mScalingRequired) {
873 dirty.inset(-1, -1);
874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
Romain Guycfef1232012-02-23 13:50:37 -0800876
877 final Rect localDirty = mDirty;
878 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700879 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800880 mAttachInfo.mIgnoreDirtyState = true;
881 }
Romain Guycfef1232012-02-23 13:50:37 -0800882
883 // Add the new dirty rect to the current one
884 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
885 // Intersect with the bounds of the window to skip
886 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700887 final float appScale = mAttachInfo.mApplicationScale;
888 localDirty.intersect(0, 0,
889 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guycfef1232012-02-23 13:50:37 -0800890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 if (!mWillDrawSoon) {
892 scheduleTraversals();
893 }
Romain Guycfef1232012-02-23 13:50:37 -0800894
895 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700896 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897
Dianne Hackbornce418e62011-03-01 14:31:38 -0800898 void setStopped(boolean stopped) {
899 if (mStopped != stopped) {
900 mStopped = stopped;
901 if (!stopped) {
902 scheduleTraversals();
903 }
904 }
905 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906
Romain Guycfef1232012-02-23 13:50:37 -0800907 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 return null;
909 }
910
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700911 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 if (child != mView) {
913 throw new RuntimeException("child is not mine, honest!");
914 }
915 // Note: don't apply scroll offset, because we want to know its
916 // visibility in the virtual canvas being given to the view hierarchy.
917 return r.intersect(0, 0, mWidth, mHeight);
918 }
919
920 public void bringChildToFront(View child) {
921 }
922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 int getHostVisibility() {
924 return mAppVisible ? mView.getVisibility() : View.GONE;
925 }
Romain Guy8506ab42009-06-11 17:35:47 -0700926
Romain Guy7d70fbf2011-05-24 17:40:25 -0700927 void disposeResizeBuffer() {
928 if (mResizeBuffer != null) {
929 mResizeBuffer.destroy();
930 mResizeBuffer = null;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800931 }
932 }
933
Chet Haasecca2c982011-05-20 14:34:18 -0700934 /**
935 * Add LayoutTransition to the list of transitions to be started in the next traversal.
936 * This list will be cleared after the transitions on the list are start()'ed. These
937 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
938 * happens during the layout phase of traversal, which we want to complete before any of the
939 * animations are started (because those animations may side-effect properties that layout
940 * depends upon, like the bounding rectangles of the affected views). So we add the transition
941 * to the list and it is started just prior to starting the drawing phase of traversal.
942 *
943 * @param transition The LayoutTransition to be started on the next traversal.
944 *
945 * @hide
946 */
947 public void requestTransitionStart(LayoutTransition transition) {
948 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
949 if (mPendingTransitions == null) {
950 mPendingTransitions = new ArrayList<LayoutTransition>();
951 }
952 mPendingTransitions.add(transition);
953 }
954 }
955
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700956 void scheduleTraversals() {
957 if (!mTraversalScheduled) {
958 mTraversalScheduled = true;
959 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
960 mChoreographer.postCallback(
961 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Jeff Brown330314c2012-04-27 02:20:22 -0700962 scheduleConsumeBatchedInput();
Jeff Brown96e942d2011-11-30 19:55:01 -0800963 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700964 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800965
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700966 void unscheduleTraversals() {
967 if (mTraversalScheduled) {
968 mTraversalScheduled = false;
969 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
970 mChoreographer.removeCallbacks(
971 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
972 }
973 }
974
975 void doTraversal() {
976 if (mTraversalScheduled) {
977 mTraversalScheduled = false;
978 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
979
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700980 if (mProfile) {
981 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -0800982 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800983
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700984 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
985 try {
986 performTraversals();
987 } finally {
988 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
989 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800990
Jeff Brownebb2d8d2012-03-23 17:14:34 -0700991 if (mProfile) {
992 Debug.stopMethodTracing();
993 mProfile = false;
994 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800995 }
996 }
997
Dianne Hackborn9d090892012-06-11 18:35:41 -0700998 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
999 // Update window's global keep screen on flag: if a view has requested
1000 // that the screen be kept on, then it is always set; otherwise, it is
1001 // set to whatever the client last requested for the global state.
1002 if (mAttachInfo.mKeepScreenOn) {
1003 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1004 } else {
1005 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1006 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1007 }
1008 }
1009
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001010 private boolean collectViewAttributes() {
1011 final View.AttachInfo attachInfo = mAttachInfo;
1012 if (attachInfo.mRecomputeGlobalAttributes) {
1013 //Log.i(TAG, "Computing view hierarchy attributes!");
1014 attachInfo.mRecomputeGlobalAttributes = false;
1015 boolean oldScreenOn = attachInfo.mKeepScreenOn;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001016 attachInfo.mKeepScreenOn = false;
1017 attachInfo.mSystemUiVisibility = 0;
1018 attachInfo.mHasSystemUiListeners = false;
1019 mView.dispatchCollectViewAttributes(attachInfo, 0);
Dianne Hackborn139e5aa2012-05-05 20:36:38 -07001020 attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001021 WindowManager.LayoutParams params = mWindowAttributes;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001022 if (attachInfo.mKeepScreenOn != oldScreenOn
Craig Mautner7eac0f52012-09-13 13:14:14 -07001023 || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1024 || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001025 applyKeepScreenOnFlag(params);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001026 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1027 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1028 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1029 return true;
1030 }
1031 }
1032 return false;
1033 }
1034
1035 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1036 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1037 int childWidthMeasureSpec;
1038 int childHeightMeasureSpec;
1039 boolean windowSizeMayChange = false;
1040
1041 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1042 "Measuring " + host + " in display " + desiredWindowWidth
1043 + "x" + desiredWindowHeight + "...");
1044
1045 boolean goodMeasure = false;
1046 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1047 // On large screens, we don't want to allow dialogs to just
1048 // stretch to fill the entire width of the screen to display
1049 // one line of text. First try doing the layout at a smaller
1050 // size to see if it will fit.
1051 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1052 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1053 int baseSize = 0;
1054 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1055 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1056 }
1057 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1058 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1059 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1060 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001061 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001062 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1063 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1064 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1065 goodMeasure = true;
1066 } else {
1067 // Didn't fit in that size... try expanding a bit.
1068 baseSize = (baseSize+desiredWindowWidth)/2;
1069 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1070 + baseSize);
1071 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001072 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001073 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1074 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1075 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1076 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1077 goodMeasure = true;
1078 }
1079 }
1080 }
1081 }
1082
1083 if (!goodMeasure) {
1084 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1085 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001086 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001087 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1088 windowSizeMayChange = true;
1089 }
1090 }
1091
1092 if (DBG) {
1093 System.out.println("======================================");
1094 System.out.println("performTraversals -- after measure");
1095 host.debug();
1096 }
1097
1098 return windowSizeMayChange;
1099 }
1100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 private void performTraversals() {
1102 // cache mView since it is used so much below...
1103 final View host = mView;
1104
1105 if (DBG) {
1106 System.out.println("======================================");
1107 System.out.println("performTraversals");
1108 host.debug();
1109 }
1110
1111 if (host == null || !mAdded)
1112 return;
1113
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001114 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001116 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001118 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 WindowManager.LayoutParams lp = mWindowAttributes;
1120
1121 int desiredWindowWidth;
1122 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123
1124 final View.AttachInfo attachInfo = mAttachInfo;
1125
1126 final int viewVisibility = getHostVisibility();
1127 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1128 || mNewSurfaceNeeded;
1129
1130 WindowManager.LayoutParams params = null;
1131 if (mWindowAttributesChanged) {
1132 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001133 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 params = lp;
1135 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001136 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
1137 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1138 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001139 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001140 mLayoutRequested = true;
1141 if (mLastInCompatMode) {
1142 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1143 mLastInCompatMode = false;
1144 } else {
1145 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1146 mLastInCompatMode = true;
1147 }
1148 }
Romain Guyf21c9b02011-09-06 16:56:54 -07001149
1150 mWindowAttributesChangesFlag = 0;
1151
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001152 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001154 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 mLayoutRequested = true;
1156
Dianne Hackborna239c842011-06-01 12:28:20 -07001157 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1158 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001159 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001160 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001161 desiredWindowWidth = size.x;
1162 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001163 } else {
1164 DisplayMetrics packageMetrics =
1165 mView.getContext().getResources().getDisplayMetrics();
1166 desiredWindowWidth = packageMetrics.widthPixels;
1167 desiredWindowHeight = packageMetrics.heightPixels;
1168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169
1170 // For the very first time, tell the view hierarchy that it
1171 // is attached to the window. Note that at this point the surface
1172 // object is not initialized to its backing store, but soon it
1173 // will be (assuming the window is visible).
1174 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -08001175 // We used to use the following condition to choose 32 bits drawing caches:
1176 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1177 // However, windows are now always 32 bits by default, so choose 32 bits
1178 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 attachInfo.mHasWindowFocus = false;
1180 attachInfo.mWindowVisibility = viewVisibility;
1181 attachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001183 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001184 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 host.dispatchAttachedToWindow(attachInfo, 0);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001186 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1187 host.fitSystemWindows(mFitSystemWindowsInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001191 desiredWindowWidth = frame.width();
1192 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001194 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001195 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001196 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001198 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 }
1200 }
1201
1202 if (viewVisibilityChanged) {
1203 attachInfo.mWindowVisibility = viewVisibility;
1204 host.dispatchWindowVisibilityChanged(viewVisibility);
1205 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001206 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 }
1208 if (viewVisibility == View.GONE) {
1209 // After making a window gone, we will count it as being
1210 // shown for the first time the next time it gets focus.
1211 mHasHadWindowFocus = false;
1212 }
1213 }
1214
Chet Haaseb78c2842012-04-19 13:39:50 -07001215 // Execute enqueued actions on every traversal in case a detached view enqueued an action
1216 getRunQueue().executeActions(attachInfo.mHandler);
1217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001219
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001220 boolean layoutRequested = mLayoutRequested && !mStopped;
1221 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001222
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001223 final Resources res = mView.getContext().getResources();
1224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 // make sure touch mode code executes by setting cached value
1227 // to opposite of the added touch mode.
1228 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001229 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 } else {
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001231 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001234 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1236 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1237 + mAttachInfo.mVisibleInsets);
1238 }
1239 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1240 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001241 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242
Dianne Hackborna239c842011-06-01 12:28:20 -07001243 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1244 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001245 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001246 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001247 desiredWindowWidth = size.x;
1248 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001249 } else {
1250 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1251 desiredWindowWidth = packageMetrics.widthPixels;
1252 desiredWindowHeight = packageMetrics.heightPixels;
1253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 }
1255 }
1256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001258 windowSizeMayChange |= measureHierarchy(host, lp, res,
1259 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 }
1261
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001262 if (collectViewAttributes()) {
1263 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001265 if (attachInfo.mForceReportNewAttributes) {
1266 attachInfo.mForceReportNewAttributes = false;
1267 params = lp;
1268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269
1270 if (mFirst || attachInfo.mViewVisibilityChanged) {
1271 attachInfo.mViewVisibilityChanged = false;
1272 int resizeMode = mSoftInputMode &
1273 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1274 // If we are in auto resize mode, then we need to determine
1275 // what mode to use now.
1276 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1277 final int N = attachInfo.mScrollContainers.size();
1278 for (int i=0; i<N; i++) {
1279 if (attachInfo.mScrollContainers.get(i).isShown()) {
1280 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1281 }
1282 }
1283 if (resizeMode == 0) {
1284 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1285 }
1286 if ((lp.softInputMode &
1287 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1288 lp.softInputMode = (lp.softInputMode &
1289 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1290 resizeMode;
1291 params = lp;
1292 }
1293 }
1294 }
Romain Guy8506ab42009-06-11 17:35:47 -07001295
Dianne Hackborn4702a852012-08-17 15:18:29 -07001296 if (params != null && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 if (!PixelFormat.formatHasAlpha(params.format)) {
1298 params.format = PixelFormat.TRANSLUCENT;
1299 }
1300 }
1301
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001302 if (mFitSystemWindowsRequested) {
1303 mFitSystemWindowsRequested = false;
1304 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1305 host.fitSystemWindows(mFitSystemWindowsInsets);
1306 if (mLayoutRequested) {
1307 // Short-circuit catching a new layout request here, so
1308 // we don't need to go through two layout passes when things
1309 // change due to fitting system windows, which can happen a lot.
1310 windowSizeMayChange |= measureHierarchy(host, lp,
1311 mView.getContext().getResources(),
1312 desiredWindowWidth, desiredWindowHeight);
1313 }
1314 }
1315
1316 if (layoutRequested) {
1317 // Clear this now, so that if anything requests a layout in the
1318 // rest of this function we will catch it and re-run a full
1319 // layout pass.
1320 mLayoutRequested = false;
1321 }
1322
1323 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001324 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001325 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1326 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1327 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1328 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329
1330 final boolean computesInternalInsets =
1331 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
Romain Guy812ccbe2010-06-01 14:07:24 -07001332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 boolean insetsPending = false;
1334 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001335
1336 if (mFirst || windowShouldResize || insetsChanged ||
1337 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338
1339 if (viewVisibility == View.VISIBLE) {
1340 // If this window is giving internal insets to the window
1341 // manager, and it is being added or changing its visibility,
1342 // then we want to first give the window manager "fake"
1343 // insets to cause it to effectively ignore the content of
1344 // the window during layout. This avoids it briefly causing
1345 // other windows to resize/move based on the raw frame of the
1346 // window, waiting until we can finish laying out this window
1347 // and get back to the window manager with the ultimately
1348 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001349 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 }
1351
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001352 if (mSurfaceHolder != null) {
1353 mSurfaceHolder.mSurfaceLock.lock();
1354 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001355 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001356
Romain Guyc361da82010-10-25 15:29:10 -07001357 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 boolean contentInsetsChanged = false;
Romain Guy13922e02009-05-12 17:56:14 -07001359 boolean visibleInsetsChanged;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001360 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001363 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001364 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1365 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001366 }
Romain Guy2a83f002011-01-18 18:28:21 -08001367
1368 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001369 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
1372 + " content=" + mPendingContentInsets.toShortString()
1373 + " visible=" + mPendingVisibleInsets.toShortString()
1374 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001375
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001376 if (mPendingConfiguration.seq != 0) {
1377 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1378 + mPendingConfiguration);
1379 updateConfiguration(mPendingConfiguration, !mFirst);
1380 mPendingConfiguration.seq = 0;
1381 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 contentInsetsChanged = !mPendingContentInsets.equals(
1384 mAttachInfo.mContentInsets);
1385 visibleInsetsChanged = !mPendingVisibleInsets.equals(
1386 mAttachInfo.mVisibleInsets);
1387 if (contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001388 if (mWidth > 0 && mHeight > 0 && lp != null &&
1389 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1390 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001391 mSurface != null && mSurface.isValid() &&
1392 !mAttachInfo.mTurnOffWindowResizeAnim &&
1393 mAttachInfo.mHardwareRenderer != null &&
1394 mAttachInfo.mHardwareRenderer.isEnabled() &&
1395 mAttachInfo.mHardwareRenderer.validate() &&
1396 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1397
1398 disposeResizeBuffer();
1399
1400 boolean completed = false;
Romain Guyc89b14b2012-08-08 14:53:48 -07001401 HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
Chet Haase08837c22011-11-28 11:53:21 -08001402 HardwareCanvas layerCanvas = null;
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001403 try {
1404 if (mResizeBuffer == null) {
1405 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1406 mWidth, mHeight, false);
1407 } else if (mResizeBuffer.getWidth() != mWidth ||
1408 mResizeBuffer.getHeight() != mHeight) {
1409 mResizeBuffer.resize(mWidth, mHeight);
1410 }
Chet Haase603f6de2012-09-14 15:31:25 -07001411 // TODO: should handle create/resize failure
Romain Guyc89b14b2012-08-08 14:53:48 -07001412 layerCanvas = mResizeBuffer.start(hwRendererCanvas);
Chet Haase08837c22011-11-28 11:53:21 -08001413 layerCanvas.setViewport(mWidth, mHeight);
1414 layerCanvas.onPreDraw(null);
1415 final int restoreCount = layerCanvas.save();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001416
Chet Haase08837c22011-11-28 11:53:21 -08001417 layerCanvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001418
1419 int yoff;
1420 final boolean scrolling = mScroller != null
1421 && mScroller.computeScrollOffset();
1422 if (scrolling) {
1423 yoff = mScroller.getCurrY();
1424 mScroller.abortAnimation();
1425 } else {
1426 yoff = mScrollY;
1427 }
1428
Chet Haase08837c22011-11-28 11:53:21 -08001429 layerCanvas.translate(0, -yoff);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001430 if (mTranslator != null) {
Chet Haase08837c22011-11-28 11:53:21 -08001431 mTranslator.translateCanvas(layerCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001432 }
1433
Chet Haase08837c22011-11-28 11:53:21 -08001434 mView.draw(layerCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001435
Svetoslav Ganov42138042012-03-20 11:51:39 -07001436 drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1437
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001438 mResizeBufferStartTime = SystemClock.uptimeMillis();
1439 mResizeBufferDuration = mView.getResources().getInteger(
1440 com.android.internal.R.integer.config_mediumAnimTime);
1441 completed = true;
1442
Chet Haase08837c22011-11-28 11:53:21 -08001443 layerCanvas.restoreToCount(restoreCount);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001444 } catch (OutOfMemoryError e) {
1445 Log.w(TAG, "Not enough memory for content change anim buffer", e);
1446 } finally {
Chet Haase08837c22011-11-28 11:53:21 -08001447 if (layerCanvas != null) {
1448 layerCanvas.onPostDraw();
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001449 }
1450 if (mResizeBuffer != null) {
Romain Guyc89b14b2012-08-08 14:53:48 -07001451 mResizeBuffer.end(hwRendererCanvas);
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001452 if (!completed) {
1453 mResizeBuffer.destroy();
1454 mResizeBuffer = null;
1455 }
1456 }
1457 }
1458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1461 + mAttachInfo.mContentInsets);
1462 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001463 if (contentInsetsChanged || mLastSystemUiVisibility !=
1464 mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested) {
1465 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1466 mFitSystemWindowsRequested = false;
1467 mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1468 host.fitSystemWindows(mFitSystemWindowsInsets);
1469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 if (visibleInsetsChanged) {
1471 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1472 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1473 + mAttachInfo.mVisibleInsets);
1474 }
1475
1476 if (!hadSurface) {
1477 if (mSurface.isValid()) {
1478 // If we are creating a new surface, then we need to
1479 // completely redraw it. Also, when we get to the
1480 // point of drawing it we will hold off and schedule
1481 // a new traversal instead. This is so we can tell the
1482 // window manager about all of the windows being displayed
1483 // before actually drawing them, so it can display then
1484 // all at once.
1485 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001486 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001487 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001488
Romain Guyb051e892010-09-28 19:09:36 -07001489 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001490 try {
Romain Guy786fc932012-07-24 16:24:56 -07001491 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
1492 mHolder.getSurface());
Dianne Hackborn64825172011-03-02 21:32:58 -08001493 } catch (Surface.OutOfResourcesException e) {
1494 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1495 try {
Dianne Hackborn3b842062012-09-23 13:29:44 -07001496 if (!mWindowSession.outOfMemory(mWindow) &&
1497 Process.myUid() != Process.SYSTEM_UID) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001498 Slog.w(TAG, "No processes killed for memory; killing self");
1499 Process.killProcess(Process.myPid());
1500 }
1501 } catch (RemoteException ex) {
1502 }
1503 mLayoutRequested = true; // ask wm for a new surface next time.
1504 return;
1505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 }
1507 }
1508 } else if (!mSurface.isValid()) {
1509 // If the surface has been removed, then reset the scroll
1510 // positions.
1511 mLastScrolledFocus = null;
1512 mScrollY = mCurScrollY = 0;
1513 if (mScroller != null) {
1514 mScroller.abortAnimation();
1515 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07001516 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001517 // Our surface is gone
1518 if (mAttachInfo.mHardwareRenderer != null &&
1519 mAttachInfo.mHardwareRenderer.isEnabled()) {
1520 mAttachInfo.mHardwareRenderer.destroy(true);
1521 }
Romain Guy2a83f002011-01-18 18:28:21 -08001522 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1523 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001524 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001525 try {
Romain Guy786fc932012-07-24 16:24:56 -07001526 mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
Dianne Hackborn64825172011-03-02 21:32:58 -08001527 } catch (Surface.OutOfResourcesException e) {
1528 Log.e(TAG, "OutOfResourcesException updating HW surface", e);
1529 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001530 if (!mWindowSession.outOfMemory(mWindow)) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001531 Slog.w(TAG, "No processes killed for memory; killing self");
1532 Process.killProcess(Process.myPid());
1533 }
1534 } catch (RemoteException ex) {
1535 }
1536 mLayoutRequested = true; // ask wm for a new surface next time.
1537 return;
1538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 }
1540 } catch (RemoteException e) {
1541 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001544 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545
1546 attachInfo.mWindowLeft = frame.left;
1547 attachInfo.mWindowTop = frame.top;
1548
1549 // !!FIXME!! This next section handles the case where we did not get the
1550 // window size we asked for. We should avoid this by getting a maximum size from
1551 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001552 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001553 mWidth = frame.width();
1554 mHeight = frame.height();
1555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001557 if (mSurfaceHolder != null) {
1558 // The app owns the surface; tell it about what is going on.
1559 if (mSurface.isValid()) {
1560 // XXX .copyFrom() doesn't work!
1561 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1562 mSurfaceHolder.mSurface = mSurface;
1563 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001564 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001565 mSurfaceHolder.mSurfaceLock.unlock();
1566 if (mSurface.isValid()) {
1567 if (!hadSurface) {
1568 mSurfaceHolder.ungetCallbacks();
1569
1570 mIsCreating = true;
1571 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1572 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1573 if (callbacks != null) {
1574 for (SurfaceHolder.Callback c : callbacks) {
1575 c.surfaceCreated(mSurfaceHolder);
1576 }
1577 }
1578 surfaceChanged = true;
1579 }
1580 if (surfaceChanged) {
1581 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1582 lp.format, mWidth, mHeight);
1583 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1584 if (callbacks != null) {
1585 for (SurfaceHolder.Callback c : callbacks) {
1586 c.surfaceChanged(mSurfaceHolder, lp.format,
1587 mWidth, mHeight);
1588 }
1589 }
1590 }
1591 mIsCreating = false;
1592 } else if (hadSurface) {
1593 mSurfaceHolder.ungetCallbacks();
1594 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1595 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1596 if (callbacks != null) {
1597 for (SurfaceHolder.Callback c : callbacks) {
1598 c.surfaceDestroyed(mSurfaceHolder);
1599 }
1600 }
1601 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001602 try {
1603 mSurfaceHolder.mSurface = new Surface();
1604 } finally {
1605 mSurfaceHolder.mSurfaceLock.unlock();
1606 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001607 }
1608 }
Romain Guy53389bd2010-09-07 17:16:32 -07001609
Chet Haase40e03832011-10-06 08:34:13 -07001610 if (mAttachInfo.mHardwareRenderer != null &&
1611 mAttachInfo.mHardwareRenderer.isEnabled()) {
1612 if (hwInitialized || windowShouldResize ||
1613 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1614 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1615 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1616 if (!hwInitialized) {
Romain Guy786fc932012-07-24 16:24:56 -07001617 mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
Chet Haase391fef02012-09-27 15:26:36 -07001618 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001619 }
Romain Guy03985752011-07-11 15:33:51 -07001620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 }
1622
Dianne Hackbornce418e62011-03-01 14:31:38 -08001623 if (!mStopped) {
1624 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001625 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001626 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1627 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001628 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1629 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001630
1631 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1632 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1633 + " mHeight=" + mHeight
1634 + " measuredHeight=" + host.getMeasuredHeight()
1635 + " coveredInsetsChanged=" + contentInsetsChanged);
1636
1637 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001638 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001639
1640 // Implementation of weights from WindowManager.LayoutParams
1641 // We just grow the dimensions as needed and re-measure if
1642 // needs be
1643 int width = host.getMeasuredWidth();
1644 int height = host.getMeasuredHeight();
1645 boolean measureAgain = false;
1646
1647 if (lp.horizontalWeight > 0.0f) {
1648 width += (int) ((mWidth - width) * lp.horizontalWeight);
1649 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1650 MeasureSpec.EXACTLY);
1651 measureAgain = true;
1652 }
1653 if (lp.verticalWeight > 0.0f) {
1654 height += (int) ((mHeight - height) * lp.verticalWeight);
1655 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1656 MeasureSpec.EXACTLY);
1657 measureAgain = true;
1658 }
1659
1660 if (measureAgain) {
1661 if (DEBUG_LAYOUT) Log.v(TAG,
1662 "And hey let's measure once more: width=" + width
1663 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001664 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001665 }
1666
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001667 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001670 } else {
1671 // Not the first pass and no window/insets/visibility change but the window
1672 // may have moved and we need check that and if so to update the left and right
1673 // in the attach info. We translate only the window frame since on window move
1674 // the window manager tells us only for the new frame but the insets are the
1675 // same and we do not want to translate them more than once.
1676
1677 // TODO: Well, we are checking whether the frame has changed similarly
1678 // to how this is done for the insets. This is however incorrect since
1679 // the insets and the frame are translated. For example, the old frame
1680 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1681 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1682 // true since we are comparing a not translated value to a translated one.
1683 // This scenario is rare but we may want to fix that.
1684
1685 final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1686 || attachInfo.mWindowTop != frame.top);
1687 if (windowMoved) {
1688 if (mTranslator != null) {
1689 mTranslator.translateRectInScreenToAppWinFrame(frame);
1690 }
1691 attachInfo.mWindowLeft = frame.left;
1692 attachInfo.mWindowTop = frame.top;
1693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 }
1695
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001696 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 boolean triggerGlobalLayoutListener = didLayout
1698 || attachInfo.mRecomputeGlobalAttributes;
1699 if (didLayout) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001700 performLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701
1702 // By this point all views have been sized and positionned
1703 // We can compute the transparent area
1704
Dianne Hackborn4702a852012-08-17 15:18:29 -07001705 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 // start out transparent
1707 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1708 host.getLocationInWindow(mTmpLocation);
1709 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1710 mTmpLocation[0] + host.mRight - host.mLeft,
1711 mTmpLocation[1] + host.mBottom - host.mTop);
1712
1713 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001714 if (mTranslator != null) {
1715 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1716 }
1717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1719 mPreviousTransparentRegion.set(mTransparentRegion);
1720 // reconfigure window manager
1721 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001722 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 } catch (RemoteException e) {
1724 }
1725 }
1726 }
1727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 if (DBG) {
1729 System.out.println("======================================");
1730 System.out.println("performTraversals -- after setFrame");
1731 host.debug();
1732 }
1733 }
1734
1735 if (triggerGlobalLayoutListener) {
1736 attachInfo.mRecomputeGlobalAttributes = false;
1737 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001738
1739 if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07001740 postSendWindowContentChangedCallback(mView);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743
1744 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001745 // Clear the original insets.
1746 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1747 insets.reset();
1748
1749 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001751
1752 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1754 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001755
1756 // Translate insets to screen coordinates if needed.
1757 final Rect contentInsets;
1758 final Rect visibleInsets;
1759 final Region touchableRegion;
1760 if (mTranslator != null) {
1761 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1762 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1763 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1764 } else {
1765 contentInsets = insets.contentInsets;
1766 visibleInsets = insets.visibleInsets;
1767 touchableRegion = insets.touchableRegion;
1768 }
1769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001771 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001772 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 } catch (RemoteException e) {
1774 }
1775 }
1776 }
Romain Guy8506ab42009-06-11 17:35:47 -07001777
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001778 boolean skipDraw = false;
1779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 if (mFirst) {
1781 // handle first focus request
1782 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1783 + mView.hasFocus());
1784 if (mView != null) {
1785 if (!mView.hasFocus()) {
1786 mView.requestFocus(View.FOCUS_FORWARD);
1787 mFocusedView = mRealFocusedView = mView.findFocus();
1788 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
1789 + mFocusedView);
1790 } else {
1791 mRealFocusedView = mView.findFocus();
1792 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
1793 + mRealFocusedView);
1794 }
1795 }
Jeff Brown98365d72012-08-19 20:30:52 -07001796 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001797 // The first time we relayout the window, if the system is
1798 // doing window animations, we want to hold of on any future
1799 // draws until the animation is done.
1800 mWindowsAnimating = true;
1801 }
1802 } else if (mWindowsAnimating) {
1803 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 }
1805
1806 mFirst = false;
1807 mWillDrawSoon = false;
1808 mNewSurfaceNeeded = false;
1809 mViewVisibility = viewVisibility;
1810
1811 if (mAttachInfo.mHasWindowFocus) {
1812 final boolean imTarget = WindowManager.LayoutParams
1813 .mayUseInputMethod(mWindowAttributes.flags);
1814 if (imTarget != mLastWasImTarget) {
1815 mLastWasImTarget = imTarget;
1816 InputMethodManager imm = InputMethodManager.peekInstance();
1817 if (imm != null && imTarget) {
1818 imm.startGettingWindowFocus(mView);
1819 imm.onWindowFocus(mView, mView.findFocus(),
1820 mWindowAttributes.softInputMode,
1821 !mHasHadWindowFocus, mWindowAttributes.flags);
1822 }
1823 }
1824 }
Romain Guy8506ab42009-06-11 17:35:47 -07001825
Jeff Brown96e942d2011-11-30 19:55:01 -08001826 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001827 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001828 mReportNextDraw = true;
1829 }
1830
Romain Guyea835032011-07-28 19:24:37 -07001831 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1832 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833
Chet Haase61158c62011-09-06 22:19:45 -07001834 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001835 if (!skipDraw || mReportNextDraw) {
1836 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1837 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1838 mPendingTransitions.get(i).startChangingAnimations();
1839 }
1840 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001841 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001842
1843 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001846 if (viewVisibility == View.VISIBLE) {
1847 // Try again
1848 scheduleTraversals();
1849 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001850 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1851 mPendingTransitions.get(i).endChangingAnimations();
1852 }
1853 mPendingTransitions.clear();
1854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001856
1857 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 }
1859
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001860 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1861 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1862 try {
1863 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1864 } finally {
1865 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1866 }
1867 }
1868
1869 private void performLayout() {
1870 mLayoutRequested = false;
1871 mScrollMayChange = true;
1872
1873 final View host = mView;
1874 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1875 Log.v(TAG, "Laying out " + host + " to (" +
1876 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
1877 }
1878
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001879 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
1880 try {
1881 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
1882 } finally {
1883 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1884 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001885 }
1886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 public void requestTransparentRegion(View child) {
1888 // the test below should not fail unless someone is messing with us
1889 checkThread();
1890 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001891 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 // Need to make sure we re-evaluate the window attributes next
1893 // time around, to ensure the window has the correct format.
1894 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07001895 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07001896 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 }
1898 }
1899
1900 /**
1901 * Figures out the measure spec for the root view in a window based on it's
1902 * layout params.
1903 *
1904 * @param windowSize
1905 * The available width or height of the window
1906 *
1907 * @param rootDimension
1908 * The layout params for one dimension (width or height) of the
1909 * window.
1910 *
1911 * @return The measure spec to use to measure the root view.
1912 */
Romain Guya998dff2012-03-23 18:58:36 -07001913 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 int measureSpec;
1915 switch (rootDimension) {
1916
Romain Guy980a9382010-01-08 15:06:28 -08001917 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 // Window can't resize. Force root view to be windowSize.
1919 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
1920 break;
1921 case ViewGroup.LayoutParams.WRAP_CONTENT:
1922 // Window can resize. Set max size for root view.
1923 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
1924 break;
1925 default:
1926 // Window wants to be an exact size. Force root view to be that size.
1927 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
1928 break;
1929 }
1930 return measureSpec;
1931 }
1932
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001933 int mHardwareYOffset;
1934 int mResizeAlpha;
1935 final Paint mResizePaint = new Paint();
1936
Romain Guy7d70fbf2011-05-24 17:40:25 -07001937 public void onHardwarePreDraw(HardwareCanvas canvas) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001938 canvas.translate(0, -mHardwareYOffset);
1939 }
1940
Romain Guy7d70fbf2011-05-24 17:40:25 -07001941 public void onHardwarePostDraw(HardwareCanvas canvas) {
1942 if (mResizeBuffer != null) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001943 mResizePaint.setAlpha(mResizeAlpha);
Romain Guy7d70fbf2011-05-24 17:40:25 -07001944 canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001945 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001946 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001947 }
1948
Chet Haaseed30fd82011-04-22 16:18:45 -07001949 /**
1950 * @hide
1951 */
1952 void outputDisplayList(View view) {
1953 if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
Chet Haaseed30fd82011-04-22 16:18:45 -07001954 DisplayList displayList = view.getDisplayList();
1955 if (displayList != null) {
Romain Guy59a12ca2011-06-09 17:48:21 -07001956 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
1957 }
1958 }
1959 }
1960
1961 /**
1962 * @see #PROPERTY_PROFILE_RENDERING
1963 */
1964 private void profileRendering(boolean enabled) {
1965 if (mProfileRendering) {
1966 mRenderProfilingEnabled = enabled;
1967 if (mRenderProfiler == null) {
1968 mRenderProfiler = new Thread(new Runnable() {
1969 @Override
1970 public void run() {
1971 Log.d(TAG, "Starting profiling thread");
1972 while (mRenderProfilingEnabled) {
1973 mAttachInfo.mHandler.post(new Runnable() {
1974 @Override
1975 public void run() {
1976 mDirty.set(0, 0, mWidth, mHeight);
1977 scheduleTraversals();
1978 }
1979 });
1980 try {
1981 // TODO: This should use vsync when we get an API
1982 Thread.sleep(15);
1983 } catch (InterruptedException e) {
1984 Log.d(TAG, "Exiting profiling thread");
1985 }
1986 }
1987 }
1988 }, "Rendering Profiler");
1989 mRenderProfiler.start();
1990 } else {
1991 mRenderProfiler.interrupt();
1992 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07001993 }
1994 }
1995 }
1996
Chet Haase2f2022a2011-10-11 06:41:59 -07001997 /**
1998 * Called from draw() when DEBUG_FPS is enabled
1999 */
2000 private void trackFPS() {
2001 // Tracks frames per second drawn. First value in a series of draws may be bogus
2002 // because it down not account for the intervening idle time
2003 long nowTime = System.currentTimeMillis();
2004 if (mFpsStartTime < 0) {
2005 mFpsStartTime = mFpsPrevTime = nowTime;
2006 mFpsNumFrames = 0;
2007 } else {
2008 ++mFpsNumFrames;
2009 String thisHash = Integer.toHexString(System.identityHashCode(this));
2010 long frameTime = nowTime - mFpsPrevTime;
2011 long totalTime = nowTime - mFpsStartTime;
2012 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2013 mFpsPrevTime = nowTime;
2014 if (totalTime > 1000) {
2015 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2016 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2017 mFpsStartTime = nowTime;
2018 mFpsNumFrames = 0;
2019 }
2020 }
2021 }
2022
Jeff Brown96e942d2011-11-30 19:55:01 -08002023 private void performDraw() {
Craig Mautner006f0e42012-03-21 11:00:32 -07002024 if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2025 return;
2026 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002027
Jeff Brown96e942d2011-11-30 19:55:01 -08002028 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2029 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002030
Romain Guy1f59e5c2012-05-06 14:11:16 -07002031 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002032 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2033 try {
2034 draw(fullRedrawNeeded);
2035 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002036 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002037 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2038 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002039
Jeff Brown96e942d2011-11-30 19:55:01 -08002040 if (mReportNextDraw) {
2041 mReportNextDraw = false;
2042
2043 if (LOCAL_LOGV) {
2044 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2045 }
2046 if (mSurfaceHolder != null && mSurface.isValid()) {
2047 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2048 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2049 if (callbacks != null) {
2050 for (SurfaceHolder.Callback c : callbacks) {
2051 if (c instanceof SurfaceHolder.Callback2) {
2052 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2053 mSurfaceHolder);
2054 }
2055 }
2056 }
2057 }
2058 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002059 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002060 } catch (RemoteException e) {
2061 }
2062 }
2063 }
2064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 private void draw(boolean fullRedrawNeeded) {
2066 Surface surface = mSurface;
2067 if (surface == null || !surface.isValid()) {
2068 return;
2069 }
2070
Chet Haase2f2022a2011-10-11 06:41:59 -07002071 if (DEBUG_FPS) {
2072 trackFPS();
2073 }
2074
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002075 if (!sFirstDrawComplete) {
2076 synchronized (sFirstDrawHandlers) {
2077 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002078 final int count = sFirstDrawHandlers.size();
2079 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002080 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002081 }
2082 }
2083 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 scrollToRectOrFocus(null, false);
2086
Romain Guy25eba5c2012-04-04 17:29:03 -07002087 final AttachInfo attachInfo = mAttachInfo;
2088 if (attachInfo.mViewScrollChanged) {
2089 attachInfo.mViewScrollChanged = false;
2090 attachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 }
Romain Guy8506ab42009-06-11 17:35:47 -07002092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002094 boolean animating = mScroller != null && mScroller.computeScrollOffset();
2095 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 yoff = mScroller.getCurrY();
2097 } else {
2098 yoff = mScrollY;
2099 }
2100 if (mCurScrollY != yoff) {
2101 mCurScrollY = yoff;
2102 fullRedrawNeeded = true;
2103 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002104
Romain Guy25eba5c2012-04-04 17:29:03 -07002105 final float appScale = attachInfo.mApplicationScale;
2106 final boolean scalingRequired = attachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002108 int resizeAlpha = 0;
Romain Guy7d70fbf2011-05-24 17:40:25 -07002109 if (mResizeBuffer != null) {
2110 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2111 if (deltaTime < mResizeBufferDuration) {
2112 float amt = deltaTime/(float) mResizeBufferDuration;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002113 amt = mResizeInterpolator.getInterpolation(amt);
2114 animating = true;
2115 resizeAlpha = 255 - (int)(amt*255);
2116 } else {
Romain Guy7d70fbf2011-05-24 17:40:25 -07002117 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002118 }
2119 }
2120
Jeff Brown96e942d2011-11-30 19:55:01 -08002121 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002122 if (mSurfaceHolder != null) {
2123 // The app owns the surface, we won't draw.
2124 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002125 if (animating) {
2126 if (mScroller != null) {
2127 mScroller.abortAnimation();
2128 }
Romain Guy7d70fbf2011-05-24 17:40:25 -07002129 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002130 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002131 return;
2132 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002133
2134 if (fullRedrawNeeded) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002135 attachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002136 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002137 }
Chet Haasead4f7032011-06-22 09:18:31 -07002138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002140 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 + mWindowAttributes.getTitle()
2142 + ": dirty={" + dirty.left + "," + dirty.top
2143 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002144 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2145 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 }
2147
Romain Guy25eba5c2012-04-04 17:29:03 -07002148 attachInfo.mTreeObserver.dispatchOnDraw();
2149
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002150 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002151 if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002152 // Draw with hardware renderer.
2153 mIsAnimating = false;
2154 mHardwareYOffset = yoff;
2155 mResizeAlpha = resizeAlpha;
Romain Guyfea12b82011-01-27 15:36:40 -08002156
Jeff Brown96e942d2011-11-30 19:55:01 -08002157 mCurrentDirty.set(dirty);
2158 mCurrentDirty.union(mPreviousDirty);
2159 mPreviousDirty.set(dirty);
2160 dirty.setEmpty();
2161
Romain Guy25eba5c2012-04-04 17:29:03 -07002162 if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
Jeff Brown96e942d2011-11-30 19:55:01 -08002163 animating ? null : mCurrentDirty)) {
2164 mPreviousDirty.set(0, 0, mWidth, mHeight);
Jeff Brown4e91a182011-04-07 11:38:09 -07002165 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002166 } else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2167 return;
Jeff Brown95db2b22011-11-30 19:54:41 -08002168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 }
Romain Guy8506ab42009-06-11 17:35:47 -07002170
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002171 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 mFullRedrawNeeded = true;
2173 scheduleTraversals();
2174 }
2175 }
2176
Romain Guy25eba5c2012-04-04 17:29:03 -07002177 /**
Romain Guyedbca122012-04-04 18:25:53 -07002178 * @return true if drawing was succesfull, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002179 */
2180 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2181 boolean scalingRequired, Rect dirty) {
2182
Romain Guy413baf82012-05-15 19:15:47 -07002183 // If we get here with a disabled & requested hardware renderer, something went
2184 // wrong (an invalidate posted right before we destroyed the hardware surface
2185 // for instance) so we should just bail out. Locking the surface with software
2186 // rendering at this point would lock it forever and prevent hardware renderer
2187 // from doing its job when it comes back.
2188 if (attachInfo.mHardwareRenderer != null && !attachInfo.mHardwareRenderer.isEnabled() &&
2189 attachInfo.mHardwareRenderer.isRequested()) {
2190 mFullRedrawNeeded = true;
2191 scheduleTraversals();
2192 return false;
2193 }
2194
Romain Guy25eba5c2012-04-04 17:29:03 -07002195 // Draw with software renderer.
2196 Canvas canvas;
2197 try {
2198 int left = dirty.left;
2199 int top = dirty.top;
2200 int right = dirty.right;
2201 int bottom = dirty.bottom;
2202
Romain Guy25eba5c2012-04-04 17:29:03 -07002203 canvas = mSurface.lockCanvas(dirty);
2204
Romain Guy25eba5c2012-04-04 17:29:03 -07002205 if (left != dirty.left || top != dirty.top || right != dirty.right ||
2206 bottom != dirty.bottom) {
2207 attachInfo.mIgnoreDirtyState = true;
2208 }
2209
2210 // TODO: Do this in native
2211 canvas.setDensity(mDensity);
2212 } catch (Surface.OutOfResourcesException e) {
2213 Log.e(TAG, "OutOfResourcesException locking surface", e);
2214 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002215 if (!mWindowSession.outOfMemory(mWindow)) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002216 Slog.w(TAG, "No processes killed for memory; killing self");
2217 Process.killProcess(Process.myPid());
2218 }
2219 } catch (RemoteException ex) {
2220 }
2221 mLayoutRequested = true; // ask wm for a new surface next time.
2222 return false;
2223 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002224 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002225 // Don't assume this is due to out of memory, it could be
2226 // something else, and if it is something else then we could
2227 // kill stuff (or ourself) for no reason.
2228 mLayoutRequested = true; // ask wm for a new surface next time.
2229 return false;
2230 }
2231
2232 try {
2233 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2234 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2235 + canvas.getWidth() + ", h=" + canvas.getHeight());
2236 //canvas.drawARGB(255, 255, 0, 0);
2237 }
2238
Romain Guy25eba5c2012-04-04 17:29:03 -07002239 // If this bitmap's format includes an alpha channel, we
2240 // need to clear it before drawing so that the child will
2241 // properly re-composite its drawing on a transparent
2242 // background. This automatically respects the clip/dirty region
2243 // or
2244 // If we are applying an offset, we need to clear the area
2245 // where the offset doesn't appear to avoid having garbage
2246 // left in the blank areas.
2247 if (!canvas.isOpaque() || yoff != 0) {
2248 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2249 }
2250
2251 dirty.setEmpty();
2252 mIsAnimating = false;
2253 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002254 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002255
2256 if (DEBUG_DRAW) {
2257 Context cxt = mView.getContext();
2258 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2259 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2260 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2261 }
2262 try {
2263 canvas.translate(0, -yoff);
2264 if (mTranslator != null) {
2265 mTranslator.translateCanvas(canvas);
2266 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002267 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002268 attachInfo.mSetIgnoreDirtyState = false;
2269
Romain Guy25eba5c2012-04-04 17:29:03 -07002270 mView.draw(canvas);
2271
Svetoslav Ganov42138042012-03-20 11:51:39 -07002272 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002273 } finally {
2274 if (!attachInfo.mSetIgnoreDirtyState) {
2275 // Only clear the flag if it was not set during the mView.draw() call
2276 attachInfo.mIgnoreDirtyState = false;
2277 }
2278 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002279 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002280 try {
2281 surface.unlockCanvasAndPost(canvas);
2282 } catch (IllegalArgumentException e) {
2283 Log.e(TAG, "Could not unlock surface", e);
2284 mLayoutRequested = true; // ask wm for a new surface next time.
2285 //noinspection ReturnInsideFinallyBlock
2286 return false;
2287 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002288
Romain Guy25eba5c2012-04-04 17:29:03 -07002289 if (LOCAL_LOGV) {
2290 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2291 }
2292 }
2293 return true;
2294 }
2295
Svetoslav Ganov42138042012-03-20 11:51:39 -07002296 /**
2297 * We want to draw a highlight around the current accessibility focused.
2298 * Since adding a style for all possible view is not a viable option we
2299 * have this specialized drawing method.
2300 *
2301 * Note: We are doing this here to be able to draw the highlight for
2302 * virtual views in addition to real ones.
2303 *
2304 * @param canvas The canvas on which to draw.
2305 */
2306 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
Svetoslav Ganov07b726c2012-04-30 12:24:57 -07002307 AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2308 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002309 return;
2310 }
2311 if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
2312 return;
2313 }
2314 Drawable drawable = getAccessibilityFocusedDrawable();
2315 if (drawable == null) {
2316 return;
2317 }
2318 AccessibilityNodeProvider provider =
2319 mAccessibilityFocusedHost.getAccessibilityNodeProvider();
2320 Rect bounds = mView.mAttachInfo.mTmpInvalRect;
2321 if (provider == null) {
2322 mAccessibilityFocusedHost.getDrawingRect(bounds);
2323 if (mView instanceof ViewGroup) {
2324 ViewGroup viewGroup = (ViewGroup) mView;
Svetoslav Ganovc8860602012-10-05 17:45:06 -07002325 try {
2326 viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
2327 } catch (IllegalArgumentException iae) {
2328 Log.e(TAG, "Temporary detached view that was neither removed not reattached: "
2329 + mAccessibilityFocusedHost);
2330 return;
2331 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002332 }
2333 } else {
2334 if (mAccessibilityFocusedVirtualView == null) {
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07002335 return;
2336 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002337 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
2338 bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
2339 }
2340 drawable.setBounds(bounds);
2341 drawable.draw(canvas);
2342 }
2343
2344 private Drawable getAccessibilityFocusedDrawable() {
2345 if (mAttachInfo != null) {
2346 // Lazily load the accessibility focus drawable.
2347 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2348 TypedValue value = new TypedValue();
2349 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2350 R.attr.accessibilityFocusedDrawable, value, true);
2351 if (resolved) {
2352 mAttachInfo.mAccessibilityFocusDrawable =
2353 mView.mContext.getResources().getDrawable(value.resourceId);
2354 }
2355 }
2356 return mAttachInfo.mAccessibilityFocusDrawable;
2357 }
2358 return null;
2359 }
2360
Romain Guy51e4d4d2012-03-15 18:30:47 -07002361 void invalidateDisplayLists() {
2362 final ArrayList<DisplayList> displayLists = mDisplayLists;
2363 final int count = displayLists.size();
2364
2365 for (int i = 0; i < count; i++) {
Romain Guy38c2ece2012-05-24 14:20:56 -07002366 final DisplayList displayList = displayLists.get(i);
2367 displayList.invalidate();
2368 displayList.clear();
Romain Guy51e4d4d2012-03-15 18:30:47 -07002369 }
2370
2371 displayLists.clear();
2372 }
2373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2375 final View.AttachInfo attachInfo = mAttachInfo;
2376 final Rect ci = attachInfo.mContentInsets;
2377 final Rect vi = attachInfo.mVisibleInsets;
2378 int scrollY = 0;
2379 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002381 if (vi.left > ci.left || vi.top > ci.top
2382 || vi.right > ci.right || vi.bottom > ci.bottom) {
2383 // We'll assume that we aren't going to change the scroll
2384 // offset, since we want to avoid that unless it is actually
2385 // going to make the focus visible... otherwise we scroll
2386 // all over the place.
2387 scrollY = mScrollY;
2388 // We can be called for two different situations: during a draw,
2389 // to update the scroll position if the focus has changed (in which
2390 // case 'rectangle' is null), or in response to a
2391 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2392 // is non-null and we just want to scroll to whatever that
2393 // rectangle is).
2394 View focus = mRealFocusedView;
Romain Guye8b16522009-07-14 13:06:42 -07002395
2396 // When in touch mode, focus points to the previously focused view,
2397 // which may have been removed from the view hierarchy. The following
Joe Onoratob71193b2009-11-24 18:34:42 -05002398 // line checks whether the view is still in our hierarchy.
2399 if (focus == null || focus.mAttachInfo != mAttachInfo) {
Romain Guye8b16522009-07-14 13:06:42 -07002400 mRealFocusedView = null;
2401 return false;
2402 }
2403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 if (focus != mLastScrolledFocus) {
2405 // If the focus has changed, then ignore any requests to scroll
2406 // to a rectangle; first we want to make sure the entire focus
2407 // view is visible.
2408 rectangle = null;
2409 }
2410 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2411 + " rectangle=" + rectangle + " ci=" + ci
2412 + " vi=" + vi);
2413 if (focus == mLastScrolledFocus && !mScrollMayChange
2414 && rectangle == null) {
2415 // Optimization: if the focus hasn't changed since last
2416 // time, and no layout has happened, then just leave things
2417 // as they are.
2418 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2419 + mScrollY + " vi=" + vi.toShortString());
2420 } else if (focus != null) {
2421 // We need to determine if the currently focused view is
2422 // within the visible part of the window and, if not, apply
2423 // a pan so it can be seen.
2424 mLastScrolledFocus = focus;
2425 mScrollMayChange = false;
2426 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2427 // Try to find the rectangle from the focus view.
2428 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2429 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2430 + mView.getWidth() + " h=" + mView.getHeight()
2431 + " ci=" + ci.toShortString()
2432 + " vi=" + vi.toShortString());
2433 if (rectangle == null) {
2434 focus.getFocusedRect(mTempRect);
2435 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2436 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002437 if (mView instanceof ViewGroup) {
2438 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2439 focus, mTempRect);
2440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002441 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2442 "Focus in window: focusRect="
2443 + mTempRect.toShortString()
2444 + " visRect=" + mVisRect.toShortString());
2445 } else {
2446 mTempRect.set(rectangle);
2447 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2448 "Request scroll to rect: "
2449 + mTempRect.toShortString()
2450 + " visRect=" + mVisRect.toShortString());
2451 }
2452 if (mTempRect.intersect(mVisRect)) {
2453 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2454 "Focus window visible rect: "
2455 + mTempRect.toShortString());
2456 if (mTempRect.height() >
2457 (mView.getHeight()-vi.top-vi.bottom)) {
2458 // If the focus simply is not going to fit, then
2459 // best is probably just to leave things as-is.
2460 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2461 "Too tall; leaving scrollY=" + scrollY);
2462 } else if ((mTempRect.top-scrollY) < vi.top) {
2463 scrollY -= vi.top - (mTempRect.top-scrollY);
2464 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2465 "Top covered; scrollY=" + scrollY);
2466 } else if ((mTempRect.bottom-scrollY)
2467 > (mView.getHeight()-vi.bottom)) {
2468 scrollY += (mTempRect.bottom-scrollY)
2469 - (mView.getHeight()-vi.bottom);
2470 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2471 "Bottom covered; scrollY=" + scrollY);
2472 }
2473 handled = true;
2474 }
2475 }
2476 }
2477 }
Romain Guy8506ab42009-06-11 17:35:47 -07002478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 if (scrollY != mScrollY) {
2480 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2481 + mScrollY + " , new=" + scrollY);
Romain Guy7d70fbf2011-05-24 17:40:25 -07002482 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 if (mScroller == null) {
2484 mScroller = new Scroller(mView.getContext());
2485 }
2486 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2487 } else if (mScroller != null) {
2488 mScroller.abortAnimation();
2489 }
2490 mScrollY = scrollY;
2491 }
Romain Guy8506ab42009-06-11 17:35:47 -07002492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 return handled;
2494 }
Romain Guy8506ab42009-06-11 17:35:47 -07002495
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002496 /**
2497 * @hide
2498 */
2499 public View getAccessibilityFocusedHost() {
2500 return mAccessibilityFocusedHost;
2501 }
2502
2503 /**
2504 * @hide
2505 */
2506 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2507 return mAccessibilityFocusedVirtualView;
2508 }
2509
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002510 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002511 // If we have a virtual view with accessibility focus we need
2512 // to clear the focus and invalidate the virtual view bounds.
2513 if (mAccessibilityFocusedVirtualView != null) {
2514
2515 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2516 View focusHost = mAccessibilityFocusedHost;
2517 focusHost.clearAccessibilityFocusNoCallbacks();
2518
2519 // Wipe the state of the current accessibility focus since
2520 // the call into the provider to clear accessibility focus
2521 // will fire an accessibility event which will end up calling
2522 // this method and we want to have clean state when this
2523 // invocation happens.
2524 mAccessibilityFocusedHost = null;
2525 mAccessibilityFocusedVirtualView = null;
2526
2527 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2528 if (provider != null) {
2529 // Invalidate the area of the cleared accessibility focus.
2530 focusNode.getBoundsInParent(mTempRect);
2531 focusHost.invalidate(mTempRect);
2532 // Clear accessibility focus in the virtual node.
2533 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2534 focusNode.getSourceNodeId());
2535 provider.performAction(virtualNodeId,
2536 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2537 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002538 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002539 }
2540 if (mAccessibilityFocusedHost != null) {
2541 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002542 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2543 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002544
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002545 // Set the new focus host and node.
2546 mAccessibilityFocusedHost = view;
2547 mAccessibilityFocusedVirtualView = node;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002548 }
2549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 public void requestChildFocus(View child, View focused) {
2551 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002552
2553 if (DEBUG_INPUT_RESIZE) {
2554 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002556
2557 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused);
2558 scheduleTraversals();
2559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560 mFocusedView = mRealFocusedView = focused;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 }
2562
2563 public void clearChildFocus(View child) {
2564 checkThread();
2565
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002566 if (DEBUG_INPUT_RESIZE) {
2567 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002569
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002570 mOldFocusedView = mFocusedView;
2571
2572 // Invoke the listener only if there is no view to take focus
2573 if (focusSearch(null, View.FOCUS_FORWARD) == null) {
2574 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null);
2575 }
2576
2577 mFocusedView = mRealFocusedView = null;
2578 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002579
Svetoslav Ganov42138042012-03-20 11:51:39 -07002580 @Override
2581 public ViewParent getParentForAccessibility() {
2582 return null;
2583 }
2584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 public void focusableViewAvailable(View v) {
2586 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002587 if (mView != null) {
2588 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002590 } else {
2591 // the one case where will transfer focus away from the current one
2592 // is if the current view is a view group that prefers to give focus
2593 // to its children first AND the view is a descendant of it.
2594 mFocusedView = mView.findFocus();
2595 boolean descendantsHaveDibsOnFocus =
2596 (mFocusedView instanceof ViewGroup) &&
2597 (((ViewGroup) mFocusedView).getDescendantFocusability() ==
2598 ViewGroup.FOCUS_AFTER_DESCENDANTS);
2599 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
2600 // If a view gets the focus, the listener will be invoked from requestChildFocus()
2601 v.requestFocus();
2602 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603 }
2604 }
2605 }
2606
2607 public void recomputeViewAttributes(View child) {
2608 checkThread();
2609 if (mView == child) {
2610 mAttachInfo.mRecomputeGlobalAttributes = true;
2611 if (!mWillDrawSoon) {
2612 scheduleTraversals();
2613 }
2614 }
2615 }
2616
2617 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002618 if (mView != null && mView.mAttachInfo != null) {
Romain Guy16260e72011-09-01 14:26:11 -07002619 if (mAttachInfo.mHardwareRenderer != null &&
2620 mAttachInfo.mHardwareRenderer.isEnabled()) {
2621 mAttachInfo.mHardwareRenderer.validate();
2622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 mView.dispatchDetachedFromWindow();
2624 }
2625
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002626 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2627 mAccessibilityManager.removeAccessibilityStateChangeListener(
2628 mAccessibilityInteractionConnectionManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002629 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002630
Romain Guya998dff2012-03-23 18:58:36 -07002631 destroyHardwareRenderer();
2632
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002633 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 mView = null;
2636 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07002637 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002638
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002639 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640
Jeff Browncc4f7db2011-08-30 20:34:48 -07002641 if (mInputQueueCallback != null && mInputQueue != null) {
2642 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
2643 mInputQueueCallback = null;
2644 mInputQueue = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08002645 } else if (mInputEventReceiver != null) {
2646 mInputEventReceiver.dispose();
2647 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002649 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002650 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002651 } catch (RemoteException e) {
2652 }
Jeff Brown349703e2010-06-22 01:27:15 -07002653
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002654 // Dispose the input channel after removing the window so the Window Manager
2655 // doesn't interpret the input channel being closed as an abnormal termination.
2656 if (mInputChannel != null) {
2657 mInputChannel.dispose();
2658 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002659 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002660
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002661 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 }
Romain Guy8506ab42009-06-11 17:35:47 -07002663
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002664 void updateConfiguration(Configuration config, boolean force) {
2665 if (DEBUG_CONFIGURATION) Log.v(TAG,
2666 "Applying new config to window "
2667 + mWindowAttributes.getTitle()
2668 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002669
2670 CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
2671 if (ci != null) {
2672 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002673 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002674 }
2675
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002676 synchronized (sConfigCallbacks) {
2677 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2678 sConfigCallbacks.get(i).onConfigurationChanged(config);
2679 }
2680 }
2681 if (mView != null) {
2682 // At this point the resources have been updated to
2683 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002684 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002685 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002686 if (force || mLastConfiguration.diff(config) != 0) {
2687 mLastConfiguration.setTo(config);
2688 mView.dispatchConfigurationChanged(config);
2689 }
2690 }
2691 }
2692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002693 /**
2694 * Return true if child is an ancestor of parent, (or equal to the parent).
2695 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002696 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002697 if (child == parent) {
2698 return true;
2699 }
2700
2701 final ViewParent theParent = child.getParent();
2702 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2703 }
2704
Romain Guycdb86672010-03-18 18:54:50 -07002705 private static void forceLayout(View view) {
2706 view.forceLayout();
2707 if (view instanceof ViewGroup) {
2708 ViewGroup group = (ViewGroup) view;
2709 final int count = group.getChildCount();
2710 for (int i = 0; i < count; i++) {
2711 forceLayout(group.getChildAt(i));
2712 }
2713 }
2714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715
Jeff Browna175a5b2012-02-15 19:18:31 -08002716 private final static int MSG_INVALIDATE = 1;
2717 private final static int MSG_INVALIDATE_RECT = 2;
2718 private final static int MSG_DIE = 3;
2719 private final static int MSG_RESIZED = 4;
2720 private final static int MSG_RESIZED_REPORT = 5;
2721 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
2722 private final static int MSG_DISPATCH_KEY = 7;
2723 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2724 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
2725 private final static int MSG_IME_FINISHED_EVENT = 10;
2726 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2727 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2728 private final static int MSG_CHECK_FOCUS = 13;
2729 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2730 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2731 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2732 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2733 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002734 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2735 private final static int MSG_DISPATCH_SCREEN_STATE = 20;
2736 private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07002737 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07002738 private final static int MSG_DISPATCH_DONE_ANIMATING = 23;
Dianne Hackborna53de062012-05-08 18:53:51 -07002739 private final static int MSG_INVALIDATE_WORLD = 24;
Craig Mautner5702d4d2012-06-30 14:10:16 -07002740 private final static int MSG_WINDOW_MOVED = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741
Jeff Browna175a5b2012-02-15 19:18:31 -08002742 final class ViewRootHandler extends Handler {
2743 @Override
2744 public String getMessageName(Message message) {
2745 switch (message.what) {
2746 case MSG_INVALIDATE:
2747 return "MSG_INVALIDATE";
2748 case MSG_INVALIDATE_RECT:
2749 return "MSG_INVALIDATE_RECT";
2750 case MSG_DIE:
2751 return "MSG_DIE";
2752 case MSG_RESIZED:
2753 return "MSG_RESIZED";
2754 case MSG_RESIZED_REPORT:
2755 return "MSG_RESIZED_REPORT";
2756 case MSG_WINDOW_FOCUS_CHANGED:
2757 return "MSG_WINDOW_FOCUS_CHANGED";
2758 case MSG_DISPATCH_KEY:
2759 return "MSG_DISPATCH_KEY";
2760 case MSG_DISPATCH_APP_VISIBILITY:
2761 return "MSG_DISPATCH_APP_VISIBILITY";
2762 case MSG_DISPATCH_GET_NEW_SURFACE:
2763 return "MSG_DISPATCH_GET_NEW_SURFACE";
2764 case MSG_IME_FINISHED_EVENT:
2765 return "MSG_IME_FINISHED_EVENT";
2766 case MSG_DISPATCH_KEY_FROM_IME:
2767 return "MSG_DISPATCH_KEY_FROM_IME";
2768 case MSG_FINISH_INPUT_CONNECTION:
2769 return "MSG_FINISH_INPUT_CONNECTION";
2770 case MSG_CHECK_FOCUS:
2771 return "MSG_CHECK_FOCUS";
2772 case MSG_CLOSE_SYSTEM_DIALOGS:
2773 return "MSG_CLOSE_SYSTEM_DIALOGS";
2774 case MSG_DISPATCH_DRAG_EVENT:
2775 return "MSG_DISPATCH_DRAG_EVENT";
2776 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
2777 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
2778 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
2779 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
2780 case MSG_UPDATE_CONFIGURATION:
2781 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08002782 case MSG_PROCESS_INPUT_EVENTS:
2783 return "MSG_PROCESS_INPUT_EVENTS";
Romain Guy51e4d4d2012-03-15 18:30:47 -07002784 case MSG_DISPATCH_SCREEN_STATE:
2785 return "MSG_DISPATCH_SCREEN_STATE";
2786 case MSG_INVALIDATE_DISPLAY_LIST:
2787 return "MSG_INVALIDATE_DISPLAY_LIST";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07002788 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
2789 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07002790 case MSG_DISPATCH_DONE_ANIMATING:
2791 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07002792 case MSG_WINDOW_MOVED:
2793 return "MSG_WINDOW_MOVED";
Jeff Browna175a5b2012-02-15 19:18:31 -08002794 }
2795 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07002796 }
Romain Guyf9284692011-07-13 18:46:21 -07002797
Jeff Browna175a5b2012-02-15 19:18:31 -08002798 @Override
2799 public void handleMessage(Message msg) {
2800 switch (msg.what) {
2801 case MSG_INVALIDATE:
2802 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002803 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08002804 case MSG_INVALIDATE_RECT:
2805 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
2806 info.target.invalidate(info.left, info.top, info.right, info.bottom);
2807 info.release();
2808 break;
2809 case MSG_IME_FINISHED_EVENT:
2810 handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
2811 break;
2812 case MSG_PROCESS_INPUT_EVENTS:
2813 mProcessInputEventsScheduled = false;
2814 doProcessInputEvents();
2815 break;
2816 case MSG_DISPATCH_APP_VISIBILITY:
2817 handleAppVisibility(msg.arg1 != 0);
2818 break;
2819 case MSG_DISPATCH_GET_NEW_SURFACE:
2820 handleGetNewSurface();
2821 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07002822 case MSG_RESIZED: {
2823 // Recycled in the fall through...
2824 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07002825 if (mWinFrame.equals(args.arg1)
2826 && mPendingContentInsets.equals(args.arg2)
2827 && mPendingVisibleInsets.equals(args.arg3)
2828 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002829 break;
Romain Guycdb86672010-03-18 18:54:50 -07002830 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07002831 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08002832 case MSG_RESIZED_REPORT:
2833 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07002834 SomeArgs args = (SomeArgs) msg.obj;
2835
2836 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08002837 if (config != null) {
2838 updateConfiguration(config, false);
2839 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07002840
2841 mWinFrame.set((Rect) args.arg1);
2842 mPendingContentInsets.set((Rect) args.arg2);
2843 mPendingVisibleInsets.set((Rect) args.arg3);
2844
2845 args.recycle();
2846
Jeff Browna175a5b2012-02-15 19:18:31 -08002847 if (msg.what == MSG_RESIZED_REPORT) {
2848 mReportNextDraw = true;
2849 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002850
Jeff Browna175a5b2012-02-15 19:18:31 -08002851 if (mView != null) {
2852 forceLayout(mView);
2853 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07002854
Jeff Browna175a5b2012-02-15 19:18:31 -08002855 requestLayout();
2856 }
2857 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07002858 case MSG_WINDOW_MOVED:
2859 if (mAdded) {
2860 final int w = mWinFrame.width();
2861 final int h = mWinFrame.height();
2862 final int l = msg.arg1;
2863 final int t = msg.arg2;
2864 mWinFrame.left = l;
2865 mWinFrame.right = l + w;
2866 mWinFrame.top = t;
2867 mWinFrame.bottom = t + h;
2868
2869 if (mView != null) {
2870 forceLayout(mView);
2871 }
2872 requestLayout();
2873 }
2874 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08002875 case MSG_WINDOW_FOCUS_CHANGED: {
2876 if (mAdded) {
2877 boolean hasWindowFocus = msg.arg1 != 0;
2878 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879
Jeff Browna175a5b2012-02-15 19:18:31 -08002880 profileRendering(hasWindowFocus);
2881
2882 if (hasWindowFocus) {
2883 boolean inTouchMode = msg.arg2 != 0;
2884 ensureTouchModeLocally(inTouchMode);
2885
2886 if (mAttachInfo.mHardwareRenderer != null &&
2887 mSurface != null && mSurface.isValid()) {
2888 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08002889 try {
Romain Guydfab3632012-10-03 14:53:25 -07002890 if (mAttachInfo.mHardwareRenderer.initializeIfNeeded(
2891 mWidth, mHeight, mHolder.getSurface())) {
2892 mFullRedrawNeeded = true;
2893 }
Jeff Browna175a5b2012-02-15 19:18:31 -08002894 } catch (Surface.OutOfResourcesException e) {
2895 Log.e(TAG, "OutOfResourcesException locking surface", e);
2896 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002897 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002898 Slog.w(TAG, "No processes killed for memory; killing self");
2899 Process.killProcess(Process.myPid());
2900 }
2901 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08002902 }
Jeff Browna175a5b2012-02-15 19:18:31 -08002903 // Retry in a bit.
2904 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
2905 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08002906 }
Dianne Hackborn64825172011-03-02 21:32:58 -08002907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 }
Romain Guy8506ab42009-06-11 17:35:47 -07002909
Jeff Browna175a5b2012-02-15 19:18:31 -08002910 mLastWasImTarget = WindowManager.LayoutParams
2911 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07002912
Jeff Browna175a5b2012-02-15 19:18:31 -08002913 InputMethodManager imm = InputMethodManager.peekInstance();
2914 if (mView != null) {
2915 if (hasWindowFocus && imm != null && mLastWasImTarget) {
2916 imm.startGettingWindowFocus(mView);
2917 }
2918 mAttachInfo.mKeyDispatchState.reset();
2919 mView.dispatchWindowFocusChanged(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002921
Jeff Browna175a5b2012-02-15 19:18:31 -08002922 // Note: must be done after the focus change callbacks,
2923 // so all of the view state is set up correctly.
2924 if (hasWindowFocus) {
2925 if (imm != null && mLastWasImTarget) {
2926 imm.onWindowFocus(mView, mView.findFocus(),
2927 mWindowAttributes.softInputMode,
2928 !mHasHadWindowFocus, mWindowAttributes.flags);
2929 }
2930 // Clear the forward bit. We can just do this directly, since
2931 // the window manager doesn't care about it.
2932 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08002934 ((WindowManager.LayoutParams)mView.getLayoutParams())
2935 .softInputMode &=
2936 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2937 mHasHadWindowFocus = true;
2938 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002939
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002940 setAccessibilityFocus(null, null);
Svetoslav Ganov1d74df22012-04-28 15:14:22 -07002941
Svetoslav Ganov42138042012-03-20 11:51:39 -07002942 if (mView != null && mAccessibilityManager.isEnabled()) {
2943 if (hasWindowFocus) {
2944 mView.sendAccessibilityEvent(
2945 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002946 }
Jeff Browna175a5b2012-02-15 19:18:31 -08002947 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002948 }
Jeff Browna175a5b2012-02-15 19:18:31 -08002949 } break;
2950 case MSG_DIE:
2951 doDie();
2952 break;
2953 case MSG_DISPATCH_KEY: {
2954 KeyEvent event = (KeyEvent)msg.obj;
2955 enqueueInputEvent(event, null, 0, true);
2956 } break;
2957 case MSG_DISPATCH_KEY_FROM_IME: {
2958 if (LOCAL_LOGV) Log.v(
2959 TAG, "Dispatching key "
2960 + msg.obj + " from IME to " + mView);
2961 KeyEvent event = (KeyEvent)msg.obj;
2962 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
2963 // The IME is trying to say this event is from the
2964 // system! Bad bad bad!
2965 //noinspection UnusedAssignment
2966 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
2967 }
2968 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
2969 } break;
2970 case MSG_FINISH_INPUT_CONNECTION: {
2971 InputMethodManager imm = InputMethodManager.peekInstance();
2972 if (imm != null) {
2973 imm.reportFinishInputConnection((InputConnection)msg.obj);
2974 }
2975 } break;
2976 case MSG_CHECK_FOCUS: {
2977 InputMethodManager imm = InputMethodManager.peekInstance();
2978 if (imm != null) {
2979 imm.checkFocus();
2980 }
2981 } break;
2982 case MSG_CLOSE_SYSTEM_DIALOGS: {
2983 if (mView != null) {
2984 mView.onCloseSystemDialogs((String)msg.obj);
2985 }
2986 } break;
2987 case MSG_DISPATCH_DRAG_EVENT:
2988 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
2989 DragEvent event = (DragEvent)msg.obj;
2990 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
2991 handleDragEvent(event);
2992 } break;
2993 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
2994 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
2995 } break;
2996 case MSG_UPDATE_CONFIGURATION: {
2997 Configuration config = (Configuration)msg.obj;
2998 if (config.isOtherSeqNewer(mLastConfiguration)) {
2999 config = mLastConfiguration;
3000 }
3001 updateConfiguration(config, false);
3002 } break;
Romain Guybb9908b2012-03-08 11:14:07 -08003003 case MSG_DISPATCH_SCREEN_STATE: {
Romain Guy7e4e5612012-03-05 14:37:29 -08003004 if (mView != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08003005 handleScreenStateChange(msg.arg1 == 1);
Romain Guy7e4e5612012-03-05 14:37:29 -08003006 }
3007 } break;
Romain Guy51e4d4d2012-03-15 18:30:47 -07003008 case MSG_INVALIDATE_DISPLAY_LIST: {
3009 invalidateDisplayLists();
3010 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003011 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003012 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003013 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003014 case MSG_DISPATCH_DONE_ANIMATING: {
3015 handleDispatchDoneAnimating();
3016 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003017 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003018 if (mView != null) {
3019 invalidateWorld(mView);
3020 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003021 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023 }
3024 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003025
Jeff Browna175a5b2012-02-15 19:18:31 -08003026 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003028 /**
3029 * Something in the current window tells us we need to change the touch mode. For
3030 * example, we are not in touch mode, and the user touches the screen.
3031 *
3032 * If the touch mode has changed, tell the window manager, and handle it locally.
3033 *
3034 * @param inTouchMode Whether we want to be in touch mode.
3035 * @return True if the touch mode changed and focus changed was changed as a result
3036 */
3037 boolean ensureTouchMode(boolean inTouchMode) {
3038 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3039 + "touch mode is " + mAttachInfo.mInTouchMode);
3040 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3041
3042 // tell the window manager
3043 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003044 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003045 } catch (RemoteException e) {
3046 throw new RuntimeException(e);
3047 }
3048
3049 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003050 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 }
3052
3053 /**
3054 * Ensure that the touch mode for this window is set, and if it is changing,
3055 * take the appropriate action.
3056 * @param inTouchMode Whether we want to be in touch mode.
3057 * @return True if the touch mode changed and focus changed was changed as a result
3058 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003059 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3061 + "touch mode is " + mAttachInfo.mInTouchMode);
3062
3063 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3064
3065 mAttachInfo.mInTouchMode = inTouchMode;
3066 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3067
Romain Guy2d4cff62010-04-09 15:39:00 -07003068 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 }
3070
3071 private boolean enterTouchMode() {
3072 if (mView != null) {
3073 if (mView.hasFocus()) {
3074 // note: not relying on mFocusedView here because this could
3075 // be when the window is first being added, and mFocused isn't
3076 // set yet.
3077 final View focused = mView.findFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003078 if (focused != null && !focused.isFocusableInTouchMode()) {
3079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003080 final ViewGroup ancestorToTakeFocus =
3081 findAncestorToTakeFocusInTouchMode(focused);
3082 if (ancestorToTakeFocus != null) {
3083 // there is an ancestor that wants focus after its descendants that
3084 // is focusable in touch mode.. give it focus
3085 return ancestorToTakeFocus.requestFocus();
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003086 } else {
3087 // nothing appropriate to have focus in touch mode, clear it out
3088 mView.unFocus();
3089 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
3090 mFocusedView = null;
3091 mOldFocusedView = null;
3092 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 }
3094 }
3095 }
3096 }
3097 return false;
3098 }
3099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 /**
3101 * Find an ancestor of focused that wants focus after its descendants and is
3102 * focusable in touch mode.
3103 * @param focused The currently focused view.
3104 * @return An appropriate view, or null if no such view exists.
3105 */
Romain Guya998dff2012-03-23 18:58:36 -07003106 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003107 ViewParent parent = focused.getParent();
3108 while (parent instanceof ViewGroup) {
3109 final ViewGroup vgParent = (ViewGroup) parent;
3110 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3111 && vgParent.isFocusableInTouchMode()) {
3112 return vgParent;
3113 }
3114 if (vgParent.isRootNamespace()) {
3115 return null;
3116 } else {
3117 parent = vgParent.getParent();
3118 }
3119 }
3120 return null;
3121 }
3122
3123 private boolean leaveTouchMode() {
3124 if (mView != null) {
3125 if (mView.hasFocus()) {
3126 // i learned the hard way to not trust mFocusedView :)
3127 mFocusedView = mView.findFocus();
3128 if (!(mFocusedView instanceof ViewGroup)) {
3129 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003130 return false;
3131 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003132 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3133 // some view group has focus, and doesn't prefer its children
3134 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003135 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003136 }
3137 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003138
3139 // find the best view to give focus to in this brave new non-touch-mode
3140 // world
3141 final View focused = focusSearch(null, View.FOCUS_DOWN);
3142 if (focused != null) {
3143 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 }
3145 }
3146 return false;
3147 }
3148
Jeff Brown4952dfd2011-11-30 19:23:22 -08003149 private void deliverInputEvent(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003150 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
3151 try {
3152 if (q.mEvent instanceof KeyEvent) {
3153 deliverKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003154 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003155 final int source = q.mEvent.getSource();
3156 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3157 deliverPointerEvent(q);
3158 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3159 deliverTrackballEvent(q);
3160 } else {
3161 deliverGenericMotionEvent(q);
3162 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003163 }
Jeff Brown481c1572012-03-09 14:41:15 -08003164 } finally {
3165 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003166 }
3167 }
3168
3169 private void deliverPointerEvent(QueuedInputEvent q) {
3170 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown7564d622011-07-14 19:14:22 -07003171 final boolean isTouchEvent = event.isTouchEvent();
Jeff Brown21bc5c92011-02-28 18:27:14 -08003172 if (mInputEventConsistencyVerifier != null) {
Jeff Brown7564d622011-07-14 19:14:22 -07003173 if (isTouchEvent) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08003174 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
3175 } else {
3176 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
3177 }
3178 }
3179
Jeff Brown3915bb82010-11-05 15:02:16 -07003180 // If there is no view, then the event will not be handled.
3181 if (mView == null || !mAdded) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003182 finishInputEvent(q, false);
Jeff Brown3915bb82010-11-05 15:02:16 -07003183 return;
3184 }
3185
3186 // Translate the pointer event for compatibility, if needed.
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003187 if (mTranslator != null) {
3188 mTranslator.translateEventInScreenToAppWindow(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189 }
3190
Jeff Brown7564d622011-07-14 19:14:22 -07003191 // Enter touch mode on down or scroll.
3192 final int action = event.getAction();
3193 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
Jeff Brown3915bb82010-11-05 15:02:16 -07003194 ensureTouchMode(true);
3195 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003196
Jeff Brown3915bb82010-11-05 15:02:16 -07003197 // Offset the scroll position.
3198 if (mCurScrollY != 0) {
3199 event.offsetLocation(0, mCurScrollY);
3200 }
3201 if (MEASURE_LATENCY) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08003202 lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
Jeff Brown3915bb82010-11-05 15:02:16 -07003203 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003204
Jeff Brown3915bb82010-11-05 15:02:16 -07003205 // Remember the touch position for possible drag-initiation.
Jeff Brown7564d622011-07-14 19:14:22 -07003206 if (isTouchEvent) {
3207 mLastTouchPoint.x = event.getRawX();
3208 mLastTouchPoint.y = event.getRawY();
3209 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003210
3211 // Dispatch touch to view hierarchy.
Jeff Brown33bbfd22011-02-24 20:55:35 -08003212 boolean handled = mView.dispatchPointerEvent(event);
Jeff Brown3915bb82010-11-05 15:02:16 -07003213 if (MEASURE_LATENCY) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08003214 lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
Jeff Brown3915bb82010-11-05 15:02:16 -07003215 }
3216 if (handled) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003217 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003218 return;
3219 }
3220
Jeff Brown3915bb82010-11-05 15:02:16 -07003221 // Pointer event was unhandled.
Jeff Brown4952dfd2011-11-30 19:23:22 -08003222 finishInputEvent(q, false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003223 }
3224
Jeff Brown4952dfd2011-11-30 19:23:22 -08003225 private void deliverTrackballEvent(QueuedInputEvent q) {
3226 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003227 if (mInputEventConsistencyVerifier != null) {
3228 mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
3229 }
3230
Victoria Leaseb38070c2012-08-24 13:46:02 -07003231 if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
3232 if (LOCAL_LOGV)
3233 Log.v(TAG, "Dispatching trackball " + event + " to " + mView);
3234
3235 // Dispatch to the IME before propagating down the view hierarchy.
3236 // The IME will eventually call back into handleImeFinishedEvent.
3237 if (mLastWasImTarget) {
3238 InputMethodManager imm = InputMethodManager.peekInstance();
3239 if (imm != null) {
3240 final int seq = event.getSequenceNumber();
3241 if (DEBUG_IMF)
3242 Log.v(TAG, "Sending trackball event to IME: seq="
3243 + seq + " event=" + event);
3244 imm.dispatchTrackballEvent(mView.getContext(), seq, event,
3245 mInputMethodCallback);
3246 return;
3247 }
3248 }
3249 }
3250
3251 // Not dispatching to IME, continue with post IME actions.
3252 deliverTrackballEventPostIme(q);
3253 }
3254
3255 private void deliverTrackballEventPostIme(QueuedInputEvent q) {
3256 final MotionEvent event = (MotionEvent) q.mEvent;
3257
Jeff Brown3915bb82010-11-05 15:02:16 -07003258 // If there is no view, then the event will not be handled.
3259 if (mView == null || !mAdded) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003260 finishInputEvent(q, false);
Jeff Brown3915bb82010-11-05 15:02:16 -07003261 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 }
3263
Jeff Brown3915bb82010-11-05 15:02:16 -07003264 // Deliver the trackball event to the view.
3265 if (mView.dispatchTrackballEvent(event)) {
3266 // If we reach this, we delivered a trackball event to mView and
3267 // mView consumed it. Because we will not translate the trackball
3268 // event into a key event, touch mode will not exit, so we exit
3269 // touch mode here.
3270 ensureTouchMode(false);
3271
Jeff Brown4952dfd2011-11-30 19:23:22 -08003272 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003273 mLastTrackballTime = Integer.MIN_VALUE;
3274 return;
3275 }
3276
3277 // Translate the trackball event into DPAD keys and try to deliver those.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 final TrackballAxis x = mTrackballAxisX;
3279 final TrackballAxis y = mTrackballAxisY;
3280
3281 long curTime = SystemClock.uptimeMillis();
Jeff Brown3915bb82010-11-05 15:02:16 -07003282 if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 // It has been too long since the last movement,
3284 // so restart at the beginning.
3285 x.reset(0);
3286 y.reset(0);
3287 mLastTrackballTime = curTime;
3288 }
3289
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003290 final int action = event.getAction();
Jeff Brown49ed71d2010-12-06 17:13:33 -08003291 final int metaState = event.getMetaState();
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003292 switch (action) {
3293 case MotionEvent.ACTION_DOWN:
3294 x.reset(2);
3295 y.reset(2);
Jeff Brownf9261d22012-02-03 13:49:15 -08003296 enqueueInputEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003297 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3298 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003299 InputDevice.SOURCE_KEYBOARD));
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003300 break;
3301 case MotionEvent.ACTION_UP:
3302 x.reset(2);
3303 y.reset(2);
Jeff Brownf9261d22012-02-03 13:49:15 -08003304 enqueueInputEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003305 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3306 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003307 InputDevice.SOURCE_KEYBOARD));
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003308 break;
3309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003311 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
3312 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
3313 + " move=" + event.getX()
3314 + " / Y=" + y.position + " step="
3315 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
3316 + " move=" + event.getY());
3317 final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
3318 final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003320 // Generate DPAD events based on the trackball movement.
3321 // We pick the axis that has moved the most as the direction of
3322 // the DPAD. When we generate DPAD events for one axis, then the
3323 // other axis is reset -- we don't want to perform DPAD jumps due
3324 // to slight movements in the trackball when making major movements
3325 // along the other axis.
3326 int keycode = 0;
3327 int movement = 0;
3328 float accel = 1;
3329 if (xOff > yOff) {
3330 movement = x.generate((2/event.getXPrecision()));
3331 if (movement != 0) {
3332 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
3333 : KeyEvent.KEYCODE_DPAD_LEFT;
3334 accel = x.acceleration;
3335 y.reset(2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003337 } else if (yOff > 0) {
3338 movement = y.generate((2/event.getYPrecision()));
3339 if (movement != 0) {
3340 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
3341 : KeyEvent.KEYCODE_DPAD_UP;
3342 accel = y.acceleration;
3343 x.reset(2);
3344 }
3345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003347 if (keycode != 0) {
3348 if (movement < 0) movement = -movement;
3349 int accelMovement = (int)(movement * accel);
3350 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
3351 + " accelMovement=" + accelMovement
3352 + " accel=" + accel);
3353 if (accelMovement > movement) {
3354 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
3355 + keycode);
3356 movement--;
Jeff Brown49ed71d2010-12-06 17:13:33 -08003357 int repeatCount = accelMovement - movement;
Jeff Brownf9261d22012-02-03 13:49:15 -08003358 enqueueInputEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003359 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
3360 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003361 InputDevice.SOURCE_KEYBOARD));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003363 while (movement > 0) {
3364 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
3365 + keycode);
3366 movement--;
3367 curTime = SystemClock.uptimeMillis();
Jeff Brownf9261d22012-02-03 13:49:15 -08003368 enqueueInputEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003369 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
3370 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003371 InputDevice.SOURCE_KEYBOARD));
Jeff Brownf9261d22012-02-03 13:49:15 -08003372 enqueueInputEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08003373 KeyEvent.ACTION_UP, keycode, 0, metaState,
3374 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003375 InputDevice.SOURCE_KEYBOARD));
3376 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003377 mLastTrackballTime = curTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003379
3380 // Unfortunately we can't tell whether the application consumed the keys, so
3381 // we always consider the trackball event handled.
Jeff Brown4952dfd2011-11-30 19:23:22 -08003382 finishInputEvent(q, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003383 }
3384
Jeff Brown4952dfd2011-11-30 19:23:22 -08003385 private void deliverGenericMotionEvent(QueuedInputEvent q) {
3386 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003387 if (mInputEventConsistencyVerifier != null) {
3388 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
3389 }
3390
Victoria Leaseb38070c2012-08-24 13:46:02 -07003391 if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
3392 if (LOCAL_LOGV)
3393 Log.v(TAG, "Dispatching generic motion " + event + " to " + mView);
3394
3395 // Dispatch to the IME before propagating down the view hierarchy.
3396 // The IME will eventually call back into handleImeFinishedEvent.
3397 if (mLastWasImTarget) {
3398 InputMethodManager imm = InputMethodManager.peekInstance();
3399 if (imm != null) {
3400 final int seq = event.getSequenceNumber();
3401 if (DEBUG_IMF)
3402 Log.v(TAG, "Sending generic motion event to IME: seq="
3403 + seq + " event=" + event);
3404 imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
3405 mInputMethodCallback);
3406 return;
3407 }
3408 }
3409 }
3410
3411 // Not dispatching to IME, continue with post IME actions.
3412 deliverGenericMotionEventPostIme(q);
3413 }
3414
3415 private void deliverGenericMotionEventPostIme(QueuedInputEvent q) {
3416 final MotionEvent event = (MotionEvent) q.mEvent;
3417 final boolean isJoystick = (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08003418
3419 // If there is no view, then the event will not be handled.
3420 if (mView == null || !mAdded) {
3421 if (isJoystick) {
3422 updateJoystickDirection(event, false);
3423 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003424 finishInputEvent(q, false);
Jeff Browncb1404e2011-01-15 18:14:15 -08003425 return;
3426 }
3427
3428 // Deliver the event to the view.
3429 if (mView.dispatchGenericMotionEvent(event)) {
Jeff Browncb1404e2011-01-15 18:14:15 -08003430 if (isJoystick) {
3431 updateJoystickDirection(event, false);
3432 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003433 finishInputEvent(q, true);
Jeff Browncb1404e2011-01-15 18:14:15 -08003434 return;
3435 }
3436
3437 if (isJoystick) {
Victoria Leaseb38070c2012-08-24 13:46:02 -07003438 // Translate the joystick event into DPAD keys and try to deliver
3439 // those.
Jeff Browncb1404e2011-01-15 18:14:15 -08003440 updateJoystickDirection(event, true);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003441 finishInputEvent(q, true);
Jeff Browncb1404e2011-01-15 18:14:15 -08003442 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003443 finishInputEvent(q, false);
Jeff Browncb1404e2011-01-15 18:14:15 -08003444 }
3445 }
3446
3447 private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) {
3448 final long time = event.getEventTime();
3449 final int metaState = event.getMetaState();
3450 final int deviceId = event.getDeviceId();
3451 final int source = event.getSource();
Jeff Brown6f2fba42011-02-19 01:08:02 -08003452
3453 int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
3454 if (xDirection == 0) {
3455 xDirection = joystickAxisValueToDirection(event.getX());
3456 }
3457
3458 int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
3459 if (yDirection == 0) {
3460 yDirection = joystickAxisValueToDirection(event.getY());
3461 }
Jeff Browncb1404e2011-01-15 18:14:15 -08003462
3463 if (xDirection != mLastJoystickXDirection) {
3464 if (mLastJoystickXKeyCode != 0) {
Jeff Brownf9261d22012-02-03 13:49:15 -08003465 enqueueInputEvent(new KeyEvent(time, time,
Jeff Browncb1404e2011-01-15 18:14:15 -08003466 KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003467 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Browncb1404e2011-01-15 18:14:15 -08003468 mLastJoystickXKeyCode = 0;
3469 }
3470
3471 mLastJoystickXDirection = xDirection;
3472
3473 if (xDirection != 0 && synthesizeNewKeys) {
3474 mLastJoystickXKeyCode = xDirection > 0
3475 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brownf9261d22012-02-03 13:49:15 -08003476 enqueueInputEvent(new KeyEvent(time, time,
Jeff Browncb1404e2011-01-15 18:14:15 -08003477 KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003478 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Browncb1404e2011-01-15 18:14:15 -08003479 }
3480 }
3481
3482 if (yDirection != mLastJoystickYDirection) {
3483 if (mLastJoystickYKeyCode != 0) {
Jeff Brownf9261d22012-02-03 13:49:15 -08003484 enqueueInputEvent(new KeyEvent(time, time,
Jeff Browncb1404e2011-01-15 18:14:15 -08003485 KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003486 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Browncb1404e2011-01-15 18:14:15 -08003487 mLastJoystickYKeyCode = 0;
3488 }
3489
3490 mLastJoystickYDirection = yDirection;
3491
3492 if (yDirection != 0 && synthesizeNewKeys) {
3493 mLastJoystickYKeyCode = yDirection > 0
3494 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brownf9261d22012-02-03 13:49:15 -08003495 enqueueInputEvent(new KeyEvent(time, time,
Jeff Browncb1404e2011-01-15 18:14:15 -08003496 KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
Jeff Brown4952dfd2011-11-30 19:23:22 -08003497 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Browncb1404e2011-01-15 18:14:15 -08003498 }
3499 }
3500 }
3501
3502 private static int joystickAxisValueToDirection(float value) {
3503 if (value >= 0.5f) {
3504 return 1;
3505 } else if (value <= -0.5f) {
3506 return -1;
3507 } else {
3508 return 0;
3509 }
3510 }
3511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003512 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003513 * Returns true if the key is used for keyboard navigation.
3514 * @param keyEvent The key event.
3515 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08003517 private static boolean isNavigationKey(KeyEvent keyEvent) {
3518 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 case KeyEvent.KEYCODE_DPAD_LEFT:
3520 case KeyEvent.KEYCODE_DPAD_RIGHT:
3521 case KeyEvent.KEYCODE_DPAD_UP:
3522 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08003523 case KeyEvent.KEYCODE_DPAD_CENTER:
3524 case KeyEvent.KEYCODE_PAGE_UP:
3525 case KeyEvent.KEYCODE_PAGE_DOWN:
3526 case KeyEvent.KEYCODE_MOVE_HOME:
3527 case KeyEvent.KEYCODE_MOVE_END:
3528 case KeyEvent.KEYCODE_TAB:
3529 case KeyEvent.KEYCODE_SPACE:
3530 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 return true;
3532 }
3533 return false;
3534 }
3535
3536 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003537 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08003539 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003540 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08003541 private static boolean isTypingKey(KeyEvent keyEvent) {
3542 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 }
3544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003546 * 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 -08003547 * @param event The key event.
3548 * @return Whether this key event should be consumed (meaning the act of
3549 * leaving touch mode alone is considered the event).
3550 */
3551 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003552 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 if (!mAttachInfo.mInTouchMode) {
3554 return false;
3555 }
3556
Jeff Brown4e6319b2010-12-13 10:36:51 -08003557 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
3558 final int action = event.getAction();
3559 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003560 return false;
3561 }
3562
Jeff Brown4e6319b2010-12-13 10:36:51 -08003563 // Don't leave touch mode if the IME told us not to.
3564 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
3565 return false;
3566 }
3567
3568 // If the key can be used for keyboard navigation then leave touch mode
3569 // and select a focused view if needed (in ensureTouchMode).
3570 // When a new focused view is selected, we consume the navigation key because
3571 // navigation doesn't make much sense unless a view already has focus so
3572 // the key's purpose is to set focus.
3573 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 return ensureTouchMode(false);
3575 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08003576
3577 // If the key can be used for typing then leave touch mode
3578 // and select a focused view if needed (in ensureTouchMode).
3579 // Always allow the view to process the typing key.
3580 if (isTypingKey(event)) {
3581 ensureTouchMode(false);
3582 return false;
3583 }
3584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 return false;
3586 }
3587
Jeff Brown4952dfd2011-11-30 19:23:22 -08003588 private void deliverKeyEvent(QueuedInputEvent q) {
3589 final KeyEvent event = (KeyEvent)q.mEvent;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003590 if (mInputEventConsistencyVerifier != null) {
3591 mInputEventConsistencyVerifier.onKeyEvent(event, 0);
3592 }
3593
Victoria Leaseb38070c2012-08-24 13:46:02 -07003594 if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003595 if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
3596
3597 // Perform predispatching before the IME.
3598 if (mView.dispatchKeyEventPreIme(event)) {
3599 finishInputEvent(q, true);
3600 return;
3601 }
3602
3603 // Dispatch to the IME before propagating down the view hierarchy.
3604 // The IME will eventually call back into handleImeFinishedEvent.
3605 if (mLastWasImTarget) {
3606 InputMethodManager imm = InputMethodManager.peekInstance();
3607 if (imm != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003608 final int seq = event.getSequenceNumber();
Jeff Brown4952dfd2011-11-30 19:23:22 -08003609 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
Jeff Brown32cbc38552011-12-01 14:01:49 -08003610 + seq + " event=" + event);
3611 imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003612 return;
3613 }
3614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003615 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003616
3617 // Not dispatching to IME, continue with post IME actions.
Jeff Brown4952dfd2011-11-30 19:23:22 -08003618 deliverKeyEventPostIme(q);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 }
3620
Jeff Brown4952dfd2011-11-30 19:23:22 -08003621 void handleImeFinishedEvent(int seq, boolean handled) {
3622 final QueuedInputEvent q = mCurrentInputEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08003623 if (q != null && q.mEvent.getSequenceNumber() == seq) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003624 if (DEBUG_IMF) {
3625 Log.v(TAG, "IME finished event: seq=" + seq
Victoria Leaseb38070c2012-08-24 13:46:02 -07003626 + " handled=" + handled + " event=" + q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003627 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003628 if (handled) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003629 finishInputEvent(q, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630 } else {
Victoria Leaseb38070c2012-08-24 13:46:02 -07003631 if (q.mEvent instanceof KeyEvent) {
Dianne Hackborn8d5e6f82012-09-11 13:52:45 -07003632 KeyEvent event = (KeyEvent)q.mEvent;
3633 if (event.getAction() != KeyEvent.ACTION_UP) {
3634 // If the window doesn't currently have input focus, then drop
3635 // this event. This could be an event that came back from the
3636 // IME dispatch but the window has lost focus in the meantime.
3637 if (!mAttachInfo.mHasWindowFocus) {
3638 Slog.w(TAG, "Dropping event due to no window focus: " + event);
3639 finishInputEvent(q, true);
3640 return;
3641 }
3642 }
Victoria Leaseb38070c2012-08-24 13:46:02 -07003643 deliverKeyEventPostIme(q);
3644 } else {
Dianne Hackborn8d5e6f82012-09-11 13:52:45 -07003645 MotionEvent event = (MotionEvent)q.mEvent;
3646 if (event.getAction() != MotionEvent.ACTION_CANCEL
3647 && event.getAction() != MotionEvent.ACTION_UP) {
3648 // If the window doesn't currently have input focus, then drop
3649 // this event. This could be an event that came back from the
3650 // IME dispatch but the window has lost focus in the meantime.
3651 if (!mAttachInfo.mHasWindowFocus) {
3652 Slog.w(TAG, "Dropping event due to no window focus: " + event);
3653 finishInputEvent(q, true);
3654 return;
3655 }
3656 }
Victoria Leaseb38070c2012-08-24 13:46:02 -07003657 final int source = q.mEvent.getSource();
3658 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3659 deliverTrackballEventPostIme(q);
3660 } else {
3661 deliverGenericMotionEventPostIme(q);
3662 }
3663 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003664 }
3665 } else {
3666 if (DEBUG_IMF) {
3667 Log.v(TAG, "IME finished event: seq=" + seq
3668 + " handled=" + handled + ", event not found!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 }
3670 }
3671 }
Romain Guy8506ab42009-06-11 17:35:47 -07003672
Jeff Brown4952dfd2011-11-30 19:23:22 -08003673 private void deliverKeyEventPostIme(QueuedInputEvent q) {
3674 final KeyEvent event = (KeyEvent)q.mEvent;
Jeff Brown4e91a182011-04-07 11:38:09 -07003675
Jeff Brown3915bb82010-11-05 15:02:16 -07003676 // If the view went away, then the event will not be handled.
3677 if (mView == null || !mAdded) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003678 finishInputEvent(q, false);
Jeff Brown3915bb82010-11-05 15:02:16 -07003679 return;
3680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003681
Jeff Brown3915bb82010-11-05 15:02:16 -07003682 // If the key's purpose is to exit touch mode then we consume it and consider it handled.
3683 if (checkForLeavingTouchModeAndConsume(event)) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003684 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003685 return;
3686 }
Romain Guy8506ab42009-06-11 17:35:47 -07003687
Jeff Brown90655042010-12-02 13:50:46 -08003688 // Make sure the fallback event policy sees all keys that will be delivered to the
3689 // view hierarchy.
3690 mFallbackEventHandler.preDispatchKeyEvent(event);
3691
Jeff Brown3915bb82010-11-05 15:02:16 -07003692 // Deliver the key to the view hierarchy.
3693 if (mView.dispatchKeyEvent(event)) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003694 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003695 return;
3696 }
Joe Onorato86f67862010-11-05 18:57:34 -07003697
Jeff Brownc1df9072010-12-21 16:38:50 -08003698 // If the Control modifier is held, try to interpret the key as a shortcut.
Jeff Brown7bedf242011-12-07 16:55:19 -08003699 if (event.getAction() == KeyEvent.ACTION_DOWN
Jeff Brownc1df9072010-12-21 16:38:50 -08003700 && event.isCtrlPressed()
Jeff Brown7bedf242011-12-07 16:55:19 -08003701 && event.getRepeatCount() == 0
Jeff Brownc1df9072010-12-21 16:38:50 -08003702 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3703 if (mView.dispatchKeyShortcutEvent(event)) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003704 finishInputEvent(q, true);
Jeff Brownc1df9072010-12-21 16:38:50 -08003705 return;
3706 }
3707 }
3708
Jeff Brown3915bb82010-11-05 15:02:16 -07003709 // Apply the fallback event policy.
3710 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003711 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003712 return;
3713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003714
Jeff Brown3915bb82010-11-05 15:02:16 -07003715 // Handle automatic focus changes.
3716 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3717 int direction = 0;
3718 switch (event.getKeyCode()) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003719 case KeyEvent.KEYCODE_DPAD_LEFT:
3720 if (event.hasNoModifiers()) {
3721 direction = View.FOCUS_LEFT;
3722 }
3723 break;
3724 case KeyEvent.KEYCODE_DPAD_RIGHT:
3725 if (event.hasNoModifiers()) {
3726 direction = View.FOCUS_RIGHT;
3727 }
3728 break;
3729 case KeyEvent.KEYCODE_DPAD_UP:
3730 if (event.hasNoModifiers()) {
3731 direction = View.FOCUS_UP;
3732 }
3733 break;
3734 case KeyEvent.KEYCODE_DPAD_DOWN:
3735 if (event.hasNoModifiers()) {
3736 direction = View.FOCUS_DOWN;
3737 }
3738 break;
3739 case KeyEvent.KEYCODE_TAB:
3740 if (event.hasNoModifiers()) {
3741 direction = View.FOCUS_FORWARD;
3742 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3743 direction = View.FOCUS_BACKWARD;
3744 }
3745 break;
Jeff Brown3915bb82010-11-05 15:02:16 -07003746 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003747 if (direction != 0) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003748 View focused = mView.findFocus();
Jeff Brown3915bb82010-11-05 15:02:16 -07003749 if (focused != null) {
3750 View v = focused.focusSearch(direction);
3751 if (v != null && v != focused) {
3752 // do the math the get the interesting rect
3753 // of previous focused into the coord system of
3754 // newly focused view
3755 focused.getFocusedRect(mTempRect);
3756 if (mView instanceof ViewGroup) {
3757 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3758 focused, mTempRect);
3759 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3760 v, mTempRect);
3761 }
3762 if (v.requestFocus(direction, mTempRect)) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003763 playSoundEffect(SoundEffectConstants
3764 .getContantForFocusDirection(direction));
Jeff Brown4952dfd2011-11-30 19:23:22 -08003765 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003766 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 }
3768 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003769
3770 // Give the focused view a last chance to handle the dpad key.
3771 if (mView.dispatchUnhandledMove(focused, direction)) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08003772 finishInputEvent(q, true);
Jeff Brown3915bb82010-11-05 15:02:16 -07003773 return;
3774 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 }
3776 }
Jeff Brown3915bb82010-11-05 15:02:16 -07003777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778
Jeff Brown3915bb82010-11-05 15:02:16 -07003779 // Key was unhandled.
Jeff Brown4952dfd2011-11-30 19:23:22 -08003780 finishInputEvent(q, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 }
3782
Christopher Tatea53146c2010-09-07 11:57:52 -07003783 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08003784 void setLocalDragState(Object obj) {
3785 mLocalDragState = obj;
3786 }
3787
Christopher Tatea53146c2010-09-07 11:57:52 -07003788 private void handleDragEvent(DragEvent event) {
3789 // From the root, only drag start/end/location are dispatched. entered/exited
3790 // are determined and dispatched by the viewgroup hierarchy, who then report
3791 // that back here for ultimate reporting back to the framework.
3792 if (mView != null && mAdded) {
3793 final int what = event.mAction;
3794
3795 if (what == DragEvent.ACTION_DRAG_EXITED) {
3796 // A direct EXITED event means that the window manager knows we've just crossed
3797 // a window boundary, so the current drag target within this one must have
3798 // just been exited. Send it the usual notifications and then we're done
3799 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07003800 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07003801 } else {
3802 // Cache the drag description when the operation starts, then fill it in
3803 // on subsequent calls as a convenience
3804 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07003805 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07003806 mDragDescription = event.mClipDescription;
3807 } else {
3808 event.mClipDescription = mDragDescription;
3809 }
3810
3811 // For events with a [screen] location, translate into window coordinates
3812 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
3813 mDragPoint.set(event.mX, event.mY);
3814 if (mTranslator != null) {
3815 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
3816 }
3817
3818 if (mCurScrollY != 0) {
3819 mDragPoint.offset(0, mCurScrollY);
3820 }
3821
3822 event.mX = mDragPoint.x;
3823 event.mY = mDragPoint.y;
3824 }
3825
3826 // Remember who the current drag target is pre-dispatch
3827 final View prevDragView = mCurrentDragView;
3828
3829 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07003830 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07003831
3832 // If we changed apparent drag target, tell the OS about it
3833 if (prevDragView != mCurrentDragView) {
3834 try {
3835 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07003836 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07003837 }
3838 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07003839 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07003840 }
3841 } catch (RemoteException e) {
3842 Slog.e(TAG, "Unable to note drag target change");
3843 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003844 }
Chris Tated4533f12010-10-19 15:15:08 -07003845
Christopher Tate407b4e92010-11-30 17:14:08 -08003846 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07003847 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08003848 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07003849 try {
3850 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07003851 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07003852 } catch (RemoteException e) {
3853 Log.e(TAG, "Unable to report drop result");
3854 }
3855 }
Christopher Tate407b4e92010-11-30 17:14:08 -08003856
3857 // When the drag operation ends, release any local state object
3858 // that may have been in use
3859 if (what == DragEvent.ACTION_DRAG_ENDED) {
3860 setLocalDragState(null);
3861 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003862 }
3863 }
3864 event.recycle();
3865 }
3866
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003867 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
3868 if (mSeq != args.seq) {
3869 // The sequence has changed, so we need to update our value and make
3870 // sure to do a traversal afterward so the window manager is given our
3871 // most recent data.
3872 mSeq = args.seq;
3873 mAttachInfo.mForceReportNewAttributes = true;
3874 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08003875 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003876 if (mView == null) return;
3877 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003878 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003879 }
Dianne Hackborncf675782012-05-10 15:07:24 -07003880 if (mAttachInfo != null) {
3881 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
3882 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
3883 mAttachInfo.mGlobalSystemUiVisibility = visibility;
3884 mView.dispatchSystemUiVisibilityChanged(visibility);
3885 }
3886 }
Joe Onorato664644d2011-01-23 17:53:23 -08003887 }
3888
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003889 public void handleDispatchDoneAnimating() {
3890 if (mWindowsAnimating) {
3891 mWindowsAnimating = false;
3892 if (!mDirty.isEmpty() || mIsAnimating) {
3893 scheduleTraversals();
3894 }
3895 }
3896 }
3897
Christopher Tate2c095f32010-10-04 14:13:40 -07003898 public void getLastTouchPoint(Point outLocation) {
3899 outLocation.x = (int) mLastTouchPoint.x;
3900 outLocation.y = (int) mLastTouchPoint.y;
3901 }
3902
Chris Tate9d1ab882010-11-02 15:55:39 -07003903 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07003904 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07003905 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07003906 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003907 }
3908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909 private AudioManager getAudioManager() {
3910 if (mView == null) {
3911 throw new IllegalStateException("getAudioManager called when there is no mView");
3912 }
3913 if (mAudioManager == null) {
3914 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
3915 }
3916 return mAudioManager;
3917 }
3918
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003919 public AccessibilityInteractionController getAccessibilityInteractionController() {
3920 if (mView == null) {
3921 throw new IllegalStateException("getAccessibilityInteractionController"
3922 + " called when there is no mView");
3923 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07003924 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07003925 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003926 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07003927 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003928 }
3929
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003930 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
3931 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003932
3933 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003934 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003935 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07003936 restore = true;
3937 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003938 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003939 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003940 if (params != null) {
3941 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003942 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003943 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07003944 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07003945 if (params != null && mOrigWindowType != params.type) {
3946 // For compatibility with old apps, don't crash here.
3947 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
3948 Slog.w(TAG, "Window type can not be changed after "
3949 + "the window is added; ignoring change of " + mView);
3950 params.type = mOrigWindowType;
3951 }
3952 }
Jeff Brown98365d72012-08-19 20:30:52 -07003953 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07003954 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08003955 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
3956 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07003957 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackborn85afd1b2012-05-13 13:31:06 -07003958 mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003959 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07003960 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003961 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07003962 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003963 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003964
3965 if (mTranslator != null) {
3966 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
3967 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
3968 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003969 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003970 return relayoutResult;
3971 }
Romain Guy8506ab42009-06-11 17:35:47 -07003972
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003973 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003974 * {@inheritDoc}
3975 */
3976 public void playSoundEffect(int effectId) {
3977 checkThread();
3978
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07003979 try {
3980 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003981
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07003982 switch (effectId) {
3983 case SoundEffectConstants.CLICK:
3984 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
3985 return;
3986 case SoundEffectConstants.NAVIGATION_DOWN:
3987 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
3988 return;
3989 case SoundEffectConstants.NAVIGATION_LEFT:
3990 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
3991 return;
3992 case SoundEffectConstants.NAVIGATION_RIGHT:
3993 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
3994 return;
3995 case SoundEffectConstants.NAVIGATION_UP:
3996 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
3997 return;
3998 default:
3999 throw new IllegalArgumentException("unknown effect id " + effectId +
4000 " not defined in " + SoundEffectConstants.class.getCanonicalName());
4001 }
4002 } catch (IllegalStateException e) {
4003 // Exception thrown by getAudioManager() when mView is null
4004 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
4005 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004006 }
4007 }
4008
4009 /**
4010 * {@inheritDoc}
4011 */
4012 public boolean performHapticFeedback(int effectId, boolean always) {
4013 try {
Jeff Brown98365d72012-08-19 20:30:52 -07004014 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004015 } catch (RemoteException e) {
4016 return false;
4017 }
4018 }
4019
4020 /**
4021 * {@inheritDoc}
4022 */
4023 public View focusSearch(View focused, int direction) {
4024 checkThread();
4025 if (!(mView instanceof ViewGroup)) {
4026 return null;
4027 }
4028 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
4029 }
4030
4031 public void debug() {
4032 mView.debug();
4033 }
Romain Guy65b345f2011-07-27 18:51:50 -07004034
Romain Guy211370f2012-02-01 16:10:55 -08004035 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07004036 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07004037 if (mView != null) {
4038 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07004039 }
4040 }
4041
Romain Guya998dff2012-03-23 18:58:36 -07004042 private static void getGfxInfo(View view, int[] info) {
Romain Guy65b345f2011-07-27 18:51:50 -07004043 DisplayList displayList = view.mDisplayList;
4044 info[0]++;
4045 if (displayList != null) {
4046 info[1] += displayList.getSize();
4047 }
4048
4049 if (view instanceof ViewGroup) {
4050 ViewGroup group = (ViewGroup) view;
4051
4052 int count = group.getChildCount();
4053 for (int i = 0; i < count; i++) {
4054 getGfxInfo(group.getChildAt(i), info);
4055 }
4056 }
4057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004058
4059 public void die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07004060 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
4061 // done by dispatchDetachedFromWindow will cause havoc on return.
4062 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07004063 doDie();
4064 } else {
Romain Guy1f59e5c2012-05-06 14:11:16 -07004065 if (!mIsDrawing) {
4066 destroyHardwareRenderer();
4067 } else {
4068 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
4069 " window=" + this + ", title=" + mWindowAttributes.getTitle());
4070 }
Jeff Browna175a5b2012-02-15 19:18:31 -08004071 mHandler.sendEmptyMessage(MSG_DIE);
Dianne Hackborn94d69142009-09-28 22:14:42 -07004072 }
4073 }
4074
4075 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004076 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07004077 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004078 synchronized (this) {
Romain Guy16260e72011-09-01 14:26:11 -07004079 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07004080 dispatchDetachedFromWindow();
4081 }
4082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004083 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07004084 destroyHardwareRenderer();
4085
Romain Guyedbca122012-04-04 18:25:53 -07004086 if (mView != null) {
4087 int viewVisibility = mView.getVisibility();
4088 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
4089 if (mWindowAttributesChanged || viewVisibilityChanged) {
4090 // If layout params have been changed, first give them
4091 // to the window manager to make sure it has the correct
4092 // animation info.
4093 try {
4094 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07004095 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
4096 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07004097 }
4098 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004100 }
Romain Guyedbca122012-04-04 18:25:53 -07004101
4102 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004104 }
Romain Guyedbca122012-04-04 18:25:53 -07004105
4106 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107 }
4108 }
4109
Dianne Hackborn5fd21692011-06-07 14:09:47 -07004110 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08004111 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
4112 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07004113 }
4114
Dianne Hackborna53de062012-05-08 18:53:51 -07004115 public void loadSystemProperties() {
4116 boolean layout = SystemProperties.getBoolean(
4117 View.DEBUG_LAYOUT_PROPERTY, false);
4118 if (layout != mAttachInfo.mDebugLayout) {
4119 mAttachInfo.mDebugLayout = layout;
4120 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
4121 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
4122 }
4123 }
4124 }
4125
Romain Guy29d89972010-09-22 16:10:57 -07004126 private void destroyHardwareRenderer() {
Romain Guya998dff2012-03-23 18:58:36 -07004127 AttachInfo attachInfo = mAttachInfo;
4128 HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
4129
4130 if (hardwareRenderer != null) {
4131 if (mView != null) {
4132 hardwareRenderer.destroyHardwareResources(mView);
4133 }
4134 hardwareRenderer.destroy(true);
4135 hardwareRenderer.setRequested(false);
4136
4137 attachInfo.mHardwareRenderer = null;
4138 attachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07004139 }
4140 }
4141
Jeff Brown4952dfd2011-11-30 19:23:22 -08004142 void dispatchImeFinishedEvent(int seq, boolean handled) {
Jeff Browna175a5b2012-02-15 19:18:31 -08004143 Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004144 msg.arg1 = seq;
4145 msg.arg2 = handled ? 1 : 0;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004146 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08004147 mHandler.sendMessage(msg);
4148 }
4149
4150 public void dispatchFinishInputConnection(InputConnection connection) {
4151 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
4152 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004153 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07004154
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004155 public void dispatchResized(Rect frame, Rect contentInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08004156 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004157 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
4158 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 + " visibleInsets=" + visibleInsets.toShortString()
4160 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004161 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07004162 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004163 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07004164 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07004165 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07004166 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004167 SomeArgs args = SomeArgs.obtain();
4168 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
4169 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
4170 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
4171 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
4172 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
4173 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08004174 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004175 }
Chet Haase1f4786b2011-11-02 10:51:52 -07004176
Craig Mautner5702d4d2012-06-30 14:10:16 -07004177 public void dispatchMoved(int newX, int newY) {
4178 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
4179 if (mTranslator != null) {
4180 PointF point = new PointF(newX, newY);
4181 mTranslator.translatePointInScreenToAppWindow(point);
4182 newX = (int) (point.x + 0.5);
4183 newY = (int) (point.y + 0.5);
4184 }
4185 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
4186 mHandler.sendMessage(msg);
4187 }
4188
Jeff Brown4952dfd2011-11-30 19:23:22 -08004189 /**
4190 * Represents a pending input event that is waiting in a queue.
4191 *
4192 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08004193 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08004194 * one input event to the application at a time and waits for the application
4195 * to finish handling it before delivering the next one.
4196 *
4197 * However, because the application or IME can synthesize and inject multiple
4198 * key events at a time without going through the input dispatcher, we end up
4199 * needing a queue on the application's side.
4200 */
4201 private static final class QueuedInputEvent {
Romain Guy211370f2012-02-01 16:10:55 -08004202 public static final int FLAG_DELIVER_POST_IME = 1;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004203
4204 public QueuedInputEvent mNext;
4205
4206 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08004207 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004208 public int mFlags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004209 }
4210
4211 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08004212 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08004213 QueuedInputEvent q = mQueuedInputEventPool;
4214 if (q != null) {
4215 mQueuedInputEventPoolSize -= 1;
4216 mQueuedInputEventPool = q.mNext;
4217 q.mNext = null;
4218 } else {
4219 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07004220 }
4221
Jeff Brown4952dfd2011-11-30 19:23:22 -08004222 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08004223 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004224 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004225 return q;
4226 }
4227
4228 private void recycleQueuedInputEvent(QueuedInputEvent q) {
4229 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08004230 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004231
4232 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
4233 mQueuedInputEventPoolSize += 1;
4234 q.mNext = mQueuedInputEventPool;
4235 mQueuedInputEventPool = q;
4236 }
4237 }
4238
Jeff Brownf9261d22012-02-03 13:49:15 -08004239 void enqueueInputEvent(InputEvent event) {
4240 enqueueInputEvent(event, null, 0, false);
4241 }
4242
Jeff Brown4952dfd2011-11-30 19:23:22 -08004243 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08004244 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08004245 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004246
Jeff Brown4952dfd2011-11-30 19:23:22 -08004247 // Always enqueue the input event in order, regardless of its time stamp.
4248 // We do this because the application or the IME may inject key events
4249 // in response to touch events and we want to ensure that the injected keys
4250 // are processed in the order they were received and we cannot trust that
4251 // the time stamp of injected events are monotonic.
4252 QueuedInputEvent last = mFirstPendingInputEvent;
4253 if (last == null) {
4254 mFirstPendingInputEvent = q;
4255 } else {
4256 while (last.mNext != null) {
4257 last = last.mNext;
4258 }
4259 last.mNext = q;
4260 }
4261
Jeff Brownf9261d22012-02-03 13:49:15 -08004262 if (processImmediately) {
4263 doProcessInputEvents();
4264 } else {
4265 scheduleProcessInputEvents();
4266 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08004267 }
4268
4269 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08004270 if (!mProcessInputEventsScheduled) {
4271 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004272 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
4273 msg.setAsynchronous(true);
4274 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004275 }
4276 }
4277
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004278 void doProcessInputEvents() {
Jeff Brown4952dfd2011-11-30 19:23:22 -08004279 while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) {
4280 QueuedInputEvent q = mFirstPendingInputEvent;
4281 mFirstPendingInputEvent = q.mNext;
4282 q.mNext = null;
4283 mCurrentInputEvent = q;
4284 deliverInputEvent(q);
4285 }
4286
4287 // We are done processing all input events that we can process right now
4288 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08004289 if (mProcessInputEventsScheduled) {
4290 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08004291 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004292 }
4293 }
4294
4295 private void finishInputEvent(QueuedInputEvent q, boolean handled) {
4296 if (q != mCurrentInputEvent) {
4297 throw new IllegalStateException("finished input event out of order");
4298 }
4299
Jeff Brown32cbc38552011-12-01 14:01:49 -08004300 if (q.mReceiver != null) {
4301 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08004302 } else {
4303 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08004304 }
4305
4306 recycleQueuedInputEvent(q);
4307
4308 mCurrentInputEvent = null;
4309 if (mFirstPendingInputEvent != null) {
4310 scheduleProcessInputEvents();
4311 }
4312 }
4313
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004314 void scheduleConsumeBatchedInput() {
4315 if (!mConsumeBatchedInputScheduled) {
4316 mConsumeBatchedInputScheduled = true;
4317 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
4318 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08004319 }
4320 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004321
4322 void unscheduleConsumeBatchedInput() {
4323 if (mConsumeBatchedInputScheduled) {
4324 mConsumeBatchedInputScheduled = false;
4325 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
4326 mConsumedBatchedInputRunnable, null);
4327 }
4328 }
4329
Jeff Brown771526c2012-04-27 15:13:25 -07004330 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004331 if (mConsumeBatchedInputScheduled) {
4332 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07004333 if (mInputEventReceiver != null) {
Jeff Brown771526c2012-04-27 15:13:25 -07004334 mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004335 }
Jeff Brown330314c2012-04-27 02:20:22 -07004336 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004337 }
4338 }
4339
4340 final class TraversalRunnable implements Runnable {
4341 @Override
4342 public void run() {
4343 doTraversal();
4344 }
4345 }
4346 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08004347
Jeff Brown32cbc38552011-12-01 14:01:49 -08004348 final class WindowInputEventReceiver extends InputEventReceiver {
4349 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
4350 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07004351 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08004352
4353 @Override
4354 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08004355 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08004356 }
Jeff Brown072ec962012-02-07 14:46:57 -08004357
4358 @Override
4359 public void onBatchedInputEventPending() {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004360 scheduleConsumeBatchedInput();
4361 }
4362
4363 @Override
4364 public void dispose() {
4365 unscheduleConsumeBatchedInput();
4366 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08004367 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08004368 }
4369 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004370
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004371 final class ConsumeBatchedInputRunnable implements Runnable {
4372 @Override
4373 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07004374 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004375 }
4376 }
4377 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
4378 new ConsumeBatchedInputRunnable();
4379 boolean mConsumeBatchedInputScheduled;
4380
Jeff Brown6cb7b462012-03-05 13:21:17 -08004381 final class InvalidateOnAnimationRunnable implements Runnable {
4382 private boolean mPosted;
4383 private ArrayList<View> mViews = new ArrayList<View>();
4384 private ArrayList<AttachInfo.InvalidateInfo> mViewRects =
4385 new ArrayList<AttachInfo.InvalidateInfo>();
4386 private View[] mTempViews;
4387 private AttachInfo.InvalidateInfo[] mTempViewRects;
4388
4389 public void addView(View view) {
4390 synchronized (this) {
4391 mViews.add(view);
4392 postIfNeededLocked();
4393 }
4394 }
4395
4396 public void addViewRect(AttachInfo.InvalidateInfo info) {
4397 synchronized (this) {
4398 mViewRects.add(info);
4399 postIfNeededLocked();
4400 }
4401 }
4402
4403 public void removeView(View view) {
4404 synchronized (this) {
4405 mViews.remove(view);
4406
4407 for (int i = mViewRects.size(); i-- > 0; ) {
4408 AttachInfo.InvalidateInfo info = mViewRects.get(i);
4409 if (info.target == view) {
4410 mViewRects.remove(i);
4411 info.release();
4412 }
4413 }
4414
4415 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004416 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08004417 mPosted = false;
4418 }
4419 }
4420 }
4421
4422 @Override
4423 public void run() {
4424 final int viewCount;
4425 final int viewRectCount;
4426 synchronized (this) {
4427 mPosted = false;
4428
4429 viewCount = mViews.size();
4430 if (viewCount != 0) {
4431 mTempViews = mViews.toArray(mTempViews != null
4432 ? mTempViews : new View[viewCount]);
4433 mViews.clear();
4434 }
4435
4436 viewRectCount = mViewRects.size();
4437 if (viewRectCount != 0) {
4438 mTempViewRects = mViewRects.toArray(mTempViewRects != null
4439 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
4440 mViewRects.clear();
4441 }
4442 }
4443
4444 for (int i = 0; i < viewCount; i++) {
4445 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07004446 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08004447 }
4448
4449 for (int i = 0; i < viewRectCount; i++) {
4450 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
4451 info.target.invalidate(info.left, info.top, info.right, info.bottom);
4452 info.release();
4453 }
4454 }
4455
4456 private void postIfNeededLocked() {
4457 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07004458 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08004459 mPosted = true;
4460 }
4461 }
4462 }
4463 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
4464 new InvalidateOnAnimationRunnable();
4465
Jeff Browna175a5b2012-02-15 19:18:31 -08004466 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
4467 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
4468 mHandler.sendMessageDelayed(msg, delayMilliseconds);
4469 }
4470
Jeff Browna175a5b2012-02-15 19:18:31 -08004471 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
4472 long delayMilliseconds) {
4473 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
4474 mHandler.sendMessageDelayed(msg, delayMilliseconds);
4475 }
4476
Jeff Brown6cb7b462012-03-05 13:21:17 -08004477 public void dispatchInvalidateOnAnimation(View view) {
4478 mInvalidateOnAnimationRunnable.addView(view);
4479 }
4480
4481 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
4482 mInvalidateOnAnimationRunnable.addViewRect(info);
4483 }
4484
Romain Guy2a0f2282012-05-08 14:43:12 -07004485 public void enqueueDisplayList(DisplayList displayList) {
Romain Guy51e4d4d2012-03-15 18:30:47 -07004486 mDisplayLists.add(displayList);
4487
4488 mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST);
4489 Message msg = mHandler.obtainMessage(MSG_INVALIDATE_DISPLAY_LIST);
4490 mHandler.sendMessage(msg);
4491 }
Romain Guy2a0f2282012-05-08 14:43:12 -07004492
4493 public void dequeueDisplayList(DisplayList displayList) {
4494 if (mDisplayLists.remove(displayList)) {
4495 displayList.invalidate();
4496 if (mDisplayLists.size() == 0) {
4497 mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST);
4498 }
4499 }
4500 }
4501
Jeff Brown6cb7b462012-03-05 13:21:17 -08004502 public void cancelInvalidate(View view) {
4503 mHandler.removeMessages(MSG_INVALIDATE, view);
4504 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
4505 // them to the pool
4506 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
4507 mInvalidateOnAnimationRunnable.removeView(view);
4508 }
4509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004510 public void dispatchKey(KeyEvent event) {
Jeff Browna175a5b2012-02-15 19:18:31 -08004511 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08004512 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08004513 mHandler.sendMessage(msg);
4514 }
4515
4516 public void dispatchKeyFromIme(KeyEvent event) {
4517 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08004518 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08004519 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08004520 }
4521
John Reckd6b10982012-04-19 18:01:35 -07004522 public void dispatchUnhandledKey(KeyEvent event) {
4523 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
4524 final KeyCharacterMap kcm = event.getKeyCharacterMap();
4525 final int keyCode = event.getKeyCode();
4526 final int metaState = event.getMetaState();
4527
Jeff Brownfd23e3e2012-05-09 13:34:28 -07004528 // Check for fallback actions specified by the key character map.
4529 KeyCharacterMap.FallbackAction fallbackAction =
4530 kcm.getFallbackAction(keyCode, metaState);
4531 if (fallbackAction != null) {
4532 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
4533 KeyEvent fallbackEvent = KeyEvent.obtain(
4534 event.getDownTime(), event.getEventTime(),
4535 event.getAction(), fallbackAction.keyCode,
4536 event.getRepeatCount(), fallbackAction.metaState,
4537 event.getDeviceId(), event.getScanCode(),
4538 flags, event.getSource(), null);
4539 fallbackAction.recycle();
4540
John Reckd6b10982012-04-19 18:01:35 -07004541 dispatchKey(fallbackEvent);
4542 }
4543 }
4544 }
4545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004546 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08004547 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004548 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08004549 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551
Romain Guybb9908b2012-03-08 11:14:07 -08004552 public void dispatchScreenStateChange(boolean on) {
4553 Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
Romain Guy7e4e5612012-03-05 14:37:29 -08004554 msg.arg1 = on ? 1 : 0;
4555 mHandler.sendMessage(msg);
4556 }
4557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08004559 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
4560 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004561 }
4562
4563 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
4564 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08004565 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004566 msg.arg1 = hasFocus ? 1 : 0;
4567 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08004568 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004569 }
4570
Dianne Hackbornffa42482009-09-23 22:20:11 -07004571 public void dispatchCloseSystemDialogs(String reason) {
4572 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08004573 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07004574 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08004575 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07004576 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004577
4578 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07004579 final int what;
4580 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08004581 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
4582 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07004583 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08004584 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07004585 }
Jeff Browna175a5b2012-02-15 19:18:31 -08004586 Message msg = mHandler.obtainMessage(what, event);
4587 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07004588 }
4589
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004590 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
4591 int localValue, int localChanges) {
4592 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
4593 args.seq = seq;
4594 args.globalVisibility = globalVisibility;
4595 args.localValue = localValue;
4596 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08004597 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
4598 }
4599
Dianne Hackborn12d3a942012-04-27 14:16:30 -07004600 public void dispatchDoneAnimating() {
4601 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
4602 }
4603
Jeff Browna175a5b2012-02-15 19:18:31 -08004604 public void dispatchCheckFocus() {
4605 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
4606 // This will result in a call to checkFocus() below.
4607 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
4608 }
Joe Onorato664644d2011-01-23 17:53:23 -08004609 }
4610
svetoslavganov75986cf2009-05-14 22:28:01 -07004611 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004612 * Post a callback to send a
4613 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07004614 * This event is send at most once every
4615 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004616 */
Svetoslav Ganov42138042012-03-20 11:51:39 -07004617 private void postSendWindowContentChangedCallback(View source) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07004618 if (mSendWindowContentChangedAccessibilityEvent == null) {
4619 mSendWindowContentChangedAccessibilityEvent =
4620 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004621 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07004622 View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource;
4623 if (oldSource == null) {
4624 mSendWindowContentChangedAccessibilityEvent.mSource = source;
Jeff Browna175a5b2012-02-15 19:18:31 -08004625 mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
Svetoslav Ganova0156172011-06-26 17:55:44 -07004626 ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
Svetoslav Ganov42138042012-03-20 11:51:39 -07004627 } else {
Romain Guyba6be8a2012-04-23 18:22:09 -07004628 mSendWindowContentChangedAccessibilityEvent.mSource =
4629 getCommonPredecessor(oldSource, source);
Svetoslav Ganova0156172011-06-26 17:55:44 -07004630 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004631 }
4632
4633 /**
4634 * Remove a posted callback to send a
4635 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
4636 */
4637 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07004638 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08004639 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07004640 }
4641 }
4642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 public boolean showContextMenuForChild(View originalView) {
4644 return false;
4645 }
4646
Adam Powell6e346362010-07-23 10:18:23 -07004647 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
4648 return null;
4649 }
4650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004651 public void createContextMenu(ContextMenu menu) {
4652 }
4653
4654 public void childDrawableStateChanged(View child) {
4655 }
4656
Svetoslav Ganov736c2752011-04-22 18:30:36 -07004657 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
4658 if (mView == null) {
4659 return false;
4660 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07004661 // Intercept accessibility focus events fired by virtual nodes to keep
4662 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07004663 final int eventType = event.getEventType();
4664 switch (eventType) {
4665 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07004666 final long sourceNodeId = event.getSourceNodeId();
4667 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
4668 sourceNodeId);
4669 View source = mView.findViewByAccessibilityId(accessibilityViewId);
4670 if (source != null) {
4671 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
4672 if (provider != null) {
4673 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
4674 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
4675 setAccessibilityFocus(source, node);
4676 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07004677 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07004678 } break;
4679 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07004680 final long sourceNodeId = event.getSourceNodeId();
4681 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
4682 sourceNodeId);
4683 View source = mView.findViewByAccessibilityId(accessibilityViewId);
4684 if (source != null) {
4685 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
4686 if (provider != null) {
4687 setAccessibilityFocus(null, null);
4688 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07004689 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07004690 } break;
4691 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004692 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07004693 return true;
4694 }
4695
Svetoslav Ganov42138042012-03-20 11:51:39 -07004696 @Override
4697 public void childAccessibilityStateChanged(View child) {
4698 postSendWindowContentChangedCallback(child);
4699 }
4700
4701 private View getCommonPredecessor(View first, View second) {
4702 if (mAttachInfo != null) {
4703 if (mTempHashSet == null) {
4704 mTempHashSet = new HashSet<View>();
4705 }
4706 HashSet<View> seen = mTempHashSet;
4707 seen.clear();
4708 View firstCurrent = first;
4709 while (firstCurrent != null) {
4710 seen.add(firstCurrent);
4711 ViewParent firstCurrentParent = firstCurrent.mParent;
4712 if (firstCurrentParent instanceof View) {
4713 firstCurrent = (View) firstCurrentParent;
4714 } else {
4715 firstCurrent = null;
4716 }
4717 }
4718 View secondCurrent = second;
4719 while (secondCurrent != null) {
4720 if (seen.contains(secondCurrent)) {
4721 seen.clear();
4722 return secondCurrent;
4723 }
4724 ViewParent secondCurrentParent = secondCurrent.mParent;
4725 if (secondCurrentParent instanceof View) {
4726 secondCurrent = (View) secondCurrentParent;
4727 } else {
4728 secondCurrent = null;
4729 }
4730 }
4731 seen.clear();
4732 }
4733 return null;
4734 }
4735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004736 void checkThread() {
4737 if (mThread != Thread.currentThread()) {
4738 throw new CalledFromWrongThreadException(
4739 "Only the original thread that created a view hierarchy can touch its views.");
4740 }
4741 }
4742
4743 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07004744 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004745 }
4746
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07004747 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
4748 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
4749 if (rectangle != null) {
4750 mTempRect.set(rectangle);
4751 mTempRect.offset(0, -mCurScrollY);
4752 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
4753 try {
4754 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
4755 } catch (RemoteException re) {
4756 /* ignore */
4757 }
4758 }
4759 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004760 }
Romain Guy8506ab42009-06-11 17:35:47 -07004761
Adam Powell539ee872012-02-03 19:00:49 -08004762 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
4763 // Do nothing.
4764 }
4765
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07004766 class TakenSurfaceHolder extends BaseSurfaceHolder {
4767 @Override
4768 public boolean onAllowLockCanvas() {
4769 return mDrawingAllowed;
4770 }
4771
4772 @Override
4773 public void onRelayoutContainer() {
4774 // Not currently interesting -- from changing between fixed and layout size.
4775 }
4776
4777 public void setFormat(int format) {
4778 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
4779 }
4780
4781 public void setType(int type) {
4782 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
4783 }
4784
4785 @Override
4786 public void onUpdateSurface() {
4787 // We take care of format and type changes on our own.
4788 throw new IllegalStateException("Shouldn't be here");
4789 }
4790
4791 public boolean isCreating() {
4792 return mIsCreating;
4793 }
4794
4795 @Override
4796 public void setFixedSize(int width, int height) {
4797 throw new UnsupportedOperationException(
4798 "Currently only support sizing from layout");
4799 }
4800
4801 public void setKeepScreenOn(boolean screenOn) {
4802 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
4803 }
4804 }
4805
Jeff Brown04ddf3c2012-06-14 03:57:49 -07004806 static final class InputMethodCallback implements InputMethodManager.FinishedEventCallback {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004807 private WeakReference<ViewRootImpl> mViewAncestor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004808
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004809 public InputMethodCallback(ViewRootImpl viewAncestor) {
4810 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004811 }
Romain Guy8506ab42009-06-11 17:35:47 -07004812
Jeff Brown04ddf3c2012-06-14 03:57:49 -07004813 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 public void finishedEvent(int seq, boolean handled) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004815 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004816 if (viewAncestor != null) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08004817 viewAncestor.dispatchImeFinishedEvent(seq, handled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004818 }
4819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004820 }
Romain Guy8506ab42009-06-11 17:35:47 -07004821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004822 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004823 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07004824 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004825
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004826 W(ViewRootImpl viewAncestor) {
4827 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07004828 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004829 }
4830
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004831 public void resized(Rect frame, Rect contentInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -07004832 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004833 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004834 if (viewAncestor != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004835 viewAncestor.dispatchResized(frame, contentInsets,
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07004836 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004837 }
4838 }
4839
Craig Mautner5702d4d2012-06-30 14:10:16 -07004840 @Override
4841 public void moved(int newX, int newY) {
4842 final ViewRootImpl viewAncestor = mViewAncestor.get();
4843 if (viewAncestor != null) {
4844 viewAncestor.dispatchMoved(newX, newY);
4845 }
4846 }
4847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004848 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004849 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004850 if (viewAncestor != null) {
4851 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004852 }
4853 }
4854
Romain Guybb9908b2012-03-08 11:14:07 -08004855 public void dispatchScreenState(boolean on) {
Romain Guy7e4e5612012-03-05 14:37:29 -08004856 final ViewRootImpl viewAncestor = mViewAncestor.get();
4857 if (viewAncestor != null) {
Romain Guybb9908b2012-03-08 11:14:07 -08004858 viewAncestor.dispatchScreenStateChange(on);
Romain Guy7e4e5612012-03-05 14:37:29 -08004859 }
4860 }
Romain Guybb9908b2012-03-08 11:14:07 -08004861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004862 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004863 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004864 if (viewAncestor != null) {
4865 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004866 }
4867 }
4868
4869 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004870 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004871 if (viewAncestor != null) {
4872 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873 }
4874 }
4875
4876 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004877 try {
4878 return ActivityManagerNative.getDefault().checkPermission(
4879 permission, Binder.getCallingPid(), Binder.getCallingUid());
4880 } catch (RemoteException e) {
4881 return PackageManager.PERMISSION_DENIED;
4882 }
4883 }
4884
4885 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004886 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004887 if (viewAncestor != null) {
4888 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004889 if (view != null) {
4890 if (checkCallingPermission(Manifest.permission.DUMP) !=
4891 PackageManager.PERMISSION_GRANTED) {
4892 throw new SecurityException("Insufficient permissions to invoke"
4893 + " executeCommand() from pid=" + Binder.getCallingPid()
4894 + ", uid=" + Binder.getCallingUid());
4895 }
4896
4897 OutputStream clientStream = null;
4898 try {
4899 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
4900 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
4901 } catch (IOException e) {
4902 e.printStackTrace();
4903 } finally {
4904 if (clientStream != null) {
4905 try {
4906 clientStream.close();
4907 } catch (IOException e) {
4908 e.printStackTrace();
4909 }
4910 }
4911 }
4912 }
4913 }
4914 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07004915
Dianne Hackbornffa42482009-09-23 22:20:11 -07004916 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004917 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004918 if (viewAncestor != null) {
4919 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07004920 }
4921 }
4922
Marco Nelissenbf6956b2009-11-09 15:21:13 -08004923 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
4924 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07004925 if (sync) {
4926 try {
Jeff Brown98365d72012-08-19 20:30:52 -07004927 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07004928 } catch (RemoteException e) {
4929 }
4930 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07004931 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004932
Dianne Hackborn75804932009-10-20 20:15:20 -07004933 public void dispatchWallpaperCommand(String action, int x, int y,
4934 int z, Bundle extras, boolean sync) {
4935 if (sync) {
4936 try {
Jeff Brown98365d72012-08-19 20:30:52 -07004937 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07004938 } catch (RemoteException e) {
4939 }
4940 }
4941 }
Christopher Tatea53146c2010-09-07 11:57:52 -07004942
4943 /* Drag/drop */
4944 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004945 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004946 if (viewAncestor != null) {
4947 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07004948 }
4949 }
Joe Onorato664644d2011-01-23 17:53:23 -08004950
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004951 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
4952 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07004953 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004954 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07004955 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
4956 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08004957 }
4958 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07004959
4960 public void doneAnimating() {
4961 final ViewRootImpl viewAncestor = mViewAncestor.get();
4962 if (viewAncestor != null) {
4963 viewAncestor.dispatchDoneAnimating();
4964 }
4965 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004966 }
4967
4968 /**
4969 * Maintains state information for a single trackball axis, generating
4970 * discrete (DPAD) movements based on raw trackball motion.
4971 */
4972 static final class TrackballAxis {
4973 /**
4974 * The maximum amount of acceleration we will apply.
4975 */
4976 static final float MAX_ACCELERATION = 20;
Romain Guy8506ab42009-06-11 17:35:47 -07004977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004978 /**
4979 * The maximum amount of time (in milliseconds) between events in order
4980 * for us to consider the user to be doing fast trackball movements,
4981 * and thus apply an acceleration.
4982 */
4983 static final long FAST_MOVE_TIME = 150;
Romain Guy8506ab42009-06-11 17:35:47 -07004984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004985 /**
4986 * Scaling factor to the time (in milliseconds) between events to how
4987 * much to multiple/divide the current acceleration. When movement
4988 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4989 * FAST_MOVE_TIME it divides it.
4990 */
4991 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
Romain Guy8506ab42009-06-11 17:35:47 -07004992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004993 float position;
4994 float absPosition;
4995 float acceleration = 1;
4996 long lastMoveTime = 0;
4997 int step;
4998 int dir;
4999 int nonAccelMovement;
5000
5001 void reset(int _step) {
5002 position = 0;
5003 acceleration = 1;
5004 lastMoveTime = 0;
5005 step = _step;
5006 dir = 0;
5007 }
5008
5009 /**
5010 * Add trackball movement into the state. If the direction of movement
5011 * has been reversed, the state is reset before adding the
5012 * movement (so that you don't have to compensate for any previously
5013 * collected movement before see the result of the movement in the
5014 * new direction).
5015 *
5016 * @return Returns the absolute value of the amount of movement
5017 * collected so far.
5018 */
5019 float collect(float off, long time, String axis) {
5020 long normTime;
5021 if (off > 0) {
5022 normTime = (long)(off * FAST_MOVE_TIME);
5023 if (dir < 0) {
5024 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
5025 position = 0;
5026 step = 0;
5027 acceleration = 1;
5028 lastMoveTime = 0;
5029 }
5030 dir = 1;
5031 } else if (off < 0) {
5032 normTime = (long)((-off) * FAST_MOVE_TIME);
5033 if (dir > 0) {
5034 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
5035 position = 0;
5036 step = 0;
5037 acceleration = 1;
5038 lastMoveTime = 0;
5039 }
5040 dir = -1;
5041 } else {
5042 normTime = 0;
5043 }
Romain Guy8506ab42009-06-11 17:35:47 -07005044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005045 // The number of milliseconds between each movement that is
5046 // considered "normal" and will not result in any acceleration
5047 // or deceleration, scaled by the offset we have here.
5048 if (normTime > 0) {
5049 long delta = time - lastMoveTime;
5050 lastMoveTime = time;
5051 float acc = acceleration;
5052 if (delta < normTime) {
5053 // The user is scrolling rapidly, so increase acceleration.
5054 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
5055 if (scale > 1) acc *= scale;
5056 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
5057 + off + " normTime=" + normTime + " delta=" + delta
5058 + " scale=" + scale + " acc=" + acc);
5059 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
5060 } else {
5061 // The user is scrolling slowly, so decrease acceleration.
5062 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
5063 if (scale > 1) acc /= scale;
5064 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
5065 + off + " normTime=" + normTime + " delta=" + delta
5066 + " scale=" + scale + " acc=" + acc);
5067 acceleration = acc > 1 ? acc : 1;
5068 }
5069 }
5070 position += off;
5071 return (absPosition = Math.abs(position));
5072 }
5073
5074 /**
5075 * Generate the number of discrete movement events appropriate for
5076 * the currently collected trackball movement.
5077 *
5078 * @param precision The minimum movement required to generate the
5079 * first discrete movement.
5080 *
5081 * @return Returns the number of discrete movements, either positive
5082 * or negative, or 0 if there is not enough trackball movement yet
5083 * for a discrete movement.
5084 */
5085 int generate(float precision) {
5086 int movement = 0;
5087 nonAccelMovement = 0;
5088 do {
5089 final int dir = position >= 0 ? 1 : -1;
5090 switch (step) {
5091 // If we are going to execute the first step, then we want
5092 // to do this as soon as possible instead of waiting for
5093 // a full movement, in order to make things look responsive.
5094 case 0:
5095 if (absPosition < precision) {
5096 return movement;
5097 }
5098 movement += dir;
5099 nonAccelMovement += dir;
5100 step = 1;
5101 break;
5102 // If we have generated the first movement, then we need
5103 // to wait for the second complete trackball motion before
5104 // generating the second discrete movement.
5105 case 1:
5106 if (absPosition < 2) {
5107 return movement;
5108 }
5109 movement += dir;
5110 nonAccelMovement += dir;
5111 position += dir > 0 ? -2 : 2;
5112 absPosition = Math.abs(position);
5113 step = 2;
5114 break;
5115 // After the first two, we generate discrete movements
5116 // consistently with the trackball, applying an acceleration
5117 // if the trackball is moving quickly. This is a simple
5118 // acceleration on top of what we already compute based
5119 // on how quickly the wheel is being turned, to apply
5120 // a longer increasing acceleration to continuous movement
5121 // in one direction.
5122 default:
5123 if (absPosition < 1) {
5124 return movement;
5125 }
5126 movement += dir;
5127 position += dir >= 0 ? -1 : 1;
5128 absPosition = Math.abs(position);
5129 float acc = acceleration;
5130 acc *= 1.1f;
5131 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
5132 break;
5133 }
5134 } while (true);
5135 }
5136 }
5137
5138 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
5139 public CalledFromWrongThreadException(String msg) {
5140 super(msg);
5141 }
5142 }
5143
5144 private SurfaceHolder mHolder = new SurfaceHolder() {
5145 // we only need a SurfaceHolder for opengl. it would be nice
5146 // to implement everything else though, especially the callback
5147 // support (opengl doesn't make use of it right now, but eventually
5148 // will).
5149 public Surface getSurface() {
5150 return mSurface;
5151 }
5152
5153 public boolean isCreating() {
5154 return false;
5155 }
5156
5157 public void addCallback(Callback callback) {
5158 }
5159
5160 public void removeCallback(Callback callback) {
5161 }
5162
5163 public void setFixedSize(int width, int height) {
5164 }
5165
5166 public void setSizeFromLayout() {
5167 }
5168
5169 public void setFormat(int format) {
5170 }
5171
5172 public void setType(int type) {
5173 }
5174
5175 public void setKeepScreenOn(boolean screenOn) {
5176 }
5177
5178 public Canvas lockCanvas() {
5179 return null;
5180 }
5181
5182 public Canvas lockCanvas(Rect dirty) {
5183 return null;
5184 }
5185
5186 public void unlockCanvasAndPost(Canvas canvas) {
5187 }
5188 public Rect getSurfaceFrame() {
5189 return null;
5190 }
5191 };
5192
5193 static RunQueue getRunQueue() {
5194 RunQueue rq = sRunQueues.get();
5195 if (rq != null) {
5196 return rq;
5197 }
5198 rq = new RunQueue();
5199 sRunQueues.set(rq);
5200 return rq;
5201 }
Romain Guy8506ab42009-06-11 17:35:47 -07005202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005203 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08005204 * The run queue is used to enqueue pending work from Views when no Handler is
5205 * attached. The work is executed during the next call to performTraversals on
5206 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005207 * @hide
5208 */
5209 static final class RunQueue {
5210 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
5211
5212 void post(Runnable action) {
5213 postDelayed(action, 0);
5214 }
5215
5216 void postDelayed(Runnable action, long delayMillis) {
5217 HandlerAction handlerAction = new HandlerAction();
5218 handlerAction.action = action;
5219 handlerAction.delay = delayMillis;
5220
5221 synchronized (mActions) {
5222 mActions.add(handlerAction);
5223 }
5224 }
5225
5226 void removeCallbacks(Runnable action) {
5227 final HandlerAction handlerAction = new HandlerAction();
5228 handlerAction.action = action;
5229
5230 synchronized (mActions) {
5231 final ArrayList<HandlerAction> actions = mActions;
5232
5233 while (actions.remove(handlerAction)) {
5234 // Keep going
5235 }
5236 }
5237 }
5238
5239 void executeActions(Handler handler) {
5240 synchronized (mActions) {
5241 final ArrayList<HandlerAction> actions = mActions;
5242 final int count = actions.size();
5243
5244 for (int i = 0; i < count; i++) {
5245 final HandlerAction handlerAction = actions.get(i);
5246 handler.postDelayed(handlerAction.action, handlerAction.delay);
5247 }
5248
Romain Guy15df6702009-08-17 20:17:30 -07005249 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005250 }
5251 }
5252
5253 private static class HandlerAction {
5254 Runnable action;
5255 long delay;
5256
5257 @Override
5258 public boolean equals(Object o) {
5259 if (this == o) return true;
5260 if (o == null || getClass() != o.getClass()) return false;
5261
5262 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005263 return !(action != null ? !action.equals(that.action) : that.action != null);
5264
5265 }
5266
5267 @Override
5268 public int hashCode() {
5269 int result = action != null ? action.hashCode() : 0;
5270 result = 31 * result + (int) (delay ^ (delay >>> 32));
5271 return result;
5272 }
5273 }
5274 }
5275
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005276 /**
5277 * Class for managing the accessibility interaction connection
5278 * based on the global accessibility state.
5279 */
5280 final class AccessibilityInteractionConnectionManager
5281 implements AccessibilityStateChangeListener {
5282 public void onAccessibilityStateChanged(boolean enabled) {
5283 if (enabled) {
5284 ensureConnection();
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08005285 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
5286 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
5287 View focusedView = mView.findFocus();
5288 if (focusedView != null && focusedView != mView) {
5289 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
5290 }
5291 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005292 } else {
5293 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07005294 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005295 }
5296 }
5297
5298 public void ensureConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08005299 if (mAttachInfo != null) {
5300 final boolean registered =
5301 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
5302 if (!registered) {
5303 mAttachInfo.mAccessibilityWindowId =
5304 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
5305 new AccessibilityInteractionConnection(ViewRootImpl.this));
5306 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005307 }
5308 }
5309
5310 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08005311 final boolean registered =
5312 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005313 if (registered) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08005314 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005315 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
5316 }
5317 }
5318 }
5319
5320 /**
5321 * This class is an interface this ViewAncestor provides to the
5322 * AccessibilityManagerService to the latter can interact with
5323 * the view hierarchy in this ViewAncestor.
5324 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07005325 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005326 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07005327 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005328
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07005329 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
5330 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005331 }
5332
Svetoslav Ganov42138042012-03-20 11:51:39 -07005333 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07005334 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005335 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov86783472012-06-06 21:12:20 -07005336 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07005337 ViewRootImpl viewRootImpl = mViewRootImpl.get();
5338 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07005339 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07005340 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005341 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005342 } else {
5343 // We cannot make the call and notify the caller so it does not wait.
5344 try {
5345 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
5346 } catch (RemoteException re) {
5347 /* best effort - ignore */
5348 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07005349 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005350 }
5351
Svetoslav Ganov42138042012-03-20 11:51:39 -07005352 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07005353 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07005354 Bundle arguments, int interactionId,
5355 IAccessibilityInteractionConnectionCallback callback, int flags,
5356 int interogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07005357 ViewRootImpl viewRootImpl = mViewRootImpl.get();
5358 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07005359 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07005360 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svetoslav Ganov42138042012-03-20 11:51:39 -07005361 interactionId, callback, flags, interogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005362 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005363 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005364 try {
5365 callback.setPerformAccessibilityActionResult(false, interactionId);
5366 } catch (RemoteException re) {
5367 /* best effort - ignore */
5368 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005369 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005370 }
5371
Svetoslav Ganov42138042012-03-20 11:51:39 -07005372 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005373 public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005374 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov86783472012-06-06 21:12:20 -07005375 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07005376 ViewRootImpl viewRootImpl = mViewRootImpl.get();
5377 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07005378 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005379 .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005380 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005381 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005382 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005383 try {
5384 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
5385 } catch (RemoteException re) {
5386 /* best effort - ignore */
5387 }
5388 }
5389 }
5390
Svetoslav Ganov42138042012-03-20 11:51:39 -07005391 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005392 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005393 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov86783472012-06-06 21:12:20 -07005394 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005395 ViewRootImpl viewRootImpl = mViewRootImpl.get();
5396 if (viewRootImpl != null && viewRootImpl.mView != null) {
5397 viewRootImpl.getAccessibilityInteractionController()
5398 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005399 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005400 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005401 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005402 try {
5403 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
5404 } catch (RemoteException re) {
5405 /* best effort - ignore */
5406 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005407 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005408 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005409
Svetoslav Ganov42138042012-03-20 11:51:39 -07005410 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005411 public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
Svetoslav Ganov86783472012-06-06 21:12:20 -07005412 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08005413 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005414 ViewRootImpl viewRootImpl = mViewRootImpl.get();
5415 if (viewRootImpl != null && viewRootImpl.mView != null) {
5416 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005417 .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
5418 flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07005419 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005420 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005421 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005422 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005423 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005424 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005425 }
5426 }
5427 }
5428
Svetoslav Ganov42138042012-03-20 11:51:39 -07005429 @Override
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005430 public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
Svetoslav Ganov42138042012-03-20 11:51:39 -07005431 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005432 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005433 ViewRootImpl viewRootImpl = mViewRootImpl.get();
5434 if (viewRootImpl != null && viewRootImpl.mView != null) {
5435 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07005436 .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
5437 callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07005438 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005439 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005440 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005441 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005442 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005443 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005444 }
5445 }
5446 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005447 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005448
Svetoslav Ganova0156172011-06-26 17:55:44 -07005449 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005450 public View mSource;
Svetoslav Ganova0156172011-06-26 17:55:44 -07005451
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07005452 public void run() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005453 if (mSource != null) {
5454 mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
5455 mSource.resetAccessibilityStateChanged();
5456 mSource = null;
Svetoslav Ganov79311c42012-01-17 20:24:26 -08005457 }
5458 }
5459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005460}