blob: 042095a14d6975d90e5af011dca9ae4d1e54ddf8 [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;
20import android.app.ActivityManagerNative;
21import android.content.ClipDescription;
22import android.content.ComponentCallbacks;
23import android.content.Context;
24import android.content.pm.PackageManager;
25import android.content.res.CompatibilityInfo;
26import android.content.res.Configuration;
27import android.content.res.Resources;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080028import android.graphics.Bitmap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.Canvas;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080030import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070032import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070033import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070034import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.graphics.Rect;
36import android.graphics.Region;
Romain Guy6b7bd242010-10-06 19:49:23 -070037import android.media.AudioManager;
38import android.os.Binder;
39import android.os.Bundle;
40import android.os.Debug;
41import android.os.Handler;
42import android.os.LatencyTimer;
43import android.os.Looper;
44import android.os.Message;
45import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070047import android.os.RemoteException;
48import android.os.ServiceManager;
49import android.os.SystemClock;
50import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.util.AndroidRuntimeException;
52import android.util.Config;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070053import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.util.EventLog;
Romain Guy6b7bd242010-10-06 19:49:23 -070055import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070056import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.util.SparseArray;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080058import android.util.TypedValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070060import android.view.accessibility.AccessibilityEvent;
61import android.view.accessibility.AccessibilityManager;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080062import android.view.animation.AccelerateDecelerateInterpolator;
63import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.view.inputmethod.InputConnection;
65import android.view.inputmethod.InputMethodManager;
66import android.widget.Scroller;
Joe Onorato86f67862010-11-05 18:57:34 -070067import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070068import com.android.internal.view.BaseSurfaceHolder;
69import com.android.internal.view.IInputMethodCallback;
70import com.android.internal.view.IInputMethodSession;
71import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import java.io.IOException;
74import java.io.OutputStream;
Romain Guy6b7bd242010-10-06 19:49:23 -070075import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import java.util.ArrayList;
77
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078/**
79 * The top of a view hierarchy, implementing the needed protocol between View
80 * and the WindowManager. This is for the most part an internal implementation
81 * detail of {@link WindowManagerImpl}.
82 *
83 * {@hide}
84 */
Romain Guy812ccbe2010-06-01 14:07:24 -070085@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Dianne Hackborn0f761d62010-11-30 22:06:10 -080086public final class ViewRoot extends Handler implements ViewParent,
87 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 private static final String TAG = "ViewRoot";
89 private static final boolean DBG = false;
Mike Reedfd716532009-10-12 14:42:56 -040090 private static final boolean SHOW_FPS = false;
Romain Guy812ccbe2010-06-01 14:07:24 -070091 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 /** @noinspection PointlessBooleanExpression*/
93 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
94 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080095 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
97 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
98 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
99 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700100 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private static final boolean WATCH_POINTER = false;
102
Michael Chan53071d62009-05-13 17:29:48 -0700103 private static final boolean MEASURE_LATENCY = false;
104 private static LatencyTimer lt;
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 /**
107 * Maximum time we allow the user to roll the trackball enough to generate
108 * a key event, before resetting the counters.
109 */
110 static final int MAX_TRACKBALL_DELAY = 250;
111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 static IWindowSession sWindowSession;
113
114 static final Object mStaticInit = new Object();
115 static boolean mInitialized = false;
116
117 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
118
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800119 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
120 static boolean sFirstDrawComplete = false;
121
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800122 static final ArrayList<ComponentCallbacks> sConfigCallbacks
123 = new ArrayList<ComponentCallbacks>();
124
Romain Guy8506ab42009-06-11 17:35:47 -0700125 private static int sDrawTime;
Romain Guy13922e02009-05-12 17:56:14 -0700126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 long mLastTrackballTime = 0;
128 final TrackballAxis mTrackballAxisX = new TrackballAxis();
129 final TrackballAxis mTrackballAxisY = new TrackballAxis();
130
131 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700132
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800133 final TypedValue mTmpValue = new TypedValue();
134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 final InputMethodCallback mInputMethodCallback;
136 final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
137 int mPendingEventSeq = 0;
Romain Guy8506ab42009-06-11 17:35:47 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 final Thread mThread;
140
141 final WindowLeaked mLocation;
142
143 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
144
145 final W mWindow;
146
147 View mView;
148 View mFocusedView;
149 View mRealFocusedView; // this is not set to null in touch mode
150 int mViewVisibility;
151 boolean mAppVisible = true;
152
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700153 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700154 BaseSurfaceHolder mSurfaceHolder;
155 boolean mIsCreating;
156 boolean mDrawingAllowed;
157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 final Region mTransparentRegion;
159 final Region mPreviousTransparentRegion;
160
161 int mWidth;
162 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800163 Rect mDirty;
164 final Rect mCurrentDirty = new Rect();
165 final Rect mPreviousDirty = new Rect();
Romain Guybb93d552009-03-24 21:04:15 -0700166 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700167
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700168 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
170 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700171 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700172 InputQueue.Callback mInputQueueCallback;
173 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700174 FallbackEventHandler mFallbackEventHandler;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 final Rect mTempRect; // used in the transaction to not thrash the heap.
177 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
179 boolean mTraversalScheduled;
180 boolean mWillDrawSoon;
181 boolean mLayoutRequested;
182 boolean mFirst;
183 boolean mReportNextDraw;
184 boolean mFullRedrawNeeded;
185 boolean mNewSurfaceNeeded;
186 boolean mHasHadWindowFocus;
187 boolean mLastWasImTarget;
188
189 boolean mWindowAttributesChanged = false;
190
191 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700192 // Surface can never be reassigned or cleared (use Surface.clear()).
193 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
195 boolean mAdded;
196 boolean mAddedTouchMode;
197
198 /*package*/ int mAddNesting;
199
200 // These are accessed by multiple threads.
201 final Rect mWinFrame; // frame given by window manager.
202
203 final Rect mPendingVisibleInsets = new Rect();
204 final Rect mPendingContentInsets = new Rect();
205 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
206 = new ViewTreeObserver.InternalInsetsInfo();
207
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700208 final Configuration mLastConfiguration = new Configuration();
209 final Configuration mPendingConfiguration = new Configuration();
210
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800211 class ResizedInfo {
212 Rect coveredInsets;
213 Rect visibleInsets;
214 Configuration newConfig;
215 }
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 boolean mScrollMayChange;
218 int mSoftInputMode;
219 View mLastScrolledFocus;
220 int mScrollY;
221 int mCurScrollY;
222 Scroller mScroller;
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800223 Bitmap mResizeBitmap;
224 long mResizeBitmapStartTime;
225 int mResizeBitmapDuration;
226 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Romain Guy8506ab42009-06-11 17:35:47 -0700227
Romain Guy8506ab42009-06-11 17:35:47 -0700228 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229
Christopher Tatea53146c2010-09-07 11:57:52 -0700230 /* Drag/drop */
231 ClipDescription mDragDescription;
232 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800233 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700234 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700235 final PointF mLastTouchPoint = new PointF();
Christopher Tatea53146c2010-09-07 11:57:52 -0700236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 /**
238 * see {@link #playSoundEffect(int)}
239 */
240 AudioManager mAudioManager;
241
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700242 private final int mDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700243
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700244 public static IWindowSession getWindowSession(Looper mainLooper) {
245 synchronized (mStaticInit) {
246 if (!mInitialized) {
247 try {
248 InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
249 sWindowSession = IWindowManager.Stub.asInterface(
250 ServiceManager.getService("window"))
251 .openSession(imm.getClient(), imm.getInputContext());
252 mInitialized = true;
253 } catch (RemoteException e) {
254 }
255 }
256 return sWindowSession;
257 }
258 }
259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 public ViewRoot(Context context) {
261 super();
262
Romain Guy812ccbe2010-06-01 14:07:24 -0700263 if (MEASURE_LATENCY) {
264 if (lt == null) {
265 lt = new LatencyTimer(100, 1000);
266 }
Michael Chan53071d62009-05-13 17:29:48 -0700267 }
268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 // Initialize the statics when this class is first instantiated. This is
270 // done here instead of in the static block because Zygote does not
271 // allow the spawning of threads.
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700272 getWindowSession(context.getMainLooper());
273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 mThread = Thread.currentThread();
275 mLocation = new WindowLeaked(null);
276 mLocation.fillInStackTrace();
277 mWidth = -1;
278 mHeight = -1;
279 mDirty = new Rect();
280 mTempRect = new Rect();
281 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700283 mWindow = new W(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 mInputMethodCallback = new InputMethodCallback(this);
285 mViewVisibility = View.GONE;
286 mTransparentRegion = new Region();
287 mPreviousTransparentRegion = new Region();
288 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 mAdded = false;
290 mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
291 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700292 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700293 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 }
295
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800296 public static void addFirstDrawHandler(Runnable callback) {
297 synchronized (sFirstDrawHandlers) {
298 if (!sFirstDrawComplete) {
299 sFirstDrawHandlers.add(callback);
300 }
301 }
302 }
303
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800304 public static void addConfigCallback(ComponentCallbacks callback) {
305 synchronized (sConfigCallbacks) {
306 sConfigCallbacks.add(callback);
307 }
308 }
309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 // FIXME for perf testing only
311 private boolean mProfile = false;
312
313 /**
314 * Call this to profile the next traversal call.
315 * FIXME for perf testing only. Remove eventually
316 */
317 public void profile() {
318 mProfile = true;
319 }
320
321 /**
322 * Indicates whether we are in touch mode. Calling this method triggers an IPC
323 * call and should be avoided whenever possible.
324 *
325 * @return True, if the device is in touch mode, false otherwise.
326 *
327 * @hide
328 */
329 static boolean isInTouchMode() {
330 if (mInitialized) {
331 try {
332 return sWindowSession.getInTouchMode();
333 } catch (RemoteException e) {
334 }
335 }
336 return false;
337 }
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 /**
340 * We have one child
341 */
Romain Guye4d01122010-06-16 18:44:05 -0700342 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 synchronized (this) {
344 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700345 mView = view;
Joe Onorato86f67862010-11-05 18:57:34 -0700346 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700347 mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700348 attrs = mWindowAttributes;
Romain Guye4d01122010-06-16 18:44:05 -0700349
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700350 if (view instanceof RootViewSurfaceTaker) {
351 mSurfaceHolderCallback =
352 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
353 if (mSurfaceHolderCallback != null) {
354 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700355 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700356 }
357 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800358
359 // If the application owns the surface, don't enable hardware acceleration
360 if (mSurfaceHolder == null) {
361 enableHardwareAcceleration(attrs);
362 }
363
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700364 Resources resources = mView.getContext().getResources();
365 CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700366 mTranslator = compatibilityInfo.getTranslator();
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700367
368 if (mTranslator != null || !compatibilityInfo.supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700369 mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(),
370 mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700371 }
372
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700373 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700374 if (mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700375 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700376 attrs.backup();
377 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700378 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700379 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
380
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700381 if (!compatibilityInfo.supportsScreen()) {
382 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
383 }
384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 mSoftInputMode = attrs.softInputMode;
386 mWindowAttributesChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700388 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700389 mAttachInfo.mApplicationScale =
390 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 if (panelParentView != null) {
392 mAttachInfo.mPanelParentWindowToken
393 = panelParentView.getApplicationWindowToken();
394 }
395 mAdded = true;
396 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 // Schedule the first layout -before- adding to the window
399 // manager, to make sure we do the relayout before receiving
400 // any other events from the system.
401 requestLayout();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700402 mInputChannel = new InputChannel();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 try {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700404 res = sWindowSession.add(mWindow, mWindowAttributes,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700405 getHostVisibility(), mAttachInfo.mContentInsets,
406 mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 } catch (RemoteException e) {
408 mAdded = false;
409 mView = null;
410 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700411 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700412 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 unscheduleTraversals();
414 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700415 } finally {
416 if (restore) {
417 attrs.restore();
418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700420
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700421 if (mTranslator != null) {
422 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 mPendingContentInsets.set(mAttachInfo.mContentInsets);
425 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800426 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 if (res < WindowManagerImpl.ADD_OKAY) {
428 mView = null;
429 mAttachInfo.mRootView = null;
430 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700431 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 unscheduleTraversals();
433 switch (res) {
434 case WindowManagerImpl.ADD_BAD_APP_TOKEN:
435 case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
436 throw new WindowManagerImpl.BadTokenException(
437 "Unable to add window -- token " + attrs.token
438 + " is not valid; is your activity running?");
439 case WindowManagerImpl.ADD_NOT_APP_TOKEN:
440 throw new WindowManagerImpl.BadTokenException(
441 "Unable to add window -- token " + attrs.token
442 + " is not for an application");
443 case WindowManagerImpl.ADD_APP_EXITING:
444 throw new WindowManagerImpl.BadTokenException(
445 "Unable to add window -- app for token " + attrs.token
446 + " is exiting");
447 case WindowManagerImpl.ADD_DUPLICATE_ADD:
448 throw new WindowManagerImpl.BadTokenException(
449 "Unable to add window -- window " + mWindow
450 + " has already been added");
451 case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
452 // Silently ignore -- we would have just removed it
453 // right away, anyway.
454 return;
455 case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
456 throw new WindowManagerImpl.BadTokenException(
457 "Unable to add window " + mWindow +
458 " -- another window of this type already exists");
459 case WindowManagerImpl.ADD_PERMISSION_DENIED:
460 throw new WindowManagerImpl.BadTokenException(
461 "Unable to add window " + mWindow +
462 " -- permission denied for this window type");
463 }
464 throw new RuntimeException(
465 "Unable to add window -- unknown error code " + res);
466 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700467
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700468 if (view instanceof RootViewSurfaceTaker) {
469 mInputQueueCallback =
470 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
471 }
472 if (mInputQueueCallback != null) {
473 mInputQueue = new InputQueue(mInputChannel);
474 mInputQueueCallback.onInputQueueCreated(mInputQueue);
475 } else {
476 InputQueue.registerInputChannel(mInputChannel, mInputHandler,
477 Looper.myQueue());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700478 }
479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 view.assignParent(this);
481 mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
482 mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
483 }
484 }
485 }
486
Romain Guy529b60a2010-08-03 18:05:47 -0700487 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800488 mAttachInfo.mHardwareAccelerated = false;
489 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800490
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800491 // Try to enable hardware acceleration if requested
492 if (attrs != null &&
493 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
494 // Only enable hardware acceleration if we are not in the system process
495 // The window manager creates ViewRoots to display animated preview windows
496 // of launching apps and we don't want those to be hardware accelerated
497 if (!HardwareRenderer.sRendererDisabled) {
Romain Guyff26a0c2011-01-20 11:35:46 -0800498 // Don't enable hardware acceleration when we're not on the main thread
499 if (Looper.getMainLooper() != Looper.myLooper()) {
500 Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
501 + "acceleration outside of the main thread, aborting");
502 return;
503 }
504
Romain Guye4d01122010-06-16 18:44:05 -0700505 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
Romain Guyb051e892010-09-28 19:09:36 -0700506 if (mAttachInfo.mHardwareRenderer != null) {
507 mAttachInfo.mHardwareRenderer.destroy(true);
Romain Guy4caa4ed2010-08-25 14:46:24 -0700508 }
Romain Guyb051e892010-09-28 19:09:36 -0700509 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800510 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
511 = mAttachInfo.mHardwareRenderer != null;
512 } else if (HardwareRenderer.isAvailable()) {
513 mAttachInfo.mHardwareAccelerationRequested = true;
Romain Guye4d01122010-06-16 18:44:05 -0700514 }
515 }
516 }
517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 public View getView() {
519 return mView;
520 }
521
522 final WindowLeaked getLocation() {
523 return mLocation;
524 }
525
526 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
527 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700528 int oldSoftInputMode = mWindowAttributes.softInputMode;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700529 // preserve compatible window flag if exists.
530 int compatibleWindowFlag =
531 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700533 mWindowAttributes.flags |= compatibleWindowFlag;
534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 if (newView) {
536 mSoftInputMode = attrs.softInputMode;
537 requestLayout();
538 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700539 // Don't lose the mode we last auto-computed.
540 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
541 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
542 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
543 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
544 | (oldSoftInputMode
545 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 mWindowAttributesChanged = true;
548 scheduleTraversals();
549 }
550 }
551
552 void handleAppVisibility(boolean visible) {
553 if (mAppVisible != visible) {
554 mAppVisible = visible;
555 scheduleTraversals();
556 }
557 }
558
559 void handleGetNewSurface() {
560 mNewSurfaceNeeded = true;
561 mFullRedrawNeeded = true;
562 scheduleTraversals();
563 }
564
565 /**
566 * {@inheritDoc}
567 */
568 public void requestLayout() {
569 checkThread();
570 mLayoutRequested = true;
571 scheduleTraversals();
572 }
573
574 /**
575 * {@inheritDoc}
576 */
577 public boolean isLayoutRequested() {
578 return mLayoutRequested;
579 }
580
581 public void invalidateChild(View child, Rect dirty) {
582 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700583 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Chet Haase70d4ba12010-10-06 09:46:45 -0700584 if (dirty == null) {
585 // Fast invalidation for GL-enabled applications; GL must redraw everything
586 invalidate();
587 return;
588 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700589 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700591 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700592 if (mCurScrollY != 0) {
Romain Guy1e095972009-07-07 11:22:45 -0700593 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700594 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700595 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700596 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700597 }
Romain Guy1e095972009-07-07 11:22:45 -0700598 if (mAttachInfo.mScalingRequired) {
599 dirty.inset(-1, -1);
600 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
Chet Haasedaf98e92011-01-10 14:10:36 -0800602 if (!mDirty.isEmpty() && !mDirty.contains(dirty)) {
Romain Guy7d695942010-12-01 17:22:29 -0800603 mAttachInfo.mIgnoreDirtyState = true;
604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 mDirty.union(dirty);
606 if (!mWillDrawSoon) {
607 scheduleTraversals();
608 }
609 }
Romain Guy0d9275e2010-10-26 14:22:30 -0700610
611 void invalidate() {
612 mDirty.set(0, 0, mWidth, mHeight);
613 scheduleTraversals();
614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615
616 public ViewParent getParent() {
617 return null;
618 }
619
620 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
621 invalidateChild(null, dirty);
622 return null;
623 }
624
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700625 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 if (child != mView) {
627 throw new RuntimeException("child is not mine, honest!");
628 }
629 // Note: don't apply scroll offset, because we want to know its
630 // visibility in the virtual canvas being given to the view hierarchy.
631 return r.intersect(0, 0, mWidth, mHeight);
632 }
633
634 public void bringChildToFront(View child) {
635 }
636
637 public void scheduleTraversals() {
638 if (!mTraversalScheduled) {
639 mTraversalScheduled = true;
640 sendEmptyMessage(DO_TRAVERSAL);
641 }
642 }
643
644 public void unscheduleTraversals() {
645 if (mTraversalScheduled) {
646 mTraversalScheduled = false;
647 removeMessages(DO_TRAVERSAL);
648 }
649 }
650
651 int getHostVisibility() {
652 return mAppVisible ? mView.getVisibility() : View.GONE;
653 }
Romain Guy8506ab42009-06-11 17:35:47 -0700654
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800655 void disposeResizeBitmap() {
656 if (mResizeBitmap != null) {
657 mResizeBitmap.recycle();
658 mResizeBitmap = null;
659 }
660 }
661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 private void performTraversals() {
663 // cache mView since it is used so much below...
664 final View host = mView;
665
666 if (DBG) {
667 System.out.println("======================================");
668 System.out.println("performTraversals");
669 host.debug();
670 }
671
672 if (host == null || !mAdded)
673 return;
674
675 mTraversalScheduled = false;
676 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800677 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 boolean fullRedrawNeeded = mFullRedrawNeeded;
679 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700680 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 WindowManager.LayoutParams lp = mWindowAttributes;
682
683 int desiredWindowWidth;
684 int desiredWindowHeight;
685 int childWidthMeasureSpec;
686 int childHeightMeasureSpec;
687
688 final View.AttachInfo attachInfo = mAttachInfo;
689
690 final int viewVisibility = getHostVisibility();
691 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
692 || mNewSurfaceNeeded;
693
694 WindowManager.LayoutParams params = null;
695 if (mWindowAttributesChanged) {
696 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700697 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 params = lp;
699 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700700 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 if (mFirst) {
702 fullRedrawNeeded = true;
703 mLayoutRequested = true;
704
Romain Guy8506ab42009-06-11 17:35:47 -0700705 DisplayMetrics packageMetrics =
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700706 mView.getContext().getResources().getDisplayMetrics();
707 desiredWindowWidth = packageMetrics.widthPixels;
708 desiredWindowHeight = packageMetrics.heightPixels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709
710 // For the very first time, tell the view hierarchy that it
711 // is attached to the window. Note that at this point the surface
712 // object is not initialized to its backing store, but soon it
713 // will be (assuming the window is visible).
714 attachInfo.mSurface = mSurface;
Romain Guyc5d55862011-01-21 19:01:46 -0800715 // We used to use the following condition to choose 32 bits drawing caches:
716 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
717 // However, windows are now always 32 bits by default, so choose 32 bits
718 attachInfo.mUse32BitDrawingCache = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 attachInfo.mHasWindowFocus = false;
720 attachInfo.mWindowVisibility = viewVisibility;
721 attachInfo.mRecomputeGlobalAttributes = false;
722 attachInfo.mKeepScreenOn = false;
Joe Onorato664644d2011-01-23 17:53:23 -0800723 attachInfo.mSystemUiVisibility = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700725 mLastConfiguration.setTo(host.getResources().getConfiguration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 host.dispatchAttachedToWindow(attachInfo, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -0700728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700730 desiredWindowWidth = frame.width();
731 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700733 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700734 "View " + host + " resized to: " + frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 fullRedrawNeeded = true;
736 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800737 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739 }
740
741 if (viewVisibilityChanged) {
742 attachInfo.mWindowVisibility = viewVisibility;
743 host.dispatchWindowVisibilityChanged(viewVisibility);
744 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guyb051e892010-09-28 19:09:36 -0700745 if (mAttachInfo.mHardwareRenderer != null) {
746 mAttachInfo.mHardwareRenderer.destroy(false);
Romain Guy4caa4ed2010-08-25 14:46:24 -0700747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
749 if (viewVisibility == View.GONE) {
750 // After making a window gone, we will count it as being
751 // shown for the first time the next time it gets focus.
752 mHasHadWindowFocus = false;
753 }
754 }
755
756 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -0700757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 if (mLayoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -0700759 // Execute enqueued actions on every layout in case a view that was detached
760 // enqueued an action after being detached
761 getRunQueue().executeActions(attachInfo.mHandler);
762
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800763 final Resources res = mView.getContext().getResources();
764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 if (mFirst) {
766 host.fitSystemWindows(mAttachInfo.mContentInsets);
767 // make sure touch mode code executes by setting cached value
768 // to opposite of the added touch mode.
769 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -0700770 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 } else {
772 if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800773 if (mWidth > 0 && mHeight > 0 &&
774 mSurface != null && mSurface.isValid() &&
775 mAttachInfo.mHardwareRenderer != null &&
776 mAttachInfo.mHardwareRenderer.isEnabled() &&
777 lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
778
779 disposeResizeBitmap();
780
781 boolean completed = false;
782 try {
783 mResizeBitmap = Bitmap.createBitmap(mWidth, mHeight,
784 Bitmap.Config.ARGB_8888);
785 mResizeBitmap.setHasAlpha(false);
786 Canvas canvas = new Canvas(mResizeBitmap);
Romain Guyf90f8172011-01-25 22:53:24 -0800787 canvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800788 int yoff;
789 final boolean scrolling = mScroller != null
790 && mScroller.computeScrollOffset();
791 if (scrolling) {
792 yoff = mScroller.getCurrY();
793 mScroller.abortAnimation();
794 } else {
795 yoff = mScrollY;
796 }
797 canvas.translate(0, -yoff);
798 if (mTranslator != null) {
799 mTranslator.translateCanvas(canvas);
800 }
801 canvas.setScreenDensity(mAttachInfo.mScalingRequired
802 ? DisplayMetrics.DENSITY_DEVICE : 0);
803 mView.draw(canvas);
804 mResizeBitmapStartTime = SystemClock.uptimeMillis();
805 mResizeBitmapDuration = mView.getResources().getInteger(
806 com.android.internal.R.integer.config_mediumAnimTime);
807 completed = true;
808 } catch (OutOfMemoryError e) {
809 Log.w(TAG, "Not enough memory for content change anim buffer", e);
810 } finally {
811 if (!completed) {
812 mResizeBitmap = null;
813 }
814 }
815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 mAttachInfo.mContentInsets.set(mPendingContentInsets);
817 host.fitSystemWindows(mAttachInfo.mContentInsets);
818 insetsChanged = true;
819 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
820 + mAttachInfo.mContentInsets);
821 }
822 if (!mAttachInfo.mVisibleInsets.equals(mPendingVisibleInsets)) {
823 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
824 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
825 + mAttachInfo.mVisibleInsets);
826 }
827 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
828 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800829 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800831 DisplayMetrics packageMetrics = res.getDisplayMetrics();
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700832 desiredWindowWidth = packageMetrics.widthPixels;
833 desiredWindowHeight = packageMetrics.heightPixels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
835 }
836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 // Ask host how big it wants to be
Jeff Brownc5ed5912010-07-14 18:48:53 -0700838 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 "Measuring " + host + " in display " + desiredWindowWidth
840 + "x" + desiredWindowHeight + "...");
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800841
842 boolean goodMeasure = false;
843 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
844 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
845 // On large screens, we don't want to allow dialogs to just
846 // stretch to fill the entire width of the screen to display
847 // one line of text. First try doing the layout at a smaller
848 // size to see if it will fit.
849 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
850 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
851 int baseSize = 0;
852 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
853 baseSize = (int)mTmpValue.getDimension(packageMetrics);
854 }
855 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800856 if (baseSize != 0 && desiredWindowWidth > baseSize) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800857 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
858 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
859 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
860 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
Dianne Hackborn189ee182010-12-02 21:48:53 -0800861 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
862 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800863 goodMeasure = true;
864 } else {
865 // Didn't fit in that size... try expanding a bit.
866 baseSize = (baseSize+desiredWindowWidth)/2;
867 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
868 + baseSize);
Dianne Hackborn189ee182010-12-02 21:48:53 -0800869 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800870 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
871 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
Dianne Hackborn189ee182010-12-02 21:48:53 -0800872 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
873 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800874 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
875 goodMeasure = true;
876 }
877 }
878 }
879 }
880
881 if (!goodMeasure) {
882 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
883 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
884 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Adam Powellaa0b92c2010-12-13 22:38:53 -0800885 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
886 windowSizeMayChange = true;
887 }
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889
890 if (DBG) {
891 System.out.println("======================================");
892 System.out.println("performTraversals -- after measure");
893 host.debug();
894 }
895 }
896
Romain Guy6e81e572011-01-25 12:52:58 -0800897 if (attachInfo.mRecomputeGlobalAttributes && host.mAttachInfo != null) {
Joe Onorato664644d2011-01-23 17:53:23 -0800898 //Log.i(TAG, "Computing view hierarchy attributes!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 attachInfo.mRecomputeGlobalAttributes = false;
Joe Onorato664644d2011-01-23 17:53:23 -0800900 boolean oldScreenOn = attachInfo.mKeepScreenOn;
901 int oldVis = attachInfo.mSystemUiVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 attachInfo.mKeepScreenOn = false;
Joe Onorato664644d2011-01-23 17:53:23 -0800903 attachInfo.mSystemUiVisibility = 0;
904 attachInfo.mHasSystemUiListeners = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 host.dispatchCollectViewAttributes(0);
Joe Onorato14782f72011-01-25 19:53:17 -0800906 if (attachInfo.mKeepScreenOn != oldScreenOn
907 || attachInfo.mSystemUiVisibility != oldVis
908 || attachInfo.mHasSystemUiListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 }
911 }
912
913 if (mFirst || attachInfo.mViewVisibilityChanged) {
914 attachInfo.mViewVisibilityChanged = false;
915 int resizeMode = mSoftInputMode &
916 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
917 // If we are in auto resize mode, then we need to determine
918 // what mode to use now.
919 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
920 final int N = attachInfo.mScrollContainers.size();
921 for (int i=0; i<N; i++) {
922 if (attachInfo.mScrollContainers.get(i).isShown()) {
923 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
924 }
925 }
926 if (resizeMode == 0) {
927 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
928 }
929 if ((lp.softInputMode &
930 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
931 lp.softInputMode = (lp.softInputMode &
932 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
933 resizeMode;
934 params = lp;
935 }
936 }
937 }
Romain Guy8506ab42009-06-11 17:35:47 -0700938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
940 if (!PixelFormat.formatHasAlpha(params.format)) {
941 params.format = PixelFormat.TRANSLUCENT;
942 }
943 }
944
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800945 boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -0800946 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -0700947 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
948 frame.width() < desiredWindowWidth && frame.width() != mWidth)
949 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
950 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951
952 final boolean computesInternalInsets =
953 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
Romain Guy812ccbe2010-06-01 14:07:24 -0700954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 boolean insetsPending = false;
956 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -0700957
958 if (mFirst || windowShouldResize || insetsChanged ||
959 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960
961 if (viewVisibility == View.VISIBLE) {
962 // If this window is giving internal insets to the window
963 // manager, and it is being added or changing its visibility,
964 // then we want to first give the window manager "fake"
965 // insets to cause it to effectively ignore the content of
966 // the window during layout. This avoids it briefly causing
967 // other windows to resize/move based on the raw frame of the
968 // window, waiting until we can finish laying out this window
969 // and get back to the window manager with the ultimately
970 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -0700971 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700974 if (mSurfaceHolder != null) {
975 mSurfaceHolder.mSurfaceLock.lock();
976 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700977 }
Romain Guy812ccbe2010-06-01 14:07:24 -0700978
Romain Guyc361da82010-10-25 15:29:10 -0700979 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 boolean contentInsetsChanged = false;
Romain Guy13922e02009-05-12 17:56:14 -0700981 boolean visibleInsetsChanged;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700982 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -0700983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 int fl = 0;
986 if (params != null) {
987 fl = params.flags;
988 if (attachInfo.mKeepScreenOn) {
989 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
990 }
Joe Onorato14782f72011-01-25 19:53:17 -0800991 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
992 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners
993 || params.subtreeSystemUiVisibility != 0
994 || params.systemUiVisibility != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700996 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -0800997 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
998 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700999 }
Romain Guy2a83f002011-01-18 18:28:21 -08001000
1001 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001002 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 if (params != null) {
1005 params.flags = fl;
1006 }
1007
1008 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
1009 + " content=" + mPendingContentInsets.toShortString()
1010 + " visible=" + mPendingVisibleInsets.toShortString()
1011 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001012
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001013 if (mPendingConfiguration.seq != 0) {
1014 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1015 + mPendingConfiguration);
1016 updateConfiguration(mPendingConfiguration, !mFirst);
1017 mPendingConfiguration.seq = 0;
1018 }
1019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 contentInsetsChanged = !mPendingContentInsets.equals(
1021 mAttachInfo.mContentInsets);
1022 visibleInsetsChanged = !mPendingVisibleInsets.equals(
1023 mAttachInfo.mVisibleInsets);
1024 if (contentInsetsChanged) {
1025 mAttachInfo.mContentInsets.set(mPendingContentInsets);
1026 host.fitSystemWindows(mAttachInfo.mContentInsets);
1027 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1028 + mAttachInfo.mContentInsets);
1029 }
1030 if (visibleInsetsChanged) {
1031 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1032 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1033 + mAttachInfo.mVisibleInsets);
1034 }
1035
1036 if (!hadSurface) {
1037 if (mSurface.isValid()) {
1038 // If we are creating a new surface, then we need to
1039 // completely redraw it. Also, when we get to the
1040 // point of drawing it we will hold off and schedule
1041 // a new traversal instead. This is so we can tell the
1042 // window manager about all of the windows being displayed
1043 // before actually drawing them, so it can display then
1044 // all at once.
1045 newSurface = true;
1046 fullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001047 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001048
Romain Guyb051e892010-09-28 19:09:36 -07001049 if (mAttachInfo.mHardwareRenderer != null) {
Romain Guyc361da82010-10-25 15:29:10 -07001050 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
1052 }
1053 } else if (!mSurface.isValid()) {
1054 // If the surface has been removed, then reset the scroll
1055 // positions.
1056 mLastScrolledFocus = null;
1057 mScrollY = mCurScrollY = 0;
1058 if (mScroller != null) {
1059 mScroller.abortAnimation();
1060 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001061 disposeResizeBitmap();
Romain Guy2a83f002011-01-18 18:28:21 -08001062 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1063 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Romain Guy7d7b5492011-01-24 16:33:45 -08001064 fullRedrawNeeded = true;
Romain Guy2a83f002011-01-18 18:28:21 -08001065 mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 }
1067 } catch (RemoteException e) {
1068 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001071 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072
1073 attachInfo.mWindowLeft = frame.left;
1074 attachInfo.mWindowTop = frame.top;
1075
1076 // !!FIXME!! This next section handles the case where we did not get the
1077 // window size we asked for. We should avoid this by getting a maximum size from
1078 // the window session beforehand.
1079 mWidth = frame.width();
1080 mHeight = frame.height();
1081
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001082 if (mSurfaceHolder != null) {
1083 // The app owns the surface; tell it about what is going on.
1084 if (mSurface.isValid()) {
1085 // XXX .copyFrom() doesn't work!
1086 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1087 mSurfaceHolder.mSurface = mSurface;
1088 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001089 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001090 mSurfaceHolder.mSurfaceLock.unlock();
1091 if (mSurface.isValid()) {
1092 if (!hadSurface) {
1093 mSurfaceHolder.ungetCallbacks();
1094
1095 mIsCreating = true;
1096 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1097 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1098 if (callbacks != null) {
1099 for (SurfaceHolder.Callback c : callbacks) {
1100 c.surfaceCreated(mSurfaceHolder);
1101 }
1102 }
1103 surfaceChanged = true;
1104 }
1105 if (surfaceChanged) {
1106 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1107 lp.format, mWidth, mHeight);
1108 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1109 if (callbacks != null) {
1110 for (SurfaceHolder.Callback c : callbacks) {
1111 c.surfaceChanged(mSurfaceHolder, lp.format,
1112 mWidth, mHeight);
1113 }
1114 }
1115 }
1116 mIsCreating = false;
1117 } else if (hadSurface) {
1118 mSurfaceHolder.ungetCallbacks();
1119 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1120 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1121 if (callbacks != null) {
1122 for (SurfaceHolder.Callback c : callbacks) {
1123 c.surfaceDestroyed(mSurfaceHolder);
1124 }
1125 }
1126 mSurfaceHolder.mSurfaceLock.lock();
1127 // Make surface invalid.
1128 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1129 mSurfaceHolder.mSurface = new Surface();
1130 mSurfaceHolder.mSurfaceLock.unlock();
1131 }
1132 }
Romain Guy53389bd2010-09-07 17:16:32 -07001133
Romain Guy6b5108b2011-01-04 16:11:10 -08001134 if (hwInitialized || ((windowShouldResize || params != null) &&
Romain Guydbf78bd2010-12-07 17:04:03 -08001135 mAttachInfo.mHardwareRenderer != null &&
1136 mAttachInfo.mHardwareRenderer.isEnabled())) {
Romain Guyb051e892010-09-28 19:09:36 -07001137 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 }
1139
1140 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Romain Guy2d4cff62010-04-09 15:39:00 -07001141 (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
Dianne Hackborn189ee182010-12-02 21:48:53 -08001142 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1143 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1145 childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
1146
1147 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
Dianne Hackborn189ee182010-12-02 21:48:53 -08001148 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 + " mHeight=" + mHeight
Dianne Hackbornff801ec2011-01-22 18:05:38 -08001150 + " measuredHeight=" + host.getMeasuredHeight()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 + " coveredInsetsChanged=" + contentInsetsChanged);
Romain Guy8506ab42009-06-11 17:35:47 -07001152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 // Ask host how big it wants to be
1154 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1155
1156 // Implementation of weights from WindowManager.LayoutParams
1157 // We just grow the dimensions as needed and re-measure if
1158 // needs be
Dianne Hackborn189ee182010-12-02 21:48:53 -08001159 int width = host.getMeasuredWidth();
1160 int height = host.getMeasuredHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 boolean measureAgain = false;
1162
1163 if (lp.horizontalWeight > 0.0f) {
1164 width += (int) ((mWidth - width) * lp.horizontalWeight);
1165 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1166 MeasureSpec.EXACTLY);
1167 measureAgain = true;
1168 }
1169 if (lp.verticalWeight > 0.0f) {
1170 height += (int) ((mHeight - height) * lp.verticalWeight);
1171 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1172 MeasureSpec.EXACTLY);
1173 measureAgain = true;
1174 }
1175
1176 if (measureAgain) {
1177 if (DEBUG_LAYOUT) Log.v(TAG,
1178 "And hey let's measure once more: width=" + width
1179 + " height=" + height);
1180 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1181 }
1182
1183 mLayoutRequested = true;
1184 }
1185 }
1186
1187 final boolean didLayout = mLayoutRequested;
1188 boolean triggerGlobalLayoutListener = didLayout
1189 || attachInfo.mRecomputeGlobalAttributes;
1190 if (didLayout) {
1191 mLayoutRequested = false;
1192 mScrollMayChange = true;
1193 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001194 TAG, "Laying out " + host + " to (" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08001195 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
Romain Guy13922e02009-05-12 17:56:14 -07001196 long startTime = 0L;
Romain Guy5429e1d2010-09-07 12:38:00 -07001197 if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 startTime = SystemClock.elapsedRealtime();
1199 }
Dianne Hackborn189ee182010-12-02 21:48:53 -08001200 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201
Romain Guy13922e02009-05-12 17:56:14 -07001202 if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
1203 if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
1204 throw new IllegalStateException("The view hierarchy is an inconsistent state,"
1205 + "please refer to the logs with the tag "
1206 + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
1207 }
1208 }
1209
Romain Guy5429e1d2010-09-07 12:38:00 -07001210 if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
1212 }
1213
1214 // By this point all views have been sized and positionned
1215 // We can compute the transparent area
1216
1217 if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
1218 // start out transparent
1219 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1220 host.getLocationInWindow(mTmpLocation);
1221 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1222 mTmpLocation[0] + host.mRight - host.mLeft,
1223 mTmpLocation[1] + host.mBottom - host.mTop);
1224
1225 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001226 if (mTranslator != null) {
1227 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1228 }
1229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1231 mPreviousTransparentRegion.set(mTransparentRegion);
1232 // reconfigure window manager
1233 try {
1234 sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
1235 } catch (RemoteException e) {
1236 }
1237 }
1238 }
1239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 if (DBG) {
1241 System.out.println("======================================");
1242 System.out.println("performTraversals -- after setFrame");
1243 host.debug();
1244 }
1245 }
1246
1247 if (triggerGlobalLayoutListener) {
1248 attachInfo.mRecomputeGlobalAttributes = false;
1249 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1250 }
1251
1252 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001253 // Clear the original insets.
1254 final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1255 insets.reset();
1256
1257 // Compute new insets in place.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001259
1260 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1262 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001263
1264 // Translate insets to screen coordinates if needed.
1265 final Rect contentInsets;
1266 final Rect visibleInsets;
1267 final Region touchableRegion;
1268 if (mTranslator != null) {
1269 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1270 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1271 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1272 } else {
1273 contentInsets = insets.contentInsets;
1274 visibleInsets = insets.visibleInsets;
1275 touchableRegion = insets.touchableRegion;
1276 }
1277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 try {
1279 sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001280 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 } catch (RemoteException e) {
1282 }
1283 }
1284 }
Romain Guy8506ab42009-06-11 17:35:47 -07001285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 if (mFirst) {
1287 // handle first focus request
1288 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1289 + mView.hasFocus());
1290 if (mView != null) {
1291 if (!mView.hasFocus()) {
1292 mView.requestFocus(View.FOCUS_FORWARD);
1293 mFocusedView = mRealFocusedView = mView.findFocus();
1294 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
1295 + mFocusedView);
1296 } else {
1297 mRealFocusedView = mView.findFocus();
1298 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
1299 + mRealFocusedView);
1300 }
1301 }
1302 }
1303
1304 mFirst = false;
1305 mWillDrawSoon = false;
1306 mNewSurfaceNeeded = false;
1307 mViewVisibility = viewVisibility;
1308
1309 if (mAttachInfo.mHasWindowFocus) {
1310 final boolean imTarget = WindowManager.LayoutParams
1311 .mayUseInputMethod(mWindowAttributes.flags);
1312 if (imTarget != mLastWasImTarget) {
1313 mLastWasImTarget = imTarget;
1314 InputMethodManager imm = InputMethodManager.peekInstance();
1315 if (imm != null && imTarget) {
1316 imm.startGettingWindowFocus(mView);
1317 imm.onWindowFocus(mView, mView.findFocus(),
1318 mWindowAttributes.softInputMode,
1319 !mHasHadWindowFocus, mWindowAttributes.flags);
1320 }
1321 }
1322 }
Romain Guy8506ab42009-06-11 17:35:47 -07001323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
1325
1326 if (!cancelDraw && !newSurface) {
1327 mFullRedrawNeeded = false;
1328 draw(fullRedrawNeeded);
1329
1330 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
1331 || mReportNextDraw) {
1332 if (LOCAL_LOGV) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001333 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 }
1335 mReportNextDraw = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001336 if (mSurfaceHolder != null && mSurface.isValid()) {
1337 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
1338 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1339 if (callbacks != null) {
1340 for (SurfaceHolder.Callback c : callbacks) {
1341 if (c instanceof SurfaceHolder.Callback2) {
1342 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
1343 mSurfaceHolder);
1344 }
1345 }
1346 }
1347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 try {
1349 sWindowSession.finishDrawing(mWindow);
1350 } catch (RemoteException e) {
1351 }
1352 }
1353 } else {
1354 // We were supposed to report when we are done drawing. Since we canceled the
1355 // draw, remember it here.
1356 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
1357 mReportNextDraw = true;
1358 }
1359 if (fullRedrawNeeded) {
1360 mFullRedrawNeeded = true;
1361 }
1362 // Try again
1363 scheduleTraversals();
1364 }
1365 }
1366
1367 public void requestTransparentRegion(View child) {
1368 // the test below should not fail unless someone is messing with us
1369 checkThread();
1370 if (mView == child) {
1371 mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
1372 // Need to make sure we re-evaluate the window attributes next
1373 // time around, to ensure the window has the correct format.
1374 mWindowAttributesChanged = true;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07001375 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 }
1377 }
1378
1379 /**
1380 * Figures out the measure spec for the root view in a window based on it's
1381 * layout params.
1382 *
1383 * @param windowSize
1384 * The available width or height of the window
1385 *
1386 * @param rootDimension
1387 * The layout params for one dimension (width or height) of the
1388 * window.
1389 *
1390 * @return The measure spec to use to measure the root view.
1391 */
1392 private int getRootMeasureSpec(int windowSize, int rootDimension) {
1393 int measureSpec;
1394 switch (rootDimension) {
1395
Romain Guy980a9382010-01-08 15:06:28 -08001396 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 // Window can't resize. Force root view to be windowSize.
1398 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
1399 break;
1400 case ViewGroup.LayoutParams.WRAP_CONTENT:
1401 // Window can resize. Set max size for root view.
1402 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
1403 break;
1404 default:
1405 // Window wants to be an exact size. Force root view to be that size.
1406 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
1407 break;
1408 }
1409 return measureSpec;
1410 }
1411
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001412 int mHardwareYOffset;
1413 int mResizeAlpha;
1414 final Paint mResizePaint = new Paint();
1415
1416 public void onHardwarePreDraw(Canvas canvas) {
1417 canvas.translate(0, -mHardwareYOffset);
1418 }
1419
1420 public void onHardwarePostDraw(Canvas canvas) {
1421 if (mResizeBitmap != null) {
1422 canvas.translate(0, mHardwareYOffset);
1423 mResizePaint.setAlpha(mResizeAlpha);
1424 canvas.drawBitmap(mResizeBitmap, 0, 0, mResizePaint);
1425 }
1426 }
1427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 private void draw(boolean fullRedrawNeeded) {
1429 Surface surface = mSurface;
1430 if (surface == null || !surface.isValid()) {
1431 return;
1432 }
1433
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08001434 if (!sFirstDrawComplete) {
1435 synchronized (sFirstDrawHandlers) {
1436 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07001437 final int count = sFirstDrawHandlers.size();
1438 for (int i = 0; i< count; i++) {
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08001439 post(sFirstDrawHandlers.get(i));
1440 }
1441 }
1442 }
1443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 scrollToRectOrFocus(null, false);
1445
1446 if (mAttachInfo.mViewScrollChanged) {
1447 mAttachInfo.mViewScrollChanged = false;
1448 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
1449 }
Romain Guy8506ab42009-06-11 17:35:47 -07001450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 int yoff;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001452 boolean animating = mScroller != null && mScroller.computeScrollOffset();
1453 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 yoff = mScroller.getCurrY();
1455 } else {
1456 yoff = mScrollY;
1457 }
1458 if (mCurScrollY != yoff) {
1459 mCurScrollY = yoff;
1460 fullRedrawNeeded = true;
1461 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001462 float appScale = mAttachInfo.mApplicationScale;
1463 boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001465 int resizeAlpha = 0;
1466 if (mResizeBitmap != null) {
1467 long deltaTime = SystemClock.uptimeMillis() - mResizeBitmapStartTime;
1468 if (deltaTime < mResizeBitmapDuration) {
1469 float amt = deltaTime/(float)mResizeBitmapDuration;
1470 amt = mResizeInterpolator.getInterpolation(amt);
1471 animating = true;
1472 resizeAlpha = 255 - (int)(amt*255);
1473 } else {
1474 disposeResizeBitmap();
1475 }
1476 }
1477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001479 if (mSurfaceHolder != null) {
1480 // The app owns the surface, we won't draw.
1481 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001482 if (animating) {
1483 if (mScroller != null) {
1484 mScroller.abortAnimation();
1485 }
1486 disposeResizeBitmap();
1487 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001488 return;
1489 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07001490
1491 if (fullRedrawNeeded) {
1492 mAttachInfo.mIgnoreDirtyState = true;
1493 dirty.union(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
1494 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001495
Romain Guyb051e892010-09-28 19:09:36 -07001496 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guyfd507262010-10-10 15:42:49 -07001497 if (!dirty.isEmpty() || mIsAnimating) {
Romain Guy101e2ae2010-10-11 12:41:21 -07001498 mIsAnimating = false;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001499 mHardwareYOffset = yoff;
1500 mResizeAlpha = resizeAlpha;
Romain Guy7d7b5492011-01-24 16:33:45 -08001501
1502 mCurrentDirty.set(dirty);
1503 mCurrentDirty.union(mPreviousDirty);
1504 mPreviousDirty.set(dirty);
1505 dirty.setEmpty();
1506
Romain Guyf90f8172011-01-25 22:53:24 -08001507 Rect currentDirty = mCurrentDirty;
1508 if (animating) {
1509 currentDirty = null;
1510 }
1511
1512 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001514
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001515 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 mFullRedrawNeeded = true;
1517 scheduleTraversals();
1518 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 return;
1521 }
1522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001524 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 + mWindowAttributes.getTitle()
1526 + ": dirty={" + dirty.left + "," + dirty.top
1527 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001528 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
1529 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001532 if (!dirty.isEmpty() || mIsAnimating) {
1533 Canvas canvas;
1534 try {
1535 int left = dirty.left;
1536 int top = dirty.top;
1537 int right = dirty.right;
1538 int bottom = dirty.bottom;
1539 canvas = surface.lockCanvas(dirty);
Romain Guy5bcdff42009-05-14 21:27:18 -07001540
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001541 if (left != dirty.left || top != dirty.top || right != dirty.right ||
1542 bottom != dirty.bottom) {
1543 mAttachInfo.mIgnoreDirtyState = true;
1544 }
1545
1546 // TODO: Do this in native
1547 canvas.setDensity(mDensity);
1548 } catch (Surface.OutOfResourcesException e) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001549 Log.e(TAG, "OutOfResourcesException locking surface", e);
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001550 // TODO: we should ask the window manager to do something!
1551 // for now we just do nothing
1552 return;
1553 } catch (IllegalArgumentException e) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001554 Log.e(TAG, "IllegalArgumentException locking surface", e);
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001555 // TODO: we should ask the window manager to do something!
1556 // for now we just do nothing
1557 return;
Romain Guy5bcdff42009-05-14 21:27:18 -07001558 }
1559
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001560 try {
1561 if (!dirty.isEmpty() || mIsAnimating) {
1562 long startTime = 0L;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001564 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001565 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001566 + canvas.getWidth() + ", h=" + canvas.getHeight());
1567 //canvas.drawARGB(255, 255, 0, 0);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569
Romain Guy5429e1d2010-09-07 12:38:00 -07001570 if (ViewDebug.DEBUG_PROFILE_DRAWING) {
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001571 startTime = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001573
1574 // If this bitmap's format includes an alpha channel, we
1575 // need to clear it before drawing so that the child will
1576 // properly re-composite its drawing on a transparent
1577 // background. This automatically respects the clip/dirty region
1578 // or
1579 // If we are applying an offset, we need to clear the area
1580 // where the offset doesn't appear to avoid having garbage
1581 // left in the blank areas.
1582 if (!canvas.isOpaque() || yoff != 0) {
1583 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
1584 }
1585
1586 dirty.setEmpty();
1587 mIsAnimating = false;
1588 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
1589 mView.mPrivateFlags |= View.DRAWN;
1590
1591 if (DEBUG_DRAW) {
1592 Context cxt = mView.getContext();
1593 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
1594 ", metrics=" + cxt.getResources().getDisplayMetrics() +
1595 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
1596 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001597 try {
1598 canvas.translate(0, -yoff);
1599 if (mTranslator != null) {
1600 mTranslator.translateCanvas(canvas);
1601 }
1602 canvas.setScreenDensity(scalingRequired
1603 ? DisplayMetrics.DENSITY_DEVICE : 0);
1604 mView.draw(canvas);
1605 } finally {
1606 mAttachInfo.mIgnoreDirtyState = false;
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001607 }
1608
1609 if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
1610 mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
1611 }
1612
Romain Guy5429e1d2010-09-07 12:38:00 -07001613 if (SHOW_FPS || ViewDebug.DEBUG_SHOW_FPS) {
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001614 int now = (int)SystemClock.elapsedRealtime();
1615 if (sDrawTime != 0) {
1616 nativeShowFPS(canvas, now - sDrawTime);
1617 }
1618 sDrawTime = now;
1619 }
1620
Romain Guy5429e1d2010-09-07 12:38:00 -07001621 if (ViewDebug.DEBUG_PROFILE_DRAWING) {
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001622 EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
1623 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 }
1625
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001626 } finally {
1627 surface.unlockCanvasAndPost(canvas);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630
1631 if (LOCAL_LOGV) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001632 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 }
Romain Guy8506ab42009-06-11 17:35:47 -07001634
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001635 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 mFullRedrawNeeded = true;
1637 scheduleTraversals();
1638 }
1639 }
1640
1641 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
1642 final View.AttachInfo attachInfo = mAttachInfo;
1643 final Rect ci = attachInfo.mContentInsets;
1644 final Rect vi = attachInfo.mVisibleInsets;
1645 int scrollY = 0;
1646 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 if (vi.left > ci.left || vi.top > ci.top
1649 || vi.right > ci.right || vi.bottom > ci.bottom) {
1650 // We'll assume that we aren't going to change the scroll
1651 // offset, since we want to avoid that unless it is actually
1652 // going to make the focus visible... otherwise we scroll
1653 // all over the place.
1654 scrollY = mScrollY;
1655 // We can be called for two different situations: during a draw,
1656 // to update the scroll position if the focus has changed (in which
1657 // case 'rectangle' is null), or in response to a
1658 // requestChildRectangleOnScreen() call (in which case 'rectangle'
1659 // is non-null and we just want to scroll to whatever that
1660 // rectangle is).
1661 View focus = mRealFocusedView;
Romain Guye8b16522009-07-14 13:06:42 -07001662
1663 // When in touch mode, focus points to the previously focused view,
1664 // which may have been removed from the view hierarchy. The following
Joe Onoratob71193b2009-11-24 18:34:42 -05001665 // line checks whether the view is still in our hierarchy.
1666 if (focus == null || focus.mAttachInfo != mAttachInfo) {
Romain Guye8b16522009-07-14 13:06:42 -07001667 mRealFocusedView = null;
1668 return false;
1669 }
1670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 if (focus != mLastScrolledFocus) {
1672 // If the focus has changed, then ignore any requests to scroll
1673 // to a rectangle; first we want to make sure the entire focus
1674 // view is visible.
1675 rectangle = null;
1676 }
1677 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
1678 + " rectangle=" + rectangle + " ci=" + ci
1679 + " vi=" + vi);
1680 if (focus == mLastScrolledFocus && !mScrollMayChange
1681 && rectangle == null) {
1682 // Optimization: if the focus hasn't changed since last
1683 // time, and no layout has happened, then just leave things
1684 // as they are.
1685 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
1686 + mScrollY + " vi=" + vi.toShortString());
1687 } else if (focus != null) {
1688 // We need to determine if the currently focused view is
1689 // within the visible part of the window and, if not, apply
1690 // a pan so it can be seen.
1691 mLastScrolledFocus = focus;
1692 mScrollMayChange = false;
1693 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
1694 // Try to find the rectangle from the focus view.
1695 if (focus.getGlobalVisibleRect(mVisRect, null)) {
1696 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
1697 + mView.getWidth() + " h=" + mView.getHeight()
1698 + " ci=" + ci.toShortString()
1699 + " vi=" + vi.toShortString());
1700 if (rectangle == null) {
1701 focus.getFocusedRect(mTempRect);
1702 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
1703 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07001704 if (mView instanceof ViewGroup) {
1705 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
1706 focus, mTempRect);
1707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1709 "Focus in window: focusRect="
1710 + mTempRect.toShortString()
1711 + " visRect=" + mVisRect.toShortString());
1712 } else {
1713 mTempRect.set(rectangle);
1714 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1715 "Request scroll to rect: "
1716 + mTempRect.toShortString()
1717 + " visRect=" + mVisRect.toShortString());
1718 }
1719 if (mTempRect.intersect(mVisRect)) {
1720 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1721 "Focus window visible rect: "
1722 + mTempRect.toShortString());
1723 if (mTempRect.height() >
1724 (mView.getHeight()-vi.top-vi.bottom)) {
1725 // If the focus simply is not going to fit, then
1726 // best is probably just to leave things as-is.
1727 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1728 "Too tall; leaving scrollY=" + scrollY);
1729 } else if ((mTempRect.top-scrollY) < vi.top) {
1730 scrollY -= vi.top - (mTempRect.top-scrollY);
1731 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1732 "Top covered; scrollY=" + scrollY);
1733 } else if ((mTempRect.bottom-scrollY)
1734 > (mView.getHeight()-vi.bottom)) {
1735 scrollY += (mTempRect.bottom-scrollY)
1736 - (mView.getHeight()-vi.bottom);
1737 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1738 "Bottom covered; scrollY=" + scrollY);
1739 }
1740 handled = true;
1741 }
1742 }
1743 }
1744 }
Romain Guy8506ab42009-06-11 17:35:47 -07001745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 if (scrollY != mScrollY) {
1747 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
1748 + mScrollY + " , new=" + scrollY);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08001749 if (!immediate && mResizeBitmap == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 if (mScroller == null) {
1751 mScroller = new Scroller(mView.getContext());
1752 }
1753 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
1754 } else if (mScroller != null) {
1755 mScroller.abortAnimation();
1756 }
1757 mScrollY = scrollY;
1758 }
Romain Guy8506ab42009-06-11 17:35:47 -07001759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 return handled;
1761 }
Romain Guy8506ab42009-06-11 17:35:47 -07001762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 public void requestChildFocus(View child, View focused) {
1764 checkThread();
1765 if (mFocusedView != focused) {
1766 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
1767 scheduleTraversals();
1768 }
1769 mFocusedView = mRealFocusedView = focused;
1770 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
1771 + mFocusedView);
1772 }
1773
1774 public void clearChildFocus(View child) {
1775 checkThread();
1776
1777 View oldFocus = mFocusedView;
1778
1779 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
1780 mFocusedView = mRealFocusedView = null;
1781 if (mView != null && !mView.hasFocus()) {
1782 // If a view gets the focus, the listener will be invoked from requestChildFocus()
1783 if (!mView.requestFocus(View.FOCUS_FORWARD)) {
1784 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
1785 }
1786 } else if (oldFocus != null) {
1787 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
1788 }
1789 }
1790
1791
1792 public void focusableViewAvailable(View v) {
1793 checkThread();
1794
1795 if (mView != null && !mView.hasFocus()) {
1796 v.requestFocus();
1797 } else {
1798 // the one case where will transfer focus away from the current one
1799 // is if the current view is a view group that prefers to give focus
1800 // to its children first AND the view is a descendant of it.
1801 mFocusedView = mView.findFocus();
1802 boolean descendantsHaveDibsOnFocus =
1803 (mFocusedView instanceof ViewGroup) &&
1804 (((ViewGroup) mFocusedView).getDescendantFocusability() ==
1805 ViewGroup.FOCUS_AFTER_DESCENDANTS);
1806 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
1807 // If a view gets the focus, the listener will be invoked from requestChildFocus()
1808 v.requestFocus();
1809 }
1810 }
1811 }
1812
1813 public void recomputeViewAttributes(View child) {
1814 checkThread();
1815 if (mView == child) {
1816 mAttachInfo.mRecomputeGlobalAttributes = true;
1817 if (!mWillDrawSoon) {
1818 scheduleTraversals();
1819 }
1820 }
1821 }
1822
1823 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08001824 if (mView != null && mView.mAttachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 mView.dispatchDetachedFromWindow();
1826 }
1827
1828 mView = null;
1829 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07001830 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831
Romain Guy29d89972010-09-22 16:10:57 -07001832 destroyHardwareRenderer();
Romain Guy4caa4ed2010-08-25 14:46:24 -07001833
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07001834 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001836 if (mInputChannel != null) {
1837 if (mInputQueueCallback != null) {
1838 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
1839 mInputQueueCallback = null;
1840 } else {
1841 InputQueue.unregisterInputChannel(mInputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -07001842 }
1843 }
1844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 try {
1846 sWindowSession.remove(mWindow);
1847 } catch (RemoteException e) {
1848 }
Jeff Brown349703e2010-06-22 01:27:15 -07001849
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001850 // Dispose the input channel after removing the window so the Window Manager
1851 // doesn't interpret the input channel being closed as an abnormal termination.
1852 if (mInputChannel != null) {
1853 mInputChannel.dispose();
1854 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07001855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
Romain Guy8506ab42009-06-11 17:35:47 -07001857
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001858 void updateConfiguration(Configuration config, boolean force) {
1859 if (DEBUG_CONFIGURATION) Log.v(TAG,
1860 "Applying new config to window "
1861 + mWindowAttributes.getTitle()
1862 + ": " + config);
1863 synchronized (sConfigCallbacks) {
1864 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
1865 sConfigCallbacks.get(i).onConfigurationChanged(config);
1866 }
1867 }
1868 if (mView != null) {
1869 // At this point the resources have been updated to
1870 // have the most recent config, whatever that is. Use
1871 // the on in them which may be newer.
1872 if (mView != null) {
1873 config = mView.getResources().getConfiguration();
1874 }
1875 if (force || mLastConfiguration.diff(config) != 0) {
1876 mLastConfiguration.setTo(config);
1877 mView.dispatchConfigurationChanged(config);
1878 }
1879 }
1880 }
1881
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 /**
1883 * Return true if child is an ancestor of parent, (or equal to the parent).
1884 */
1885 private static boolean isViewDescendantOf(View child, View parent) {
1886 if (child == parent) {
1887 return true;
1888 }
1889
1890 final ViewParent theParent = child.getParent();
1891 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
1892 }
1893
Romain Guycdb86672010-03-18 18:54:50 -07001894 private static void forceLayout(View view) {
1895 view.forceLayout();
1896 if (view instanceof ViewGroup) {
1897 ViewGroup group = (ViewGroup) view;
1898 final int count = group.getChildCount();
1899 for (int i = 0; i < count; i++) {
1900 forceLayout(group.getChildAt(i));
1901 }
1902 }
1903 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904
1905 public final static int DO_TRAVERSAL = 1000;
1906 public final static int DIE = 1001;
1907 public final static int RESIZED = 1002;
1908 public final static int RESIZED_REPORT = 1003;
1909 public final static int WINDOW_FOCUS_CHANGED = 1004;
1910 public final static int DISPATCH_KEY = 1005;
1911 public final static int DISPATCH_POINTER = 1006;
1912 public final static int DISPATCH_TRACKBALL = 1007;
1913 public final static int DISPATCH_APP_VISIBILITY = 1008;
1914 public final static int DISPATCH_GET_NEW_SURFACE = 1009;
1915 public final static int FINISHED_EVENT = 1010;
1916 public final static int DISPATCH_KEY_FROM_IME = 1011;
1917 public final static int FINISH_INPUT_CONNECTION = 1012;
1918 public final static int CHECK_FOCUS = 1013;
Dianne Hackbornffa42482009-09-23 22:20:11 -07001919 public final static int CLOSE_SYSTEM_DIALOGS = 1014;
Christopher Tatea53146c2010-09-07 11:57:52 -07001920 public final static int DISPATCH_DRAG_EVENT = 1015;
Chris Tate91e9bb32010-10-12 12:58:43 -07001921 public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
Joe Onorato664644d2011-01-23 17:53:23 -08001922 public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923
1924 @Override
1925 public void handleMessage(Message msg) {
1926 switch (msg.what) {
1927 case View.AttachInfo.INVALIDATE_MSG:
1928 ((View) msg.obj).invalidate();
1929 break;
1930 case View.AttachInfo.INVALIDATE_RECT_MSG:
1931 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
1932 info.target.invalidate(info.left, info.top, info.right, info.bottom);
1933 info.release();
1934 break;
1935 case DO_TRAVERSAL:
1936 if (mProfile) {
1937 Debug.startMethodTracing("ViewRoot");
1938 }
1939
1940 performTraversals();
1941
1942 if (mProfile) {
1943 Debug.stopMethodTracing();
1944 mProfile = false;
1945 }
1946 break;
1947 case FINISHED_EVENT:
1948 handleFinishedEvent(msg.arg1, msg.arg2 != 0);
1949 break;
1950 case DISPATCH_KEY:
Jeff Brown92ff1dd2010-08-11 16:16:06 -07001951 deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 break;
Jeff Brown3915bb82010-11-05 15:02:16 -07001953 case DISPATCH_POINTER:
1954 deliverPointerEvent((MotionEvent) msg.obj, msg.arg1 != 0);
1955 break;
1956 case DISPATCH_TRACKBALL:
1957 deliverTrackballEvent((MotionEvent) msg.obj, msg.arg1 != 0);
1958 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 case DISPATCH_APP_VISIBILITY:
1960 handleAppVisibility(msg.arg1 != 0);
1961 break;
1962 case DISPATCH_GET_NEW_SURFACE:
1963 handleGetNewSurface();
1964 break;
1965 case RESIZED:
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001966 ResizedInfo ri = (ResizedInfo)msg.obj;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001969 && mPendingContentInsets.equals(ri.coveredInsets)
Dianne Hackbornd49258f2010-03-26 00:44:29 -07001970 && mPendingVisibleInsets.equals(ri.visibleInsets)
1971 && ((ResizedInfo)msg.obj).newConfig == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 break;
1973 }
1974 // fall through...
1975 case RESIZED_REPORT:
1976 if (mAdded) {
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001977 Configuration config = ((ResizedInfo)msg.obj).newConfig;
1978 if (config != null) {
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001979 updateConfiguration(config, false);
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001980 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 mWinFrame.left = 0;
1982 mWinFrame.right = msg.arg1;
1983 mWinFrame.top = 0;
1984 mWinFrame.bottom = msg.arg2;
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001985 mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
1986 mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 if (msg.what == RESIZED_REPORT) {
1988 mReportNextDraw = true;
1989 }
Romain Guycdb86672010-03-18 18:54:50 -07001990
1991 if (mView != null) {
1992 forceLayout(mView);
1993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 requestLayout();
1995 }
1996 break;
1997 case WINDOW_FOCUS_CHANGED: {
1998 if (mAdded) {
1999 boolean hasWindowFocus = msg.arg1 != 0;
2000 mAttachInfo.mHasWindowFocus = hasWindowFocus;
2001 if (hasWindowFocus) {
2002 boolean inTouchMode = msg.arg2 != 0;
Romain Guy2d4cff62010-04-09 15:39:00 -07002003 ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004
Romain Guyc361da82010-10-25 15:29:10 -07002005 if (mAttachInfo.mHardwareRenderer != null &&
2006 mSurface != null && mSurface.isValid()) {
Romain Guy7d7b5492011-01-24 16:33:45 -08002007 mFullRedrawNeeded = true;
Romain Guyb051e892010-09-28 19:09:36 -07002008 mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
2009 mAttachInfo, mHolder);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 }
2011 }
Romain Guy8506ab42009-06-11 17:35:47 -07002012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 mLastWasImTarget = WindowManager.LayoutParams
2014 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07002015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 InputMethodManager imm = InputMethodManager.peekInstance();
2017 if (mView != null) {
2018 if (hasWindowFocus && imm != null && mLastWasImTarget) {
2019 imm.startGettingWindowFocus(mView);
2020 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002021 mAttachInfo.mKeyDispatchState.reset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 mView.dispatchWindowFocusChanged(hasWindowFocus);
2023 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 // Note: must be done after the focus change callbacks,
2026 // so all of the view state is set up correctly.
2027 if (hasWindowFocus) {
2028 if (imm != null && mLastWasImTarget) {
2029 imm.onWindowFocus(mView, mView.findFocus(),
2030 mWindowAttributes.softInputMode,
2031 !mHasHadWindowFocus, mWindowAttributes.flags);
2032 }
2033 // Clear the forward bit. We can just do this directly, since
2034 // the window manager doesn't care about it.
2035 mWindowAttributes.softInputMode &=
2036 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2037 ((WindowManager.LayoutParams)mView.getLayoutParams())
2038 .softInputMode &=
2039 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2040 mHasHadWindowFocus = true;
2041 }
svetoslavganov75986cf2009-05-14 22:28:01 -07002042
2043 if (hasWindowFocus && mView != null) {
2044 sendAccessibilityEvents();
2045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 }
2047 } break;
2048 case DIE:
Dianne Hackborn94d69142009-09-28 22:14:42 -07002049 doDie();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07002051 case DISPATCH_KEY_FROM_IME: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07002053 TAG, "Dispatching key "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 + msg.obj + " from IME to " + mView);
The Android Open Source Project10592532009-03-18 17:39:46 -07002055 KeyEvent event = (KeyEvent)msg.obj;
2056 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
2057 // The IME is trying to say this event is from the
2058 // system! Bad bad bad!
Romain Guy812ccbe2010-06-01 14:07:24 -07002059 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project10592532009-03-18 17:39:46 -07002060 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002061 deliverKeyEventPostIme((KeyEvent)msg.obj, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002062 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063 case FINISH_INPUT_CONNECTION: {
2064 InputMethodManager imm = InputMethodManager.peekInstance();
2065 if (imm != null) {
2066 imm.reportFinishInputConnection((InputConnection)msg.obj);
2067 }
2068 } break;
2069 case CHECK_FOCUS: {
2070 InputMethodManager imm = InputMethodManager.peekInstance();
2071 if (imm != null) {
2072 imm.checkFocus();
2073 }
2074 } break;
Dianne Hackbornffa42482009-09-23 22:20:11 -07002075 case CLOSE_SYSTEM_DIALOGS: {
2076 if (mView != null) {
2077 mView.onCloseSystemDialogs((String)msg.obj);
2078 }
2079 } break;
Chris Tate91e9bb32010-10-12 12:58:43 -07002080 case DISPATCH_DRAG_EVENT:
2081 case DISPATCH_DRAG_LOCATION_EVENT: {
Christopher Tate7fb8b562011-01-20 13:46:41 -08002082 DragEvent event = (DragEvent)msg.obj;
2083 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
2084 handleDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07002085 } break;
Joe Onorato664644d2011-01-23 17:53:23 -08002086 case DISPATCH_SYSTEM_UI_VISIBILITY: {
2087 handleDispatchSystemUiVisibilityChanged(msg.arg1);
2088 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 }
2090 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002091
Jeff Brown3915bb82010-11-05 15:02:16 -07002092 private void startInputEvent(InputQueue.FinishedCallback finishedCallback) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07002093 if (mFinishedCallback != null) {
2094 Slog.w(TAG, "Received a new input event from the input queue but there is "
2095 + "already an unfinished input event in progress.");
2096 }
2097
2098 mFinishedCallback = finishedCallback;
2099 }
2100
Jeff Brown3915bb82010-11-05 15:02:16 -07002101 private void finishInputEvent(boolean handled) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07002102 if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished");
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002103
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002104 if (mFinishedCallback != null) {
Jeff Brown3915bb82010-11-05 15:02:16 -07002105 mFinishedCallback.finished(handled);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002106 mFinishedCallback = null;
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002107 } else {
Jeff Brown93ed4e32010-09-23 13:51:48 -07002108 Slog.w(TAG, "Attempted to tell the input queue that the current input event "
2109 + "is finished but there is no input event actually in progress.");
Jeff Brown46b9ac02010-04-22 18:58:52 -07002110 }
2111 }
2112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002113 /**
2114 * Something in the current window tells us we need to change the touch mode. For
2115 * example, we are not in touch mode, and the user touches the screen.
2116 *
2117 * If the touch mode has changed, tell the window manager, and handle it locally.
2118 *
2119 * @param inTouchMode Whether we want to be in touch mode.
2120 * @return True if the touch mode changed and focus changed was changed as a result
2121 */
2122 boolean ensureTouchMode(boolean inTouchMode) {
2123 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
2124 + "touch mode is " + mAttachInfo.mInTouchMode);
2125 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
2126
2127 // tell the window manager
2128 try {
2129 sWindowSession.setInTouchMode(inTouchMode);
2130 } catch (RemoteException e) {
2131 throw new RuntimeException(e);
2132 }
2133
2134 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07002135 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 }
2137
2138 /**
2139 * Ensure that the touch mode for this window is set, and if it is changing,
2140 * take the appropriate action.
2141 * @param inTouchMode Whether we want to be in touch mode.
2142 * @return True if the touch mode changed and focus changed was changed as a result
2143 */
Romain Guy2d4cff62010-04-09 15:39:00 -07002144 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
2146 + "touch mode is " + mAttachInfo.mInTouchMode);
2147
2148 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
2149
2150 mAttachInfo.mInTouchMode = inTouchMode;
2151 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
2152
Romain Guy2d4cff62010-04-09 15:39:00 -07002153 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 }
2155
2156 private boolean enterTouchMode() {
2157 if (mView != null) {
2158 if (mView.hasFocus()) {
2159 // note: not relying on mFocusedView here because this could
2160 // be when the window is first being added, and mFocused isn't
2161 // set yet.
2162 final View focused = mView.findFocus();
2163 if (focused != null && !focused.isFocusableInTouchMode()) {
2164
2165 final ViewGroup ancestorToTakeFocus =
2166 findAncestorToTakeFocusInTouchMode(focused);
2167 if (ancestorToTakeFocus != null) {
2168 // there is an ancestor that wants focus after its descendants that
2169 // is focusable in touch mode.. give it focus
2170 return ancestorToTakeFocus.requestFocus();
2171 } else {
2172 // nothing appropriate to have focus in touch mode, clear it out
2173 mView.unFocus();
2174 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
2175 mFocusedView = null;
2176 return true;
2177 }
2178 }
2179 }
2180 }
2181 return false;
2182 }
2183
2184
2185 /**
2186 * Find an ancestor of focused that wants focus after its descendants and is
2187 * focusable in touch mode.
2188 * @param focused The currently focused view.
2189 * @return An appropriate view, or null if no such view exists.
2190 */
2191 private ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
2192 ViewParent parent = focused.getParent();
2193 while (parent instanceof ViewGroup) {
2194 final ViewGroup vgParent = (ViewGroup) parent;
2195 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2196 && vgParent.isFocusableInTouchMode()) {
2197 return vgParent;
2198 }
2199 if (vgParent.isRootNamespace()) {
2200 return null;
2201 } else {
2202 parent = vgParent.getParent();
2203 }
2204 }
2205 return null;
2206 }
2207
2208 private boolean leaveTouchMode() {
2209 if (mView != null) {
2210 if (mView.hasFocus()) {
2211 // i learned the hard way to not trust mFocusedView :)
2212 mFocusedView = mView.findFocus();
2213 if (!(mFocusedView instanceof ViewGroup)) {
2214 // some view has focus, let it keep it
2215 return false;
2216 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
2217 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2218 // some view group has focus, and doesn't prefer its children
2219 // over itself for focus, so let them keep it.
2220 return false;
2221 }
2222 }
2223
2224 // find the best view to give focus to in this brave new non-touch-mode
2225 // world
2226 final View focused = focusSearch(null, View.FOCUS_DOWN);
2227 if (focused != null) {
2228 return focused.requestFocus(View.FOCUS_DOWN);
2229 }
2230 }
2231 return false;
2232 }
2233
Jeff Brown3915bb82010-11-05 15:02:16 -07002234 private void deliverPointerEvent(MotionEvent event, boolean sendDone) {
2235 // If there is no view, then the event will not be handled.
2236 if (mView == null || !mAdded) {
2237 finishPointerEvent(event, sendDone, false);
2238 return;
2239 }
2240
2241 // Translate the pointer event for compatibility, if needed.
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002242 if (mTranslator != null) {
2243 mTranslator.translateEventInScreenToAppWindow(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 }
2245
Jeff Brown3915bb82010-11-05 15:02:16 -07002246 // Enter touch mode on the down.
2247 boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
2248 if (isDown) {
2249 ensureTouchMode(true);
2250 }
2251 if(Config.LOGV) {
2252 captureMotionLog("captureDispatchPointer", event);
2253 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002254
Jeff Brown3915bb82010-11-05 15:02:16 -07002255 // Offset the scroll position.
2256 if (mCurScrollY != 0) {
2257 event.offsetLocation(0, mCurScrollY);
2258 }
2259 if (MEASURE_LATENCY) {
2260 lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
2261 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002262
Jeff Brown3915bb82010-11-05 15:02:16 -07002263 // Remember the touch position for possible drag-initiation.
2264 mLastTouchPoint.x = event.getRawX();
2265 mLastTouchPoint.y = event.getRawY();
2266
2267 // Dispatch touch to view hierarchy.
2268 boolean handled = mView.dispatchTouchEvent(event);
2269 if (MEASURE_LATENCY) {
2270 lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
2271 }
2272 if (handled) {
2273 finishPointerEvent(event, sendDone, true);
2274 return;
2275 }
2276
2277 // Apply edge slop and try again, if appropriate.
2278 final int edgeFlags = event.getEdgeFlags();
2279 if (edgeFlags != 0 && mView instanceof ViewGroup) {
2280 final int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
2281 int direction = View.FOCUS_UP;
2282 int x = (int)event.getX();
2283 int y = (int)event.getY();
2284 final int[] deltas = new int[2];
2285
2286 if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
2287 direction = View.FOCUS_DOWN;
2288 if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
2289 deltas[0] = edgeSlop;
2290 x += edgeSlop;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002291 } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
Jeff Brown3915bb82010-11-05 15:02:16 -07002292 deltas[0] = -edgeSlop;
2293 x -= edgeSlop;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002294 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002295 } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
2296 direction = View.FOCUS_UP;
2297 if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
2298 deltas[0] = edgeSlop;
2299 x += edgeSlop;
2300 } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
2301 deltas[0] = -edgeSlop;
2302 x -= edgeSlop;
2303 }
2304 } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
2305 direction = View.FOCUS_RIGHT;
2306 } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
2307 direction = View.FOCUS_LEFT;
2308 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002309
Jeff Brown3915bb82010-11-05 15:02:16 -07002310 View nearest = FocusFinder.getInstance().findNearestTouchable(
2311 ((ViewGroup) mView), x, y, direction, deltas);
2312 if (nearest != null) {
2313 event.offsetLocation(deltas[0], deltas[1]);
2314 event.setEdgeFlags(0);
2315 if (mView.dispatchTouchEvent(event)) {
2316 finishPointerEvent(event, sendDone, true);
2317 return;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002318 }
2319 }
2320 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002321
2322 // Pointer event was unhandled.
2323 finishPointerEvent(event, sendDone, false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002324 }
2325
Jeff Brown3915bb82010-11-05 15:02:16 -07002326 private void finishPointerEvent(MotionEvent event, boolean sendDone, boolean handled) {
2327 event.recycle();
2328 if (sendDone) {
2329 finishInputEvent(handled);
2330 }
2331 if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
2332 }
2333
2334 private void deliverTrackballEvent(MotionEvent event, boolean sendDone) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002335 if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
2336
Jeff Brown3915bb82010-11-05 15:02:16 -07002337 // If there is no view, then the event will not be handled.
2338 if (mView == null || !mAdded) {
2339 finishTrackballEvent(event, sendDone, false);
2340 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 }
2342
Jeff Brown3915bb82010-11-05 15:02:16 -07002343 // Deliver the trackball event to the view.
2344 if (mView.dispatchTrackballEvent(event)) {
2345 // If we reach this, we delivered a trackball event to mView and
2346 // mView consumed it. Because we will not translate the trackball
2347 // event into a key event, touch mode will not exit, so we exit
2348 // touch mode here.
2349 ensureTouchMode(false);
2350
2351 finishTrackballEvent(event, sendDone, true);
2352 mLastTrackballTime = Integer.MIN_VALUE;
2353 return;
2354 }
2355
2356 // Translate the trackball event into DPAD keys and try to deliver those.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357 final TrackballAxis x = mTrackballAxisX;
2358 final TrackballAxis y = mTrackballAxisY;
2359
2360 long curTime = SystemClock.uptimeMillis();
Jeff Brown3915bb82010-11-05 15:02:16 -07002361 if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002362 // It has been too long since the last movement,
2363 // so restart at the beginning.
2364 x.reset(0);
2365 y.reset(0);
2366 mLastTrackballTime = curTime;
2367 }
2368
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002369 final int action = event.getAction();
Jeff Brown49ed71d2010-12-06 17:13:33 -08002370 final int metaState = event.getMetaState();
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002371 switch (action) {
2372 case MotionEvent.ACTION_DOWN:
2373 x.reset(2);
2374 y.reset(2);
2375 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002376 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
2377 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2378 InputDevice.SOURCE_KEYBOARD), false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002379 break;
2380 case MotionEvent.ACTION_UP:
2381 x.reset(2);
2382 y.reset(2);
2383 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002384 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
2385 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2386 InputDevice.SOURCE_KEYBOARD), false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002387 break;
2388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002389
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002390 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
2391 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
2392 + " move=" + event.getX()
2393 + " / Y=" + y.position + " step="
2394 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
2395 + " move=" + event.getY());
2396 final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
2397 final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002398
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002399 // Generate DPAD events based on the trackball movement.
2400 // We pick the axis that has moved the most as the direction of
2401 // the DPAD. When we generate DPAD events for one axis, then the
2402 // other axis is reset -- we don't want to perform DPAD jumps due
2403 // to slight movements in the trackball when making major movements
2404 // along the other axis.
2405 int keycode = 0;
2406 int movement = 0;
2407 float accel = 1;
2408 if (xOff > yOff) {
2409 movement = x.generate((2/event.getXPrecision()));
2410 if (movement != 0) {
2411 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
2412 : KeyEvent.KEYCODE_DPAD_LEFT;
2413 accel = x.acceleration;
2414 y.reset(2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002416 } else if (yOff > 0) {
2417 movement = y.generate((2/event.getYPrecision()));
2418 if (movement != 0) {
2419 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
2420 : KeyEvent.KEYCODE_DPAD_UP;
2421 accel = y.acceleration;
2422 x.reset(2);
2423 }
2424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002425
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002426 if (keycode != 0) {
2427 if (movement < 0) movement = -movement;
2428 int accelMovement = (int)(movement * accel);
2429 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
2430 + " accelMovement=" + accelMovement
2431 + " accel=" + accel);
2432 if (accelMovement > movement) {
2433 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
2434 + keycode);
2435 movement--;
Jeff Brown49ed71d2010-12-06 17:13:33 -08002436 int repeatCount = accelMovement - movement;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002437 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002438 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
2439 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2440 InputDevice.SOURCE_KEYBOARD), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002441 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002442 while (movement > 0) {
2443 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
2444 + keycode);
2445 movement--;
2446 curTime = SystemClock.uptimeMillis();
2447 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002448 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
2449 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2450 InputDevice.SOURCE_KEYBOARD), false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002451 deliverKeyEvent(new KeyEvent(curTime, curTime,
Jeff Brown49ed71d2010-12-06 17:13:33 -08002452 KeyEvent.ACTION_UP, keycode, 0, metaState,
2453 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
2454 InputDevice.SOURCE_KEYBOARD), false);
2455 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002456 mLastTrackballTime = curTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002458
2459 // Unfortunately we can't tell whether the application consumed the keys, so
2460 // we always consider the trackball event handled.
2461 finishTrackballEvent(event, sendDone, true);
2462 }
2463
2464 private void finishTrackballEvent(MotionEvent event, boolean sendDone, boolean handled) {
2465 event.recycle();
2466 if (sendDone) {
2467 finishInputEvent(handled);
2468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002469 }
2470
2471 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08002472 * Returns true if the key is used for keyboard navigation.
2473 * @param keyEvent The key event.
2474 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08002476 private static boolean isNavigationKey(KeyEvent keyEvent) {
2477 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 case KeyEvent.KEYCODE_DPAD_LEFT:
2479 case KeyEvent.KEYCODE_DPAD_RIGHT:
2480 case KeyEvent.KEYCODE_DPAD_UP:
2481 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08002482 case KeyEvent.KEYCODE_DPAD_CENTER:
2483 case KeyEvent.KEYCODE_PAGE_UP:
2484 case KeyEvent.KEYCODE_PAGE_DOWN:
2485 case KeyEvent.KEYCODE_MOVE_HOME:
2486 case KeyEvent.KEYCODE_MOVE_END:
2487 case KeyEvent.KEYCODE_TAB:
2488 case KeyEvent.KEYCODE_SPACE:
2489 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 return true;
2491 }
2492 return false;
2493 }
2494
2495 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08002496 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002497 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08002498 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002499 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08002500 private static boolean isTypingKey(KeyEvent keyEvent) {
2501 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002502 }
2503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08002505 * 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 -08002506 * @param event The key event.
2507 * @return Whether this key event should be consumed (meaning the act of
2508 * leaving touch mode alone is considered the event).
2509 */
2510 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08002511 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 if (!mAttachInfo.mInTouchMode) {
2513 return false;
2514 }
2515
Jeff Brown4e6319b2010-12-13 10:36:51 -08002516 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
2517 final int action = event.getAction();
2518 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519 return false;
2520 }
2521
Jeff Brown4e6319b2010-12-13 10:36:51 -08002522 // Don't leave touch mode if the IME told us not to.
2523 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
2524 return false;
2525 }
2526
2527 // If the key can be used for keyboard navigation then leave touch mode
2528 // and select a focused view if needed (in ensureTouchMode).
2529 // When a new focused view is selected, we consume the navigation key because
2530 // navigation doesn't make much sense unless a view already has focus so
2531 // the key's purpose is to set focus.
2532 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 return ensureTouchMode(false);
2534 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08002535
2536 // If the key can be used for typing then leave touch mode
2537 // and select a focused view if needed (in ensureTouchMode).
2538 // Always allow the view to process the typing key.
2539 if (isTypingKey(event)) {
2540 ensureTouchMode(false);
2541 return false;
2542 }
2543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 return false;
2545 }
2546
2547 /**
Romain Guy8506ab42009-06-11 17:35:47 -07002548 * log motion events
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 */
2550 private static void captureMotionLog(String subTag, MotionEvent ev) {
Romain Guy8506ab42009-06-11 17:35:47 -07002551 //check dynamic switch
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 if (ev == null ||
2553 SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
2554 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 }
Romain Guy8506ab42009-06-11 17:35:47 -07002556
2557 StringBuilder sb = new StringBuilder(subTag + ": ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002558 sb.append(ev.getDownTime()).append(',');
2559 sb.append(ev.getEventTime()).append(',');
2560 sb.append(ev.getAction()).append(',');
Romain Guy8506ab42009-06-11 17:35:47 -07002561 sb.append(ev.getX()).append(',');
2562 sb.append(ev.getY()).append(',');
2563 sb.append(ev.getPressure()).append(',');
2564 sb.append(ev.getSize()).append(',');
2565 sb.append(ev.getMetaState()).append(',');
2566 sb.append(ev.getXPrecision()).append(',');
2567 sb.append(ev.getYPrecision()).append(',');
2568 sb.append(ev.getDeviceId()).append(',');
2569 sb.append(ev.getEdgeFlags());
2570 Log.d(TAG, sb.toString());
2571 }
2572 /**
2573 * log motion events
2574 */
2575 private static void captureKeyLog(String subTag, KeyEvent ev) {
2576 //check dynamic switch
2577 if (ev == null ||
2578 SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
2579 return;
2580 }
2581 StringBuilder sb = new StringBuilder(subTag + ": ");
2582 sb.append(ev.getDownTime()).append(',');
2583 sb.append(ev.getEventTime()).append(',');
2584 sb.append(ev.getAction()).append(',');
2585 sb.append(ev.getKeyCode()).append(',');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 sb.append(ev.getRepeatCount()).append(',');
2587 sb.append(ev.getMetaState()).append(',');
2588 sb.append(ev.getDeviceId()).append(',');
2589 sb.append(ev.getScanCode());
Romain Guy8506ab42009-06-11 17:35:47 -07002590 Log.d(TAG, sb.toString());
2591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002592
2593 int enqueuePendingEvent(Object event, boolean sendDone) {
2594 int seq = mPendingEventSeq+1;
2595 if (seq < 0) seq = 0;
2596 mPendingEventSeq = seq;
2597 mPendingEvents.put(seq, event);
2598 return sendDone ? seq : -seq;
2599 }
2600
2601 Object retrievePendingEvent(int seq) {
2602 if (seq < 0) seq = -seq;
2603 Object event = mPendingEvents.get(seq);
2604 if (event != null) {
2605 mPendingEvents.remove(seq);
2606 }
2607 return event;
2608 }
Romain Guy8506ab42009-06-11 17:35:47 -07002609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
Jeff Brown3915bb82010-11-05 15:02:16 -07002611 // If there is no view, then the event will not be handled.
2612 if (mView == null || !mAdded) {
2613 finishKeyEvent(event, sendDone, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002614 return;
2615 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002616
2617 if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
2618
2619 // Perform predispatching before the IME.
2620 if (mView.dispatchKeyEventPreIme(event)) {
2621 finishKeyEvent(event, sendDone, true);
2622 return;
2623 }
2624
2625 // Dispatch to the IME before propagating down the view hierarchy.
2626 // The IME will eventually call back into handleFinishedEvent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002627 if (mLastWasImTarget) {
2628 InputMethodManager imm = InputMethodManager.peekInstance();
Jeff Brown3915bb82010-11-05 15:02:16 -07002629 if (imm != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002630 int seq = enqueuePendingEvent(event, sendDone);
2631 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
2632 + seq + " event=" + event);
Jeff Brown3915bb82010-11-05 15:02:16 -07002633 imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002634 return;
2635 }
2636 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002637
2638 // Not dispatching to IME, continue with post IME actions.
2639 deliverKeyEventPostIme(event, sendDone);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640 }
2641
Jeff Brown3915bb82010-11-05 15:02:16 -07002642 private void handleFinishedEvent(int seq, boolean handled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
2644 if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
2645 + " handled=" + handled + " event=" + event);
2646 if (event != null) {
2647 final boolean sendDone = seq >= 0;
Jeff Brown3915bb82010-11-05 15:02:16 -07002648 if (handled) {
2649 finishKeyEvent(event, sendDone, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 } else {
Jeff Brown3915bb82010-11-05 15:02:16 -07002651 deliverKeyEventPostIme(event, sendDone);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 }
2653 }
2654 }
Romain Guy8506ab42009-06-11 17:35:47 -07002655
Jeff Brown3915bb82010-11-05 15:02:16 -07002656 private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) {
2657 // If the view went away, then the event will not be handled.
2658 if (mView == null || !mAdded) {
2659 finishKeyEvent(event, sendDone, false);
2660 return;
2661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662
Jeff Brown3915bb82010-11-05 15:02:16 -07002663 // If the key's purpose is to exit touch mode then we consume it and consider it handled.
2664 if (checkForLeavingTouchModeAndConsume(event)) {
2665 finishKeyEvent(event, sendDone, true);
2666 return;
2667 }
Romain Guy8506ab42009-06-11 17:35:47 -07002668
Jeff Brown3915bb82010-11-05 15:02:16 -07002669 if (Config.LOGV) {
2670 captureKeyLog("captureDispatchKeyEvent", event);
2671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672
Jeff Brown90655042010-12-02 13:50:46 -08002673 // Make sure the fallback event policy sees all keys that will be delivered to the
2674 // view hierarchy.
2675 mFallbackEventHandler.preDispatchKeyEvent(event);
2676
Jeff Brown3915bb82010-11-05 15:02:16 -07002677 // Deliver the key to the view hierarchy.
2678 if (mView.dispatchKeyEvent(event)) {
2679 finishKeyEvent(event, sendDone, true);
2680 return;
2681 }
Joe Onorato86f67862010-11-05 18:57:34 -07002682
Jeff Brownc1df9072010-12-21 16:38:50 -08002683 // If the Control modifier is held, try to interpret the key as a shortcut.
2684 if (event.getAction() == KeyEvent.ACTION_UP
2685 && event.isCtrlPressed()
2686 && !KeyEvent.isModifierKey(event.getKeyCode())) {
2687 if (mView.dispatchKeyShortcutEvent(event)) {
2688 finishKeyEvent(event, sendDone, true);
2689 return;
2690 }
2691 }
2692
Jeff Brown3915bb82010-11-05 15:02:16 -07002693 // Apply the fallback event policy.
2694 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
2695 finishKeyEvent(event, sendDone, true);
2696 return;
2697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698
Jeff Brown3915bb82010-11-05 15:02:16 -07002699 // Handle automatic focus changes.
2700 if (event.getAction() == KeyEvent.ACTION_DOWN) {
2701 int direction = 0;
2702 switch (event.getKeyCode()) {
2703 case KeyEvent.KEYCODE_DPAD_LEFT:
Jeff Brown4e6319b2010-12-13 10:36:51 -08002704 if (event.hasNoModifiers()) {
2705 direction = View.FOCUS_LEFT;
2706 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002707 break;
2708 case KeyEvent.KEYCODE_DPAD_RIGHT:
Jeff Brown4e6319b2010-12-13 10:36:51 -08002709 if (event.hasNoModifiers()) {
2710 direction = View.FOCUS_RIGHT;
2711 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002712 break;
2713 case KeyEvent.KEYCODE_DPAD_UP:
Jeff Brown4e6319b2010-12-13 10:36:51 -08002714 if (event.hasNoModifiers()) {
2715 direction = View.FOCUS_UP;
2716 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002717 break;
2718 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08002719 if (event.hasNoModifiers()) {
2720 direction = View.FOCUS_DOWN;
2721 }
2722 break;
2723 case KeyEvent.KEYCODE_TAB:
2724 if (event.hasNoModifiers()) {
2725 direction = View.FOCUS_FORWARD;
2726 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
2727 direction = View.FOCUS_BACKWARD;
2728 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002729 break;
2730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731
Jeff Brown3915bb82010-11-05 15:02:16 -07002732 if (direction != 0) {
2733 View focused = mView != null ? mView.findFocus() : null;
2734 if (focused != null) {
2735 View v = focused.focusSearch(direction);
2736 if (v != null && v != focused) {
2737 // do the math the get the interesting rect
2738 // of previous focused into the coord system of
2739 // newly focused view
2740 focused.getFocusedRect(mTempRect);
2741 if (mView instanceof ViewGroup) {
2742 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2743 focused, mTempRect);
2744 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
2745 v, mTempRect);
2746 }
2747 if (v.requestFocus(direction, mTempRect)) {
2748 playSoundEffect(
2749 SoundEffectConstants.getContantForFocusDirection(direction));
2750 finishKeyEvent(event, sendDone, true);
2751 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752 }
2753 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002754
2755 // Give the focused view a last chance to handle the dpad key.
2756 if (mView.dispatchUnhandledMove(focused, direction)) {
2757 finishKeyEvent(event, sendDone, true);
2758 return;
2759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002760 }
2761 }
Jeff Brown3915bb82010-11-05 15:02:16 -07002762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763
Jeff Brown3915bb82010-11-05 15:02:16 -07002764 // Key was unhandled.
2765 finishKeyEvent(event, sendDone, false);
2766 }
2767
2768 private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) {
2769 if (sendDone) {
2770 finishInputEvent(handled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002771 }
2772 }
2773
Christopher Tatea53146c2010-09-07 11:57:52 -07002774 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08002775 void setLocalDragState(Object obj) {
2776 mLocalDragState = obj;
2777 }
2778
Christopher Tatea53146c2010-09-07 11:57:52 -07002779 private void handleDragEvent(DragEvent event) {
2780 // From the root, only drag start/end/location are dispatched. entered/exited
2781 // are determined and dispatched by the viewgroup hierarchy, who then report
2782 // that back here for ultimate reporting back to the framework.
2783 if (mView != null && mAdded) {
2784 final int what = event.mAction;
2785
2786 if (what == DragEvent.ACTION_DRAG_EXITED) {
2787 // A direct EXITED event means that the window manager knows we've just crossed
2788 // a window boundary, so the current drag target within this one must have
2789 // just been exited. Send it the usual notifications and then we're done
2790 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07002791 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07002792 } else {
2793 // Cache the drag description when the operation starts, then fill it in
2794 // on subsequent calls as a convenience
2795 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07002796 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07002797 mDragDescription = event.mClipDescription;
2798 } else {
2799 event.mClipDescription = mDragDescription;
2800 }
2801
2802 // For events with a [screen] location, translate into window coordinates
2803 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
2804 mDragPoint.set(event.mX, event.mY);
2805 if (mTranslator != null) {
2806 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
2807 }
2808
2809 if (mCurScrollY != 0) {
2810 mDragPoint.offset(0, mCurScrollY);
2811 }
2812
2813 event.mX = mDragPoint.x;
2814 event.mY = mDragPoint.y;
2815 }
2816
2817 // Remember who the current drag target is pre-dispatch
2818 final View prevDragView = mCurrentDragView;
2819
2820 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07002821 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07002822
2823 // If we changed apparent drag target, tell the OS about it
2824 if (prevDragView != mCurrentDragView) {
2825 try {
2826 if (prevDragView != null) {
2827 sWindowSession.dragRecipientExited(mWindow);
2828 }
2829 if (mCurrentDragView != null) {
2830 sWindowSession.dragRecipientEntered(mWindow);
2831 }
2832 } catch (RemoteException e) {
2833 Slog.e(TAG, "Unable to note drag target change");
2834 }
Christopher Tatea53146c2010-09-07 11:57:52 -07002835 }
Chris Tated4533f12010-10-19 15:15:08 -07002836
Christopher Tate407b4e92010-11-30 17:14:08 -08002837 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07002838 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08002839 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07002840 try {
2841 Log.i(TAG, "Reporting drop result: " + result);
2842 sWindowSession.reportDropResult(mWindow, result);
2843 } catch (RemoteException e) {
2844 Log.e(TAG, "Unable to report drop result");
2845 }
2846 }
Christopher Tate407b4e92010-11-30 17:14:08 -08002847
2848 // When the drag operation ends, release any local state object
2849 // that may have been in use
2850 if (what == DragEvent.ACTION_DRAG_ENDED) {
2851 setLocalDragState(null);
2852 }
Christopher Tatea53146c2010-09-07 11:57:52 -07002853 }
2854 }
2855 event.recycle();
2856 }
2857
Joe Onorato664644d2011-01-23 17:53:23 -08002858 public void handleDispatchSystemUiVisibilityChanged(int visibility) {
2859 if (mView == null) return;
Joe Onorato14782f72011-01-25 19:53:17 -08002860 if (mAttachInfo != null) {
2861 mAttachInfo.mSystemUiVisibility = visibility;
2862 }
Joe Onorato664644d2011-01-23 17:53:23 -08002863 mView.dispatchSystemUiVisibilityChanged(visibility);
2864 }
2865
Christopher Tate2c095f32010-10-04 14:13:40 -07002866 public void getLastTouchPoint(Point outLocation) {
2867 outLocation.x = (int) mLastTouchPoint.x;
2868 outLocation.y = (int) mLastTouchPoint.y;
2869 }
2870
Chris Tate9d1ab882010-11-02 15:55:39 -07002871 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07002872 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07002873 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07002874 }
Christopher Tatea53146c2010-09-07 11:57:52 -07002875 }
2876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 private AudioManager getAudioManager() {
2878 if (mView == null) {
2879 throw new IllegalStateException("getAudioManager called when there is no mView");
2880 }
2881 if (mAudioManager == null) {
2882 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
2883 }
2884 return mAudioManager;
2885 }
2886
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002887 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
2888 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002889
2890 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002891 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002892 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07002893 restore = true;
2894 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002895 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002896 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002897 if (params != null) {
2898 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002899 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002900 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07002901 //Log.d(TAG, ">>>>>> CALLING relayout");
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002902 int relayoutResult = sWindowSession.relayout(
2903 mWindow, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08002904 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
2905 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002906 viewVisibility, insetsPending, mWinFrame,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002907 mPendingContentInsets, mPendingVisibleInsets,
2908 mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07002909 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002910 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07002911 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002912 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002913
2914 if (mTranslator != null) {
2915 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
2916 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
2917 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002918 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002919 return relayoutResult;
2920 }
Romain Guy8506ab42009-06-11 17:35:47 -07002921
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002922 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 * {@inheritDoc}
2924 */
2925 public void playSoundEffect(int effectId) {
2926 checkThread();
2927
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07002928 try {
2929 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07002931 switch (effectId) {
2932 case SoundEffectConstants.CLICK:
2933 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
2934 return;
2935 case SoundEffectConstants.NAVIGATION_DOWN:
2936 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
2937 return;
2938 case SoundEffectConstants.NAVIGATION_LEFT:
2939 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
2940 return;
2941 case SoundEffectConstants.NAVIGATION_RIGHT:
2942 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
2943 return;
2944 case SoundEffectConstants.NAVIGATION_UP:
2945 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
2946 return;
2947 default:
2948 throw new IllegalArgumentException("unknown effect id " + effectId +
2949 " not defined in " + SoundEffectConstants.class.getCanonicalName());
2950 }
2951 } catch (IllegalStateException e) {
2952 // Exception thrown by getAudioManager() when mView is null
2953 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
2954 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 }
2956 }
2957
2958 /**
2959 * {@inheritDoc}
2960 */
2961 public boolean performHapticFeedback(int effectId, boolean always) {
2962 try {
2963 return sWindowSession.performHapticFeedback(mWindow, effectId, always);
2964 } catch (RemoteException e) {
2965 return false;
2966 }
2967 }
2968
2969 /**
2970 * {@inheritDoc}
2971 */
2972 public View focusSearch(View focused, int direction) {
2973 checkThread();
2974 if (!(mView instanceof ViewGroup)) {
2975 return null;
2976 }
2977 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
2978 }
2979
2980 public void debug() {
2981 mView.debug();
2982 }
2983
2984 public void die(boolean immediate) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07002985 if (immediate) {
2986 doDie();
2987 } else {
2988 sendEmptyMessage(DIE);
2989 }
2990 }
2991
2992 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07002994 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 synchronized (this) {
2996 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07002997 destroyHardwareRenderer();
2998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 int viewVisibility = mView.getVisibility();
3000 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
3001 if (mWindowAttributesChanged || viewVisibilityChanged) {
3002 // If layout params have been changed, first give them
3003 // to the window manager to make sure it has the correct
3004 // animation info.
3005 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07003006 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
3007 & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 sWindowSession.finishDrawing(mWindow);
3009 }
3010 } catch (RemoteException e) {
3011 }
3012 }
3013
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003014 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003015 }
3016 if (mAdded) {
3017 mAdded = false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07003018 dispatchDetachedFromWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 }
3020 }
3021 }
3022
Romain Guy29d89972010-09-22 16:10:57 -07003023 private void destroyHardwareRenderer() {
Romain Guyb051e892010-09-28 19:09:36 -07003024 if (mAttachInfo.mHardwareRenderer != null) {
3025 mAttachInfo.mHardwareRenderer.destroy(true);
3026 mAttachInfo.mHardwareRenderer = null;
Romain Guy29d89972010-09-22 16:10:57 -07003027 mAttachInfo.mHardwareAccelerated = false;
3028 }
3029 }
3030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003031 public void dispatchFinishedEvent(int seq, boolean handled) {
3032 Message msg = obtainMessage(FINISHED_EVENT);
3033 msg.arg1 = seq;
3034 msg.arg2 = handled ? 1 : 0;
3035 sendMessage(msg);
3036 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07003037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003038 public void dispatchResized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08003039 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003040 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
3041 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
3042 + " visibleInsets=" + visibleInsets.toShortString()
3043 + " reportDraw=" + reportDraw);
3044 Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003045 if (mTranslator != null) {
3046 mTranslator.translateRectInScreenToAppWindow(coveredInsets);
3047 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
3048 w *= mTranslator.applicationInvertedScale;
3049 h *= mTranslator.applicationInvertedScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003050 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07003051 msg.arg1 = w;
3052 msg.arg2 = h;
Dianne Hackborne36d6e22010-02-17 19:46:25 -08003053 ResizedInfo ri = new ResizedInfo();
3054 ri.coveredInsets = new Rect(coveredInsets);
3055 ri.visibleInsets = new Rect(visibleInsets);
3056 ri.newConfig = newConfig;
3057 msg.obj = ri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003058 sendMessage(msg);
3059 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07003060
Jeff Brown3915bb82010-11-05 15:02:16 -07003061 private InputQueue.FinishedCallback mFinishedCallback;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003062
3063 private final InputHandler mInputHandler = new InputHandler() {
Jeff Brown3915bb82010-11-05 15:02:16 -07003064 public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003065 startInputEvent(finishedCallback);
Jeff Brown92ff1dd2010-08-11 16:16:06 -07003066 dispatchKey(event, true);
Jeff Brown46b9ac02010-04-22 18:58:52 -07003067 }
3068
Jeff Brown3915bb82010-11-05 15:02:16 -07003069 public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003070 startInputEvent(finishedCallback);
3071 dispatchMotion(event, true);
Jeff Brown46b9ac02010-04-22 18:58:52 -07003072 }
3073 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074
3075 public void dispatchKey(KeyEvent event) {
Jeff Brown92ff1dd2010-08-11 16:16:06 -07003076 dispatchKey(event, false);
3077 }
3078
3079 private void dispatchKey(KeyEvent event, boolean sendDone) {
3080 //noinspection ConstantConditions
3081 if (false && event.getAction() == KeyEvent.ACTION_DOWN) {
3082 if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
Romain Guy812ccbe2010-06-01 14:07:24 -07003083 if (DBG) Log.d("keydisp", "===================================================");
3084 if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
3085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003086 debug();
3087
Romain Guy812ccbe2010-06-01 14:07:24 -07003088 if (DBG) Log.d("keydisp", "===================================================");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 }
3090 }
3091
3092 Message msg = obtainMessage(DISPATCH_KEY);
3093 msg.obj = event;
Jeff Brown92ff1dd2010-08-11 16:16:06 -07003094 msg.arg1 = sendDone ? 1 : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095
3096 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07003097 TAG, "sending key " + event + " to " + mView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098
3099 sendMessageAtTime(msg, event.getEventTime());
3100 }
Jeff Brownc5ed5912010-07-14 18:48:53 -07003101
3102 public void dispatchMotion(MotionEvent event) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003103 dispatchMotion(event, false);
3104 }
3105
3106 private void dispatchMotion(MotionEvent event, boolean sendDone) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07003107 int source = event.getSource();
3108 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003109 dispatchPointer(event, sendDone);
Jeff Brownc5ed5912010-07-14 18:48:53 -07003110 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003111 dispatchTrackball(event, sendDone);
Jeff Brownc5ed5912010-07-14 18:48:53 -07003112 } else {
3113 // TODO
3114 Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
Jeff Brown93ed4e32010-09-23 13:51:48 -07003115 if (sendDone) {
Jeff Brown3915bb82010-11-05 15:02:16 -07003116 finishInputEvent(false);
Jeff Brown93ed4e32010-09-23 13:51:48 -07003117 }
Jeff Brownc5ed5912010-07-14 18:48:53 -07003118 }
3119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003120
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003121 public void dispatchPointer(MotionEvent event) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003122 dispatchPointer(event, false);
3123 }
3124
3125 private void dispatchPointer(MotionEvent event, boolean sendDone) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 Message msg = obtainMessage(DISPATCH_POINTER);
3127 msg.obj = event;
Jeff Brown93ed4e32010-09-23 13:51:48 -07003128 msg.arg1 = sendDone ? 1 : 0;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003129 sendMessageAtTime(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 }
3131
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003132 public void dispatchTrackball(MotionEvent event) {
Jeff Brown93ed4e32010-09-23 13:51:48 -07003133 dispatchTrackball(event, false);
3134 }
3135
3136 private void dispatchTrackball(MotionEvent event, boolean sendDone) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003137 Message msg = obtainMessage(DISPATCH_TRACKBALL);
3138 msg.obj = event;
Jeff Brown93ed4e32010-09-23 13:51:48 -07003139 msg.arg1 = sendDone ? 1 : 0;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003140 sendMessageAtTime(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 public void dispatchAppVisibility(boolean visible) {
3144 Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
3145 msg.arg1 = visible ? 1 : 0;
3146 sendMessage(msg);
3147 }
3148
3149 public void dispatchGetNewSurface() {
3150 Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
3151 sendMessage(msg);
3152 }
3153
3154 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
3155 Message msg = Message.obtain();
3156 msg.what = WINDOW_FOCUS_CHANGED;
3157 msg.arg1 = hasFocus ? 1 : 0;
3158 msg.arg2 = inTouchMode ? 1 : 0;
3159 sendMessage(msg);
3160 }
3161
Dianne Hackbornffa42482009-09-23 22:20:11 -07003162 public void dispatchCloseSystemDialogs(String reason) {
3163 Message msg = Message.obtain();
3164 msg.what = CLOSE_SYSTEM_DIALOGS;
3165 msg.obj = reason;
3166 sendMessage(msg);
3167 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003168
3169 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07003170 final int what;
3171 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
3172 what = DISPATCH_DRAG_LOCATION_EVENT;
3173 removeMessages(what);
3174 } else {
3175 what = DISPATCH_DRAG_EVENT;
3176 }
3177 Message msg = obtainMessage(what, event);
Christopher Tatea53146c2010-09-07 11:57:52 -07003178 sendMessage(msg);
3179 }
3180
Joe Onorato664644d2011-01-23 17:53:23 -08003181 public void dispatchSystemUiVisibilityChanged(int visibility) {
3182 sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, visibility, 0));
3183 }
3184
svetoslavganov75986cf2009-05-14 22:28:01 -07003185 /**
3186 * The window is getting focus so if there is anything focused/selected
3187 * send an {@link AccessibilityEvent} to announce that.
3188 */
3189 private void sendAccessibilityEvents() {
3190 if (!AccessibilityManager.getInstance(mView.getContext()).isEnabled()) {
3191 return;
3192 }
3193 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
3194 View focusedView = mView.findFocus();
3195 if (focusedView != null && focusedView != mView) {
3196 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
3197 }
3198 }
3199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 public boolean showContextMenuForChild(View originalView) {
3201 return false;
3202 }
3203
Adam Powell6e346362010-07-23 10:18:23 -07003204 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
3205 return null;
3206 }
3207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 public void createContextMenu(ContextMenu menu) {
3209 }
3210
3211 public void childDrawableStateChanged(View child) {
3212 }
3213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003214 void checkThread() {
3215 if (mThread != Thread.currentThread()) {
3216 throw new CalledFromWrongThreadException(
3217 "Only the original thread that created a view hierarchy can touch its views.");
3218 }
3219 }
3220
3221 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
3222 // ViewRoot never intercepts touch event, so this can be a no-op
3223 }
3224
3225 public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
3226 boolean immediate) {
3227 return scrollToRectOrFocus(rectangle, immediate);
3228 }
Romain Guy8506ab42009-06-11 17:35:47 -07003229
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003230 class TakenSurfaceHolder extends BaseSurfaceHolder {
3231 @Override
3232 public boolean onAllowLockCanvas() {
3233 return mDrawingAllowed;
3234 }
3235
3236 @Override
3237 public void onRelayoutContainer() {
3238 // Not currently interesting -- from changing between fixed and layout size.
3239 }
3240
3241 public void setFormat(int format) {
3242 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
3243 }
3244
3245 public void setType(int type) {
3246 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
3247 }
3248
3249 @Override
3250 public void onUpdateSurface() {
3251 // We take care of format and type changes on our own.
3252 throw new IllegalStateException("Shouldn't be here");
3253 }
3254
3255 public boolean isCreating() {
3256 return mIsCreating;
3257 }
3258
3259 @Override
3260 public void setFixedSize(int width, int height) {
3261 throw new UnsupportedOperationException(
3262 "Currently only support sizing from layout");
3263 }
3264
3265 public void setKeepScreenOn(boolean screenOn) {
3266 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
3267 }
3268 }
3269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 static class InputMethodCallback extends IInputMethodCallback.Stub {
3271 private WeakReference<ViewRoot> mViewRoot;
3272
3273 public InputMethodCallback(ViewRoot viewRoot) {
3274 mViewRoot = new WeakReference<ViewRoot>(viewRoot);
3275 }
Romain Guy8506ab42009-06-11 17:35:47 -07003276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 public void finishedEvent(int seq, boolean handled) {
3278 final ViewRoot viewRoot = mViewRoot.get();
3279 if (viewRoot != null) {
3280 viewRoot.dispatchFinishedEvent(seq, handled);
3281 }
3282 }
3283
3284 public void sessionCreated(IInputMethodSession session) throws RemoteException {
3285 // Stub -- not for use in the client.
3286 }
3287 }
Romain Guy8506ab42009-06-11 17:35:47 -07003288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 static class W extends IWindow.Stub {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07003290 private final WeakReference<ViewRoot> mViewRoot;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003291
Romain Guyfb8b7632010-08-23 21:05:08 -07003292 W(ViewRoot viewRoot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 mViewRoot = new WeakReference<ViewRoot>(viewRoot);
3294 }
3295
Romain Guyfb8b7632010-08-23 21:05:08 -07003296 public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
3297 boolean reportDraw, Configuration newConfig) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003298 final ViewRoot viewRoot = mViewRoot.get();
3299 if (viewRoot != null) {
Romain Guyfb8b7632010-08-23 21:05:08 -07003300 viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 }
3302 }
3303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 public void dispatchAppVisibility(boolean visible) {
3305 final ViewRoot viewRoot = mViewRoot.get();
3306 if (viewRoot != null) {
3307 viewRoot.dispatchAppVisibility(visible);
3308 }
3309 }
3310
3311 public void dispatchGetNewSurface() {
3312 final ViewRoot viewRoot = mViewRoot.get();
3313 if (viewRoot != null) {
3314 viewRoot.dispatchGetNewSurface();
3315 }
3316 }
3317
3318 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
3319 final ViewRoot viewRoot = mViewRoot.get();
3320 if (viewRoot != null) {
3321 viewRoot.windowFocusChanged(hasFocus, inTouchMode);
3322 }
3323 }
3324
3325 private static int checkCallingPermission(String permission) {
3326 if (!Process.supportsProcesses()) {
3327 return PackageManager.PERMISSION_GRANTED;
3328 }
3329
3330 try {
3331 return ActivityManagerNative.getDefault().checkPermission(
3332 permission, Binder.getCallingPid(), Binder.getCallingUid());
3333 } catch (RemoteException e) {
3334 return PackageManager.PERMISSION_DENIED;
3335 }
3336 }
3337
3338 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
3339 final ViewRoot viewRoot = mViewRoot.get();
3340 if (viewRoot != null) {
3341 final View view = viewRoot.mView;
3342 if (view != null) {
3343 if (checkCallingPermission(Manifest.permission.DUMP) !=
3344 PackageManager.PERMISSION_GRANTED) {
3345 throw new SecurityException("Insufficient permissions to invoke"
3346 + " executeCommand() from pid=" + Binder.getCallingPid()
3347 + ", uid=" + Binder.getCallingUid());
3348 }
3349
3350 OutputStream clientStream = null;
3351 try {
3352 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
3353 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
3354 } catch (IOException e) {
3355 e.printStackTrace();
3356 } finally {
3357 if (clientStream != null) {
3358 try {
3359 clientStream.close();
3360 } catch (IOException e) {
3361 e.printStackTrace();
3362 }
3363 }
3364 }
3365 }
3366 }
3367 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07003368
Dianne Hackbornffa42482009-09-23 22:20:11 -07003369 public void closeSystemDialogs(String reason) {
3370 final ViewRoot viewRoot = mViewRoot.get();
3371 if (viewRoot != null) {
3372 viewRoot.dispatchCloseSystemDialogs(reason);
3373 }
3374 }
3375
Marco Nelissenbf6956b2009-11-09 15:21:13 -08003376 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
3377 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07003378 if (sync) {
3379 try {
3380 sWindowSession.wallpaperOffsetsComplete(asBinder());
3381 } catch (RemoteException e) {
3382 }
3383 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07003384 }
Dianne Hackborn75804932009-10-20 20:15:20 -07003385
3386 public void dispatchWallpaperCommand(String action, int x, int y,
3387 int z, Bundle extras, boolean sync) {
3388 if (sync) {
3389 try {
3390 sWindowSession.wallpaperCommandComplete(asBinder(), null);
3391 } catch (RemoteException e) {
3392 }
3393 }
3394 }
Christopher Tatea53146c2010-09-07 11:57:52 -07003395
3396 /* Drag/drop */
3397 public void dispatchDragEvent(DragEvent event) {
3398 final ViewRoot viewRoot = mViewRoot.get();
3399 if (viewRoot != null) {
3400 viewRoot.dispatchDragEvent(event);
3401 }
3402 }
Joe Onorato664644d2011-01-23 17:53:23 -08003403
3404 @Override
3405 public void dispatchSystemUiVisibilityChanged(int visibility) {
3406 final ViewRoot viewRoot = mViewRoot.get();
3407 if (viewRoot != null) {
3408 viewRoot.dispatchSystemUiVisibilityChanged(visibility);
3409 }
3410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 }
3412
3413 /**
3414 * Maintains state information for a single trackball axis, generating
3415 * discrete (DPAD) movements based on raw trackball motion.
3416 */
3417 static final class TrackballAxis {
3418 /**
3419 * The maximum amount of acceleration we will apply.
3420 */
3421 static final float MAX_ACCELERATION = 20;
Romain Guy8506ab42009-06-11 17:35:47 -07003422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 /**
3424 * The maximum amount of time (in milliseconds) between events in order
3425 * for us to consider the user to be doing fast trackball movements,
3426 * and thus apply an acceleration.
3427 */
3428 static final long FAST_MOVE_TIME = 150;
Romain Guy8506ab42009-06-11 17:35:47 -07003429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 /**
3431 * Scaling factor to the time (in milliseconds) between events to how
3432 * much to multiple/divide the current acceleration. When movement
3433 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
3434 * FAST_MOVE_TIME it divides it.
3435 */
3436 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
Romain Guy8506ab42009-06-11 17:35:47 -07003437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 float position;
3439 float absPosition;
3440 float acceleration = 1;
3441 long lastMoveTime = 0;
3442 int step;
3443 int dir;
3444 int nonAccelMovement;
3445
3446 void reset(int _step) {
3447 position = 0;
3448 acceleration = 1;
3449 lastMoveTime = 0;
3450 step = _step;
3451 dir = 0;
3452 }
3453
3454 /**
3455 * Add trackball movement into the state. If the direction of movement
3456 * has been reversed, the state is reset before adding the
3457 * movement (so that you don't have to compensate for any previously
3458 * collected movement before see the result of the movement in the
3459 * new direction).
3460 *
3461 * @return Returns the absolute value of the amount of movement
3462 * collected so far.
3463 */
3464 float collect(float off, long time, String axis) {
3465 long normTime;
3466 if (off > 0) {
3467 normTime = (long)(off * FAST_MOVE_TIME);
3468 if (dir < 0) {
3469 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
3470 position = 0;
3471 step = 0;
3472 acceleration = 1;
3473 lastMoveTime = 0;
3474 }
3475 dir = 1;
3476 } else if (off < 0) {
3477 normTime = (long)((-off) * FAST_MOVE_TIME);
3478 if (dir > 0) {
3479 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
3480 position = 0;
3481 step = 0;
3482 acceleration = 1;
3483 lastMoveTime = 0;
3484 }
3485 dir = -1;
3486 } else {
3487 normTime = 0;
3488 }
Romain Guy8506ab42009-06-11 17:35:47 -07003489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 // The number of milliseconds between each movement that is
3491 // considered "normal" and will not result in any acceleration
3492 // or deceleration, scaled by the offset we have here.
3493 if (normTime > 0) {
3494 long delta = time - lastMoveTime;
3495 lastMoveTime = time;
3496 float acc = acceleration;
3497 if (delta < normTime) {
3498 // The user is scrolling rapidly, so increase acceleration.
3499 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
3500 if (scale > 1) acc *= scale;
3501 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
3502 + off + " normTime=" + normTime + " delta=" + delta
3503 + " scale=" + scale + " acc=" + acc);
3504 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
3505 } else {
3506 // The user is scrolling slowly, so decrease acceleration.
3507 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
3508 if (scale > 1) acc /= scale;
3509 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
3510 + off + " normTime=" + normTime + " delta=" + delta
3511 + " scale=" + scale + " acc=" + acc);
3512 acceleration = acc > 1 ? acc : 1;
3513 }
3514 }
3515 position += off;
3516 return (absPosition = Math.abs(position));
3517 }
3518
3519 /**
3520 * Generate the number of discrete movement events appropriate for
3521 * the currently collected trackball movement.
3522 *
3523 * @param precision The minimum movement required to generate the
3524 * first discrete movement.
3525 *
3526 * @return Returns the number of discrete movements, either positive
3527 * or negative, or 0 if there is not enough trackball movement yet
3528 * for a discrete movement.
3529 */
3530 int generate(float precision) {
3531 int movement = 0;
3532 nonAccelMovement = 0;
3533 do {
3534 final int dir = position >= 0 ? 1 : -1;
3535 switch (step) {
3536 // If we are going to execute the first step, then we want
3537 // to do this as soon as possible instead of waiting for
3538 // a full movement, in order to make things look responsive.
3539 case 0:
3540 if (absPosition < precision) {
3541 return movement;
3542 }
3543 movement += dir;
3544 nonAccelMovement += dir;
3545 step = 1;
3546 break;
3547 // If we have generated the first movement, then we need
3548 // to wait for the second complete trackball motion before
3549 // generating the second discrete movement.
3550 case 1:
3551 if (absPosition < 2) {
3552 return movement;
3553 }
3554 movement += dir;
3555 nonAccelMovement += dir;
3556 position += dir > 0 ? -2 : 2;
3557 absPosition = Math.abs(position);
3558 step = 2;
3559 break;
3560 // After the first two, we generate discrete movements
3561 // consistently with the trackball, applying an acceleration
3562 // if the trackball is moving quickly. This is a simple
3563 // acceleration on top of what we already compute based
3564 // on how quickly the wheel is being turned, to apply
3565 // a longer increasing acceleration to continuous movement
3566 // in one direction.
3567 default:
3568 if (absPosition < 1) {
3569 return movement;
3570 }
3571 movement += dir;
3572 position += dir >= 0 ? -1 : 1;
3573 absPosition = Math.abs(position);
3574 float acc = acceleration;
3575 acc *= 1.1f;
3576 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
3577 break;
3578 }
3579 } while (true);
3580 }
3581 }
3582
3583 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
3584 public CalledFromWrongThreadException(String msg) {
3585 super(msg);
3586 }
3587 }
3588
3589 private SurfaceHolder mHolder = new SurfaceHolder() {
3590 // we only need a SurfaceHolder for opengl. it would be nice
3591 // to implement everything else though, especially the callback
3592 // support (opengl doesn't make use of it right now, but eventually
3593 // will).
3594 public Surface getSurface() {
3595 return mSurface;
3596 }
3597
3598 public boolean isCreating() {
3599 return false;
3600 }
3601
3602 public void addCallback(Callback callback) {
3603 }
3604
3605 public void removeCallback(Callback callback) {
3606 }
3607
3608 public void setFixedSize(int width, int height) {
3609 }
3610
3611 public void setSizeFromLayout() {
3612 }
3613
3614 public void setFormat(int format) {
3615 }
3616
3617 public void setType(int type) {
3618 }
3619
3620 public void setKeepScreenOn(boolean screenOn) {
3621 }
3622
3623 public Canvas lockCanvas() {
3624 return null;
3625 }
3626
3627 public Canvas lockCanvas(Rect dirty) {
3628 return null;
3629 }
3630
3631 public void unlockCanvasAndPost(Canvas canvas) {
3632 }
3633 public Rect getSurfaceFrame() {
3634 return null;
3635 }
3636 };
3637
3638 static RunQueue getRunQueue() {
3639 RunQueue rq = sRunQueues.get();
3640 if (rq != null) {
3641 return rq;
3642 }
3643 rq = new RunQueue();
3644 sRunQueues.set(rq);
3645 return rq;
3646 }
Romain Guy8506ab42009-06-11 17:35:47 -07003647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 /**
3649 * @hide
3650 */
3651 static final class RunQueue {
3652 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
3653
3654 void post(Runnable action) {
3655 postDelayed(action, 0);
3656 }
3657
3658 void postDelayed(Runnable action, long delayMillis) {
3659 HandlerAction handlerAction = new HandlerAction();
3660 handlerAction.action = action;
3661 handlerAction.delay = delayMillis;
3662
3663 synchronized (mActions) {
3664 mActions.add(handlerAction);
3665 }
3666 }
3667
3668 void removeCallbacks(Runnable action) {
3669 final HandlerAction handlerAction = new HandlerAction();
3670 handlerAction.action = action;
3671
3672 synchronized (mActions) {
3673 final ArrayList<HandlerAction> actions = mActions;
3674
3675 while (actions.remove(handlerAction)) {
3676 // Keep going
3677 }
3678 }
3679 }
3680
3681 void executeActions(Handler handler) {
3682 synchronized (mActions) {
3683 final ArrayList<HandlerAction> actions = mActions;
3684 final int count = actions.size();
3685
3686 for (int i = 0; i < count; i++) {
3687 final HandlerAction handlerAction = actions.get(i);
3688 handler.postDelayed(handlerAction.action, handlerAction.delay);
3689 }
3690
Romain Guy15df6702009-08-17 20:17:30 -07003691 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 }
3693 }
3694
3695 private static class HandlerAction {
3696 Runnable action;
3697 long delay;
3698
3699 @Override
3700 public boolean equals(Object o) {
3701 if (this == o) return true;
3702 if (o == null || getClass() != o.getClass()) return false;
3703
3704 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 return !(action != null ? !action.equals(that.action) : that.action != null);
3706
3707 }
3708
3709 @Override
3710 public int hashCode() {
3711 int result = action != null ? action.hashCode() : 0;
3712 result = 31 * result + (int) (delay ^ (delay >>> 32));
3713 return result;
3714 }
3715 }
3716 }
3717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003718 private static native void nativeShowFPS(Canvas canvas, int durationMillis);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719}