blob: acec4762adf136ea9c5eb41e22bf91009c5bd0ec [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
Dianne Hackborndc8a7f62010-05-10 11:29:34 -070019import com.android.internal.view.BaseSurfaceHolder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import com.android.internal.view.IInputMethodCallback;
21import com.android.internal.view.IInputMethodSession;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -070022import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24import android.graphics.Canvas;
25import android.graphics.PixelFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.graphics.PorterDuff;
27import android.graphics.Rect;
28import android.graphics.Region;
29import android.os.*;
30import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.util.AndroidRuntimeException;
32import android.util.Config;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070033import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.util.Log;
35import android.util.EventLog;
Christopher Tatefa9e7c02010-05-06 12:07:10 -070036import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.util.SparseArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070039import android.view.accessibility.AccessibilityEvent;
40import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.view.inputmethod.InputConnection;
42import android.view.inputmethod.InputMethodManager;
43import android.widget.Scroller;
44import android.content.pm.PackageManager;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070045import android.content.res.CompatibilityInfo;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080046import android.content.res.Configuration;
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -070047import android.content.res.Resources;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080048import android.content.ComponentCallbacks;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.content.Context;
50import android.app.ActivityManagerNative;
51import android.Manifest;
52import android.media.AudioManager;
53
54import java.lang.ref.WeakReference;
55import java.io.IOException;
56import java.io.OutputStream;
57import java.util.ArrayList;
58
59import javax.microedition.khronos.egl.*;
60import javax.microedition.khronos.opengles.*;
61import static javax.microedition.khronos.opengles.GL10.*;
62
63/**
64 * The top of a view hierarchy, implementing the needed protocol between View
65 * and the WindowManager. This is for the most part an internal implementation
66 * detail of {@link WindowManagerImpl}.
67 *
68 * {@hide}
69 */
70@SuppressWarnings({"EmptyCatchBlock"})
71public final class ViewRoot extends Handler implements ViewParent,
72 View.AttachInfo.Callbacks {
73 private static final String TAG = "ViewRoot";
74 private static final boolean DBG = false;
Mike Reedfd716532009-10-12 14:42:56 -040075 private static final boolean SHOW_FPS = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 @SuppressWarnings({"ConstantConditionalExpression"})
77 private static final boolean LOCAL_LOGV = false ? Config.LOGD : Config.LOGV;
78 /** @noinspection PointlessBooleanExpression*/
79 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
80 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Christopher Tatefa9e7c02010-05-06 12:07:10 -070081 private static final boolean DEBUG_INPUT = true || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
83 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
84 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
85 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -070086 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final boolean WATCH_POINTER = false;
88
Michael Chan53071d62009-05-13 17:29:48 -070089 private static final boolean MEASURE_LATENCY = false;
90 private static LatencyTimer lt;
91
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 /**
93 * Maximum time we allow the user to roll the trackball enough to generate
94 * a key event, before resetting the counters.
95 */
96 static final int MAX_TRACKBALL_DELAY = 250;
97
98 static long sInstanceCount = 0;
99
100 static IWindowSession sWindowSession;
101
102 static final Object mStaticInit = new Object();
103 static boolean mInitialized = false;
104
105 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
106
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800107 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
108 static boolean sFirstDrawComplete = false;
109
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800110 static final ArrayList<ComponentCallbacks> sConfigCallbacks
111 = new ArrayList<ComponentCallbacks>();
112
Romain Guy8506ab42009-06-11 17:35:47 -0700113 private static int sDrawTime;
Romain Guy13922e02009-05-12 17:56:14 -0700114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 long mLastTrackballTime = 0;
116 final TrackballAxis mTrackballAxisX = new TrackballAxis();
117 final TrackballAxis mTrackballAxisY = new TrackballAxis();
118
119 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 final InputMethodCallback mInputMethodCallback;
122 final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
123 int mPendingEventSeq = 0;
Romain Guy8506ab42009-06-11 17:35:47 -0700124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 final Thread mThread;
126
127 final WindowLeaked mLocation;
128
129 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
130
131 final W mWindow;
132
133 View mView;
134 View mFocusedView;
135 View mRealFocusedView; // this is not set to null in touch mode
136 int mViewVisibility;
137 boolean mAppVisible = true;
138
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700139 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700140 BaseSurfaceHolder mSurfaceHolder;
141 boolean mIsCreating;
142 boolean mDrawingAllowed;
143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 final Region mTransparentRegion;
145 final Region mPreviousTransparentRegion;
146
147 int mWidth;
148 int mHeight;
149 Rect mDirty; // will be a graphics.Region soon
Romain Guybb93d552009-03-24 21:04:15 -0700150 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700151
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700152 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
154 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700155 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700156 InputQueue.Callback mInputQueueCallback;
157 InputQueue mInputQueue;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 final Rect mTempRect; // used in the transaction to not thrash the heap.
160 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
162 boolean mTraversalScheduled;
163 boolean mWillDrawSoon;
164 boolean mLayoutRequested;
165 boolean mFirst;
166 boolean mReportNextDraw;
167 boolean mFullRedrawNeeded;
168 boolean mNewSurfaceNeeded;
169 boolean mHasHadWindowFocus;
170 boolean mLastWasImTarget;
171
172 boolean mWindowAttributesChanged = false;
173
174 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700175 // Surface can never be reassigned or cleared (use Surface.clear()).
176 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
178 boolean mAdded;
179 boolean mAddedTouchMode;
180
181 /*package*/ int mAddNesting;
182
183 // These are accessed by multiple threads.
184 final Rect mWinFrame; // frame given by window manager.
185
186 final Rect mPendingVisibleInsets = new Rect();
187 final Rect mPendingContentInsets = new Rect();
188 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
189 = new ViewTreeObserver.InternalInsetsInfo();
190
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700191 final Configuration mLastConfiguration = new Configuration();
192 final Configuration mPendingConfiguration = new Configuration();
193
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800194 class ResizedInfo {
195 Rect coveredInsets;
196 Rect visibleInsets;
197 Configuration newConfig;
198 }
199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 boolean mScrollMayChange;
201 int mSoftInputMode;
202 View mLastScrolledFocus;
203 int mScrollY;
204 int mCurScrollY;
205 Scroller mScroller;
Romain Guy8506ab42009-06-11 17:35:47 -0700206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 EGL10 mEgl;
208 EGLDisplay mEglDisplay;
209 EGLContext mEglContext;
210 EGLSurface mEglSurface;
211 GL11 mGL;
212 Canvas mGlCanvas;
213 boolean mUseGL;
214 boolean mGlWanted;
215
Romain Guy8506ab42009-06-11 17:35:47 -0700216 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217
218 /**
219 * see {@link #playSoundEffect(int)}
220 */
221 AudioManager mAudioManager;
222
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700223 private final int mDensity;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700224
Adam Powellb08013c2010-09-16 16:28:11 -0700225 private boolean mHasOverlay;
226
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700227 public static IWindowSession getWindowSession(Looper mainLooper) {
228 synchronized (mStaticInit) {
229 if (!mInitialized) {
230 try {
231 InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
232 sWindowSession = IWindowManager.Stub.asInterface(
233 ServiceManager.getService("window"))
234 .openSession(imm.getClient(), imm.getInputContext());
235 mInitialized = true;
236 } catch (RemoteException e) {
237 }
238 }
239 return sWindowSession;
240 }
241 }
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 public ViewRoot(Context context) {
244 super();
245
Michael Chan53071d62009-05-13 17:29:48 -0700246 if (MEASURE_LATENCY && lt == null) {
247 lt = new LatencyTimer(100, 1000);
248 }
249
Carl Shapiro82fe5642010-02-24 00:14:23 -0800250 // For debug only
251 //++sInstanceCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
253 // Initialize the statics when this class is first instantiated. This is
254 // done here instead of in the static block because Zygote does not
255 // allow the spawning of threads.
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700256 getWindowSession(context.getMainLooper());
257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 mThread = Thread.currentThread();
259 mLocation = new WindowLeaked(null);
260 mLocation.fillInStackTrace();
261 mWidth = -1;
262 mHeight = -1;
263 mDirty = new Rect();
264 mTempRect = new Rect();
265 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 mWinFrame = new Rect();
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700267 mWindow = new W(this, context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 mInputMethodCallback = new InputMethodCallback(this);
269 mViewVisibility = View.GONE;
270 mTransparentRegion = new Region();
271 mPreviousTransparentRegion = new Region();
272 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 mAdded = false;
274 mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
275 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700276 mDensity = context.getResources().getDisplayMetrics().densityDpi;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 }
278
Carl Shapiro82fe5642010-02-24 00:14:23 -0800279 // For debug only
280 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 @Override
282 protected void finalize() throws Throwable {
283 super.finalize();
284 --sInstanceCount;
285 }
Carl Shapiro82fe5642010-02-24 00:14:23 -0800286 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287
288 public static long getInstanceCount() {
289 return sInstanceCount;
290 }
291
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800292 public static void addFirstDrawHandler(Runnable callback) {
293 synchronized (sFirstDrawHandlers) {
294 if (!sFirstDrawComplete) {
295 sFirstDrawHandlers.add(callback);
296 }
297 }
298 }
299
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800300 public static void addConfigCallback(ComponentCallbacks callback) {
301 synchronized (sConfigCallbacks) {
302 sConfigCallbacks.add(callback);
303 }
304 }
305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 // FIXME for perf testing only
307 private boolean mProfile = false;
308
309 /**
310 * Call this to profile the next traversal call.
311 * FIXME for perf testing only. Remove eventually
312 */
313 public void profile() {
314 mProfile = true;
315 }
316
317 /**
318 * Indicates whether we are in touch mode. Calling this method triggers an IPC
319 * call and should be avoided whenever possible.
320 *
321 * @return True, if the device is in touch mode, false otherwise.
322 *
323 * @hide
324 */
325 static boolean isInTouchMode() {
326 if (mInitialized) {
327 try {
328 return sWindowSession.getInTouchMode();
329 } catch (RemoteException e) {
330 }
331 }
332 return false;
333 }
334
335 private void initializeGL() {
336 initializeGLInner();
337 int err = mEgl.eglGetError();
338 if (err != EGL10.EGL_SUCCESS) {
339 // give-up on using GL
340 destroyGL();
341 mGlWanted = false;
342 }
343 }
344
345 private void initializeGLInner() {
346 final EGL10 egl = (EGL10) EGLContext.getEGL();
347 mEgl = egl;
348
349 /*
350 * Get to the default display.
351 */
352 final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
353 mEglDisplay = eglDisplay;
354
355 /*
356 * We can now initialize EGL for that display
357 */
358 int[] version = new int[2];
359 egl.eglInitialize(eglDisplay, version);
360
361 /*
362 * Specify a configuration for our opengl session
363 * and grab the first configuration that matches is
364 */
365 final int[] configSpec = {
366 EGL10.EGL_RED_SIZE, 5,
367 EGL10.EGL_GREEN_SIZE, 6,
368 EGL10.EGL_BLUE_SIZE, 5,
369 EGL10.EGL_DEPTH_SIZE, 0,
370 EGL10.EGL_NONE
371 };
372 final EGLConfig[] configs = new EGLConfig[1];
373 final int[] num_config = new int[1];
374 egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, num_config);
375 final EGLConfig config = configs[0];
376
377 /*
378 * Create an OpenGL ES context. This must be done only once, an
379 * OpenGL context is a somewhat heavy object.
380 */
381 final EGLContext context = egl.eglCreateContext(eglDisplay, config,
382 EGL10.EGL_NO_CONTEXT, null);
383 mEglContext = context;
384
385 /*
386 * Create an EGL surface we can render into.
387 */
388 final EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
389 mEglSurface = surface;
390
391 /*
392 * Before we can issue GL commands, we need to make sure
393 * the context is current and bound to a surface.
394 */
395 egl.eglMakeCurrent(eglDisplay, surface, surface, context);
396
397 /*
398 * Get to the appropriate GL interface.
399 * This is simply done by casting the GL context to either
400 * GL10 or GL11.
401 */
402 final GL11 gl = (GL11) context.getGL();
403 mGL = gl;
404 mGlCanvas = new Canvas(gl);
405 mUseGL = true;
406 }
407
408 private void destroyGL() {
409 // inform skia that the context is gone
410 nativeAbandonGlCaches();
411
412 mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
413 EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
414 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
415 mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
416 mEgl.eglTerminate(mEglDisplay);
417 mEglContext = null;
418 mEglSurface = null;
419 mEglDisplay = null;
420 mEgl = null;
421 mGlCanvas = null;
422 mGL = null;
423 mUseGL = false;
424 }
425
426 private void checkEglErrors() {
427 if (mUseGL) {
428 int err = mEgl.eglGetError();
429 if (err != EGL10.EGL_SUCCESS) {
430 // something bad has happened revert to
431 // normal rendering.
432 destroyGL();
433 if (err != EGL11.EGL_CONTEXT_LOST) {
434 // we'll try again if it was context lost
435 mGlWanted = false;
436 }
437 }
438 }
439 }
440
441 /**
442 * We have one child
443 */
444 public void setView(View view, WindowManager.LayoutParams attrs,
445 View panelParentView) {
446 synchronized (this) {
447 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700448 mView = view;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700449 mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700450 attrs = mWindowAttributes;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700451 if (view instanceof RootViewSurfaceTaker) {
452 mSurfaceHolderCallback =
453 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
454 if (mSurfaceHolderCallback != null) {
455 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700456 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700457 }
458 }
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700459 Resources resources = mView.getContext().getResources();
460 CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo();
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700461 mTranslator = compatibilityInfo.getTranslator();
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700462
463 if (mTranslator != null || !compatibilityInfo.supportsScreen()) {
Mitsuru Oshima240f8a72009-07-22 20:39:14 -0700464 mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(),
465 mTranslator);
Mitsuru Oshima38ed7d772009-07-21 14:39:34 -0700466 }
467
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700468 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700469 if (mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700470 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700471 attrs.backup();
472 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700473 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700474 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
475
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700476 if (!compatibilityInfo.supportsScreen()) {
477 attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
478 }
479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 mSoftInputMode = attrs.softInputMode;
481 mWindowAttributesChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700483 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700484 mAttachInfo.mApplicationScale =
485 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 if (panelParentView != null) {
487 mAttachInfo.mPanelParentWindowToken
488 = panelParentView.getApplicationWindowToken();
489 }
490 mAdded = true;
491 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 // Schedule the first layout -before- adding to the window
494 // manager, to make sure we do the relayout before receiving
495 // any other events from the system.
496 requestLayout();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700497 mInputChannel = new InputChannel();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 try {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700499 res = sWindowSession.add(mWindow, mWindowAttributes,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700500 getHostVisibility(), mAttachInfo.mContentInsets,
501 mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 } catch (RemoteException e) {
503 mAdded = false;
504 mView = null;
505 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700506 mInputChannel = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 unscheduleTraversals();
508 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700509 } finally {
510 if (restore) {
511 attrs.restore();
512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700514
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700515 if (mTranslator != null) {
516 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 mPendingContentInsets.set(mAttachInfo.mContentInsets);
519 mPendingVisibleInsets.set(0, 0, 0, 0);
Jeff Brownc5ed5912010-07-14 18:48:53 -0700520 if (Config.LOGV) Log.v(TAG, "Added window " + mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 if (res < WindowManagerImpl.ADD_OKAY) {
522 mView = null;
523 mAttachInfo.mRootView = null;
524 mAdded = false;
525 unscheduleTraversals();
526 switch (res) {
527 case WindowManagerImpl.ADD_BAD_APP_TOKEN:
528 case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
529 throw new WindowManagerImpl.BadTokenException(
530 "Unable to add window -- token " + attrs.token
531 + " is not valid; is your activity running?");
532 case WindowManagerImpl.ADD_NOT_APP_TOKEN:
533 throw new WindowManagerImpl.BadTokenException(
534 "Unable to add window -- token " + attrs.token
535 + " is not for an application");
536 case WindowManagerImpl.ADD_APP_EXITING:
537 throw new WindowManagerImpl.BadTokenException(
538 "Unable to add window -- app for token " + attrs.token
539 + " is exiting");
540 case WindowManagerImpl.ADD_DUPLICATE_ADD:
541 throw new WindowManagerImpl.BadTokenException(
542 "Unable to add window -- window " + mWindow
543 + " has already been added");
544 case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
545 // Silently ignore -- we would have just removed it
546 // right away, anyway.
547 return;
548 case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
549 throw new WindowManagerImpl.BadTokenException(
550 "Unable to add window " + mWindow +
551 " -- another window of this type already exists");
552 case WindowManagerImpl.ADD_PERMISSION_DENIED:
553 throw new WindowManagerImpl.BadTokenException(
554 "Unable to add window " + mWindow +
555 " -- permission denied for this window type");
556 }
557 throw new RuntimeException(
558 "Unable to add window -- unknown error code " + res);
559 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700560
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700561 if (view instanceof RootViewSurfaceTaker) {
562 mInputQueueCallback =
563 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
564 }
565 if (mInputQueueCallback != null) {
566 mInputQueue = new InputQueue(mInputChannel);
567 mInputQueueCallback.onInputQueueCreated(mInputQueue);
568 } else {
569 InputQueue.registerInputChannel(mInputChannel, mInputHandler,
570 Looper.myQueue());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700571 }
572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 view.assignParent(this);
574 mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
575 mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
576 }
577 }
578 }
579
580 public View getView() {
581 return mView;
582 }
583
584 final WindowLeaked getLocation() {
585 return mLocation;
586 }
587
588 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
589 synchronized (this) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700590 int oldSoftInputMode = mWindowAttributes.softInputMode;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700591 // preserve compatible window flag if exists.
592 int compatibleWindowFlag =
593 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 mWindowAttributes.copyFrom(attrs);
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -0700595 mWindowAttributes.flags |= compatibleWindowFlag;
596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 if (newView) {
598 mSoftInputMode = attrs.softInputMode;
599 requestLayout();
600 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700601 // Don't lose the mode we last auto-computed.
602 if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
603 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
604 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
605 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
606 | (oldSoftInputMode
607 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 mWindowAttributesChanged = true;
610 scheduleTraversals();
611 }
612 }
613
614 void handleAppVisibility(boolean visible) {
615 if (mAppVisible != visible) {
616 mAppVisible = visible;
617 scheduleTraversals();
618 }
619 }
620
621 void handleGetNewSurface() {
622 mNewSurfaceNeeded = true;
623 mFullRedrawNeeded = true;
624 scheduleTraversals();
625 }
626
627 /**
628 * {@inheritDoc}
629 */
630 public void requestLayout() {
631 checkThread();
632 mLayoutRequested = true;
633 scheduleTraversals();
634 }
635
636 /**
637 * {@inheritDoc}
638 */
639 public boolean isLayoutRequested() {
640 return mLayoutRequested;
641 }
642
643 public void invalidateChild(View child, Rect dirty) {
644 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700645 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
646 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700648 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700649 if (mCurScrollY != 0) {
Romain Guy1e095972009-07-07 11:22:45 -0700650 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700651 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700652 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700653 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700654 }
Romain Guy1e095972009-07-07 11:22:45 -0700655 if (mAttachInfo.mScalingRequired) {
656 dirty.inset(-1, -1);
657 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 }
659 mDirty.union(dirty);
660 if (!mWillDrawSoon) {
661 scheduleTraversals();
662 }
663 }
664
665 public ViewParent getParent() {
666 return null;
667 }
668
669 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
670 invalidateChild(null, dirty);
671 return null;
672 }
673
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700674 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 if (child != mView) {
676 throw new RuntimeException("child is not mine, honest!");
677 }
678 // Note: don't apply scroll offset, because we want to know its
679 // visibility in the virtual canvas being given to the view hierarchy.
680 return r.intersect(0, 0, mWidth, mHeight);
681 }
682
683 public void bringChildToFront(View child) {
684 }
685
686 public void scheduleTraversals() {
687 if (!mTraversalScheduled) {
688 mTraversalScheduled = true;
689 sendEmptyMessage(DO_TRAVERSAL);
690 }
691 }
692
693 public void unscheduleTraversals() {
694 if (mTraversalScheduled) {
695 mTraversalScheduled = false;
696 removeMessages(DO_TRAVERSAL);
697 }
698 }
699
700 int getHostVisibility() {
701 return mAppVisible ? mView.getVisibility() : View.GONE;
702 }
Romain Guy8506ab42009-06-11 17:35:47 -0700703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 private void performTraversals() {
705 // cache mView since it is used so much below...
706 final View host = mView;
707
708 if (DBG) {
709 System.out.println("======================================");
710 System.out.println("performTraversals");
711 host.debug();
712 }
713
714 if (host == null || !mAdded)
715 return;
716
717 mTraversalScheduled = false;
718 mWillDrawSoon = true;
719 boolean windowResizesToFitContent = false;
720 boolean fullRedrawNeeded = mFullRedrawNeeded;
721 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700722 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 WindowManager.LayoutParams lp = mWindowAttributes;
724
725 int desiredWindowWidth;
726 int desiredWindowHeight;
727 int childWidthMeasureSpec;
728 int childHeightMeasureSpec;
729
730 final View.AttachInfo attachInfo = mAttachInfo;
731
732 final int viewVisibility = getHostVisibility();
733 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
734 || mNewSurfaceNeeded;
735
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700736 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 WindowManager.LayoutParams params = null;
739 if (mWindowAttributesChanged) {
740 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700741 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 params = lp;
743 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700744 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 if (mFirst) {
746 fullRedrawNeeded = true;
747 mLayoutRequested = true;
748
Romain Guy8506ab42009-06-11 17:35:47 -0700749 DisplayMetrics packageMetrics =
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700750 mView.getContext().getResources().getDisplayMetrics();
751 desiredWindowWidth = packageMetrics.widthPixels;
752 desiredWindowHeight = packageMetrics.heightPixels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753
754 // For the very first time, tell the view hierarchy that it
755 // is attached to the window. Note that at this point the surface
756 // object is not initialized to its backing store, but soon it
757 // will be (assuming the window is visible).
758 attachInfo.mSurface = mSurface;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700759 attachInfo.mTranslucentWindow = PixelFormat.formatHasAlpha(lp.format);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 attachInfo.mHasWindowFocus = false;
761 attachInfo.mWindowVisibility = viewVisibility;
762 attachInfo.mRecomputeGlobalAttributes = false;
763 attachInfo.mKeepScreenOn = false;
764 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700765 mLastConfiguration.setTo(host.getResources().getConfiguration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 host.dispatchAttachedToWindow(attachInfo, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -0700768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700770 desiredWindowWidth = frame.width();
771 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700773 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700774 "View " + host + " resized to: " + frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 fullRedrawNeeded = true;
776 mLayoutRequested = true;
777 windowResizesToFitContent = true;
778 }
779 }
780
781 if (viewVisibilityChanged) {
782 attachInfo.mWindowVisibility = viewVisibility;
783 host.dispatchWindowVisibilityChanged(viewVisibility);
784 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
785 if (mUseGL) {
786 destroyGL();
787 }
788 }
789 if (viewVisibility == View.GONE) {
790 // After making a window gone, we will count it as being
791 // shown for the first time the next time it gets focus.
792 mHasHadWindowFocus = false;
793 }
794 }
795
796 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -0700797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 if (mLayoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -0700799 // Execute enqueued actions on every layout in case a view that was detached
800 // enqueued an action after being detached
801 getRunQueue().executeActions(attachInfo.mHandler);
802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 if (mFirst) {
804 host.fitSystemWindows(mAttachInfo.mContentInsets);
805 // make sure touch mode code executes by setting cached value
806 // to opposite of the added touch mode.
807 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -0700808 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 } else {
810 if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
811 mAttachInfo.mContentInsets.set(mPendingContentInsets);
812 host.fitSystemWindows(mAttachInfo.mContentInsets);
813 insetsChanged = true;
814 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
815 + mAttachInfo.mContentInsets);
816 }
817 if (!mAttachInfo.mVisibleInsets.equals(mPendingVisibleInsets)) {
818 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
819 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
820 + mAttachInfo.mVisibleInsets);
821 }
822 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
823 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
824 windowResizesToFitContent = true;
825
Romain Guy8506ab42009-06-11 17:35:47 -0700826 DisplayMetrics packageMetrics =
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700827 mView.getContext().getResources().getDisplayMetrics();
828 desiredWindowWidth = packageMetrics.widthPixels;
829 desiredWindowHeight = packageMetrics.heightPixels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
831 }
832
833 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
834 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
835
836 // Ask host how big it wants to be
Jeff Brownc5ed5912010-07-14 18:48:53 -0700837 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 "Measuring " + host + " in display " + desiredWindowWidth
839 + "x" + desiredWindowHeight + "...");
840 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
841
842 if (DBG) {
843 System.out.println("======================================");
844 System.out.println("performTraversals -- after measure");
845 host.debug();
846 }
847 }
848
849 if (attachInfo.mRecomputeGlobalAttributes) {
850 //Log.i(TAG, "Computing screen on!");
851 attachInfo.mRecomputeGlobalAttributes = false;
852 boolean oldVal = attachInfo.mKeepScreenOn;
853 attachInfo.mKeepScreenOn = false;
854 host.dispatchCollectViewAttributes(0);
855 if (attachInfo.mKeepScreenOn != oldVal) {
856 params = lp;
857 //Log.i(TAG, "Keep screen on changed: " + attachInfo.mKeepScreenOn);
858 }
859 }
860
861 if (mFirst || attachInfo.mViewVisibilityChanged) {
862 attachInfo.mViewVisibilityChanged = false;
863 int resizeMode = mSoftInputMode &
864 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
865 // If we are in auto resize mode, then we need to determine
866 // what mode to use now.
867 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
868 final int N = attachInfo.mScrollContainers.size();
869 for (int i=0; i<N; i++) {
870 if (attachInfo.mScrollContainers.get(i).isShown()) {
871 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
872 }
873 }
874 if (resizeMode == 0) {
875 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
876 }
877 if ((lp.softInputMode &
878 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
879 lp.softInputMode = (lp.softInputMode &
880 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
881 resizeMode;
882 params = lp;
883 }
884 }
885 }
Romain Guy8506ab42009-06-11 17:35:47 -0700886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
888 if (!PixelFormat.formatHasAlpha(params.format)) {
889 params.format = PixelFormat.TRANSLUCENT;
890 }
891 }
892
893 boolean windowShouldResize = mLayoutRequested && windowResizesToFitContent
Romain Guy2e4f4262010-04-06 11:07:52 -0700894 && ((mWidth != host.mMeasuredWidth || mHeight != host.mMeasuredHeight)
895 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
896 frame.width() < desiredWindowWidth && frame.width() != mWidth)
897 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
898 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899
900 final boolean computesInternalInsets =
901 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
902 boolean insetsPending = false;
903 int relayoutResult = 0;
904 if (mFirst || windowShouldResize || insetsChanged
905 || viewVisibilityChanged || params != null) {
906
907 if (viewVisibility == View.VISIBLE) {
908 // If this window is giving internal insets to the window
909 // manager, and it is being added or changing its visibility,
910 // then we want to first give the window manager "fake"
911 // insets to cause it to effectively ignore the content of
912 // the window during layout. This avoids it briefly causing
913 // other windows to resize/move based on the raw frame of the
914 // window, waiting until we can finish laying out this window
915 // and get back to the window manager with the ultimately
916 // computed insets.
917 insetsPending = computesInternalInsets
918 && (mFirst || viewVisibilityChanged);
Romain Guy8506ab42009-06-11 17:35:47 -0700919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
921 if (params == null) {
922 params = mWindowAttributes;
923 }
924 mGlWanted = true;
925 }
926 }
927
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700928 if (mSurfaceHolder != null) {
929 mSurfaceHolder.mSurfaceLock.lock();
930 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700931 }
932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 boolean initialized = false;
934 boolean contentInsetsChanged = false;
Romain Guy13922e02009-05-12 17:56:14 -0700935 boolean visibleInsetsChanged;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700936 boolean hadSurface = mSurface.isValid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 int fl = 0;
939 if (params != null) {
940 fl = params.flags;
941 if (attachInfo.mKeepScreenOn) {
942 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
943 }
944 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700945 if (DEBUG_LAYOUT) {
946 Log.i(TAG, "host=w:" + host.mMeasuredWidth + ", h:" +
947 host.mMeasuredHeight + ", params=" + params);
948 }
949 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
950
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 if (params != null) {
952 params.flags = fl;
953 }
954
955 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
956 + " content=" + mPendingContentInsets.toShortString()
957 + " visible=" + mPendingVisibleInsets.toShortString()
958 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -0700959
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700960 if (mPendingConfiguration.seq != 0) {
961 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
962 + mPendingConfiguration);
963 updateConfiguration(mPendingConfiguration, !mFirst);
964 mPendingConfiguration.seq = 0;
965 }
966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 contentInsetsChanged = !mPendingContentInsets.equals(
968 mAttachInfo.mContentInsets);
969 visibleInsetsChanged = !mPendingVisibleInsets.equals(
970 mAttachInfo.mVisibleInsets);
971 if (contentInsetsChanged) {
972 mAttachInfo.mContentInsets.set(mPendingContentInsets);
973 host.fitSystemWindows(mAttachInfo.mContentInsets);
974 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
975 + mAttachInfo.mContentInsets);
976 }
977 if (visibleInsetsChanged) {
978 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
979 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
980 + mAttachInfo.mVisibleInsets);
981 }
982
983 if (!hadSurface) {
984 if (mSurface.isValid()) {
985 // If we are creating a new surface, then we need to
986 // completely redraw it. Also, when we get to the
987 // point of drawing it we will hold off and schedule
988 // a new traversal instead. This is so we can tell the
989 // window manager about all of the windows being displayed
990 // before actually drawing them, so it can display then
991 // all at once.
992 newSurface = true;
993 fullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -0700994 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -0700995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 if (mGlWanted && !mUseGL) {
997 initializeGL();
998 initialized = mGlCanvas != null;
999 }
1000 }
1001 } else if (!mSurface.isValid()) {
1002 // If the surface has been removed, then reset the scroll
1003 // positions.
1004 mLastScrolledFocus = null;
1005 mScrollY = mCurScrollY = 0;
1006 if (mScroller != null) {
1007 mScroller.abortAnimation();
1008 }
1009 }
1010 } catch (RemoteException e) {
1011 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001014 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015
1016 attachInfo.mWindowLeft = frame.left;
1017 attachInfo.mWindowTop = frame.top;
1018
1019 // !!FIXME!! This next section handles the case where we did not get the
1020 // window size we asked for. We should avoid this by getting a maximum size from
1021 // the window session beforehand.
1022 mWidth = frame.width();
1023 mHeight = frame.height();
1024
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001025 if (mSurfaceHolder != null) {
1026 // The app owns the surface; tell it about what is going on.
1027 if (mSurface.isValid()) {
1028 // XXX .copyFrom() doesn't work!
1029 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1030 mSurfaceHolder.mSurface = mSurface;
1031 }
1032 mSurfaceHolder.mSurfaceLock.unlock();
1033 if (mSurface.isValid()) {
1034 if (!hadSurface) {
1035 mSurfaceHolder.ungetCallbacks();
1036
1037 mIsCreating = true;
1038 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1039 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1040 if (callbacks != null) {
1041 for (SurfaceHolder.Callback c : callbacks) {
1042 c.surfaceCreated(mSurfaceHolder);
1043 }
1044 }
1045 surfaceChanged = true;
1046 }
1047 if (surfaceChanged) {
1048 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1049 lp.format, mWidth, mHeight);
1050 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1051 if (callbacks != null) {
1052 for (SurfaceHolder.Callback c : callbacks) {
1053 c.surfaceChanged(mSurfaceHolder, lp.format,
1054 mWidth, mHeight);
1055 }
1056 }
1057 }
1058 mIsCreating = false;
1059 } else if (hadSurface) {
1060 mSurfaceHolder.ungetCallbacks();
1061 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1062 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1063 if (callbacks != null) {
1064 for (SurfaceHolder.Callback c : callbacks) {
1065 c.surfaceDestroyed(mSurfaceHolder);
1066 }
1067 }
1068 mSurfaceHolder.mSurfaceLock.lock();
1069 // Make surface invalid.
1070 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1071 mSurfaceHolder.mSurface = new Surface();
1072 mSurfaceHolder.mSurfaceLock.unlock();
1073 }
1074 }
1075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 if (initialized) {
Mitsuru Oshima61324e52009-07-21 15:40:36 -07001077 mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
1078 (int) (mHeight * appScale + 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 }
1080
1081 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Romain Guy2d4cff62010-04-09 15:39:00 -07001082 (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 if (focusChangedDueToTouchMode || mWidth != host.mMeasuredWidth
1084 || mHeight != host.mMeasuredHeight || contentInsetsChanged) {
1085 childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1086 childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
1087
1088 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1089 + mWidth + " measuredWidth=" + host.mMeasuredWidth
1090 + " mHeight=" + mHeight
1091 + " measuredHeight" + host.mMeasuredHeight
1092 + " coveredInsetsChanged=" + contentInsetsChanged);
Romain Guy8506ab42009-06-11 17:35:47 -07001093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 // Ask host how big it wants to be
1095 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1096
1097 // Implementation of weights from WindowManager.LayoutParams
1098 // We just grow the dimensions as needed and re-measure if
1099 // needs be
1100 int width = host.mMeasuredWidth;
1101 int height = host.mMeasuredHeight;
1102 boolean measureAgain = false;
1103
1104 if (lp.horizontalWeight > 0.0f) {
1105 width += (int) ((mWidth - width) * lp.horizontalWeight);
1106 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1107 MeasureSpec.EXACTLY);
1108 measureAgain = true;
1109 }
1110 if (lp.verticalWeight > 0.0f) {
1111 height += (int) ((mHeight - height) * lp.verticalWeight);
1112 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1113 MeasureSpec.EXACTLY);
1114 measureAgain = true;
1115 }
1116
1117 if (measureAgain) {
1118 if (DEBUG_LAYOUT) Log.v(TAG,
1119 "And hey let's measure once more: width=" + width
1120 + " height=" + height);
1121 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1122 }
1123
1124 mLayoutRequested = true;
1125 }
1126 }
1127
1128 final boolean didLayout = mLayoutRequested;
1129 boolean triggerGlobalLayoutListener = didLayout
1130 || attachInfo.mRecomputeGlobalAttributes;
1131 if (didLayout) {
1132 mLayoutRequested = false;
1133 mScrollMayChange = true;
1134 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001135 TAG, "Laying out " + host + " to (" +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
Romain Guy13922e02009-05-12 17:56:14 -07001137 long startTime = 0L;
1138 if (Config.DEBUG && ViewDebug.profileLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 startTime = SystemClock.elapsedRealtime();
1140 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
1142
Romain Guy13922e02009-05-12 17:56:14 -07001143 if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
1144 if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
1145 throw new IllegalStateException("The view hierarchy is an inconsistent state,"
1146 + "please refer to the logs with the tag "
1147 + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
1148 }
1149 }
1150
1151 if (Config.DEBUG && ViewDebug.profileLayout) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
1153 }
1154
1155 // By this point all views have been sized and positionned
1156 // We can compute the transparent area
1157
1158 if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
1159 // start out transparent
1160 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1161 host.getLocationInWindow(mTmpLocation);
1162 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1163 mTmpLocation[0] + host.mRight - host.mLeft,
1164 mTmpLocation[1] + host.mBottom - host.mTop);
1165
1166 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001167 if (mTranslator != null) {
1168 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1169 }
1170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1172 mPreviousTransparentRegion.set(mTransparentRegion);
1173 // reconfigure window manager
1174 try {
1175 sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
1176 } catch (RemoteException e) {
1177 }
1178 }
1179 }
1180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 if (DBG) {
1182 System.out.println("======================================");
1183 System.out.println("performTraversals -- after setFrame");
1184 host.debug();
1185 }
1186 }
1187
1188 if (triggerGlobalLayoutListener) {
1189 attachInfo.mRecomputeGlobalAttributes = false;
1190 attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1191 }
1192
1193 if (computesInternalInsets) {
1194 ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1195 final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets;
1196 final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets;
1197 givenContent.left = givenContent.top = givenContent.right
1198 = givenContent.bottom = givenVisible.left = givenVisible.top
1199 = givenVisible.right = givenVisible.bottom = 0;
1200 attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001201 Rect contentInsets = insets.contentInsets;
1202 Rect visibleInsets = insets.visibleInsets;
1203 if (mTranslator != null) {
1204 contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
1205 visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1208 mLastGivenInsets.set(insets);
1209 try {
1210 sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001211 contentInsets, visibleInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 } catch (RemoteException e) {
1213 }
1214 }
1215 }
Romain Guy8506ab42009-06-11 17:35:47 -07001216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 if (mFirst) {
1218 // handle first focus request
1219 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1220 + mView.hasFocus());
1221 if (mView != null) {
1222 if (!mView.hasFocus()) {
1223 mView.requestFocus(View.FOCUS_FORWARD);
1224 mFocusedView = mRealFocusedView = mView.findFocus();
1225 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
1226 + mFocusedView);
1227 } else {
1228 mRealFocusedView = mView.findFocus();
1229 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
1230 + mRealFocusedView);
1231 }
1232 }
1233 }
1234
1235 mFirst = false;
1236 mWillDrawSoon = false;
1237 mNewSurfaceNeeded = false;
1238 mViewVisibility = viewVisibility;
1239
1240 if (mAttachInfo.mHasWindowFocus) {
1241 final boolean imTarget = WindowManager.LayoutParams
1242 .mayUseInputMethod(mWindowAttributes.flags);
1243 if (imTarget != mLastWasImTarget) {
1244 mLastWasImTarget = imTarget;
1245 InputMethodManager imm = InputMethodManager.peekInstance();
1246 if (imm != null && imTarget) {
1247 imm.startGettingWindowFocus(mView);
1248 imm.onWindowFocus(mView, mView.findFocus(),
1249 mWindowAttributes.softInputMode,
1250 !mHasHadWindowFocus, mWindowAttributes.flags);
1251 }
1252 }
1253 }
Romain Guy8506ab42009-06-11 17:35:47 -07001254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
1256
1257 if (!cancelDraw && !newSurface) {
1258 mFullRedrawNeeded = false;
1259 draw(fullRedrawNeeded);
1260
1261 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
1262 || mReportNextDraw) {
1263 if (LOCAL_LOGV) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001264 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
1266 mReportNextDraw = false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001267 if (mSurfaceHolder != null && mSurface.isValid()) {
1268 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
1269 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1270 if (callbacks != null) {
1271 for (SurfaceHolder.Callback c : callbacks) {
1272 if (c instanceof SurfaceHolder.Callback2) {
1273 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
1274 mSurfaceHolder);
1275 }
1276 }
1277 }
1278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 try {
1280 sWindowSession.finishDrawing(mWindow);
1281 } catch (RemoteException e) {
1282 }
1283 }
1284 } else {
1285 // We were supposed to report when we are done drawing. Since we canceled the
1286 // draw, remember it here.
1287 if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
1288 mReportNextDraw = true;
1289 }
1290 if (fullRedrawNeeded) {
1291 mFullRedrawNeeded = true;
1292 }
1293 // Try again
1294 scheduleTraversals();
1295 }
1296 }
1297
1298 public void requestTransparentRegion(View child) {
1299 // the test below should not fail unless someone is messing with us
1300 checkThread();
1301 if (mView == child) {
1302 mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
1303 // Need to make sure we re-evaluate the window attributes next
1304 // time around, to ensure the window has the correct format.
1305 mWindowAttributesChanged = true;
1306 }
1307 }
1308
1309 /**
1310 * Figures out the measure spec for the root view in a window based on it's
1311 * layout params.
1312 *
1313 * @param windowSize
1314 * The available width or height of the window
1315 *
1316 * @param rootDimension
1317 * The layout params for one dimension (width or height) of the
1318 * window.
1319 *
1320 * @return The measure spec to use to measure the root view.
1321 */
1322 private int getRootMeasureSpec(int windowSize, int rootDimension) {
1323 int measureSpec;
1324 switch (rootDimension) {
1325
Romain Guy980a9382010-01-08 15:06:28 -08001326 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 // Window can't resize. Force root view to be windowSize.
1328 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
1329 break;
1330 case ViewGroup.LayoutParams.WRAP_CONTENT:
1331 // Window can resize. Set max size for root view.
1332 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
1333 break;
1334 default:
1335 // Window wants to be an exact size. Force root view to be that size.
1336 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
1337 break;
1338 }
1339 return measureSpec;
1340 }
1341
1342 private void draw(boolean fullRedrawNeeded) {
1343 Surface surface = mSurface;
1344 if (surface == null || !surface.isValid()) {
1345 return;
1346 }
1347
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08001348 if (!sFirstDrawComplete) {
1349 synchronized (sFirstDrawHandlers) {
1350 sFirstDrawComplete = true;
1351 for (int i=0; i<sFirstDrawHandlers.size(); i++) {
1352 post(sFirstDrawHandlers.get(i));
1353 }
1354 }
1355 }
1356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 scrollToRectOrFocus(null, false);
1358
1359 if (mAttachInfo.mViewScrollChanged) {
1360 mAttachInfo.mViewScrollChanged = false;
1361 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
1362 }
Romain Guy8506ab42009-06-11 17:35:47 -07001363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 int yoff;
Romain Guy5bcdff42009-05-14 21:27:18 -07001365 final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 if (scrolling) {
1367 yoff = mScroller.getCurrY();
1368 } else {
1369 yoff = mScrollY;
1370 }
1371 if (mCurScrollY != yoff) {
1372 mCurScrollY = yoff;
1373 fullRedrawNeeded = true;
1374 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001375 float appScale = mAttachInfo.mApplicationScale;
1376 boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377
1378 Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001379 if (mSurfaceHolder != null) {
1380 // The app owns the surface, we won't draw.
1381 dirty.setEmpty();
1382 return;
1383 }
1384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 if (mUseGL) {
1386 if (!dirty.isEmpty()) {
1387 Canvas canvas = mGlCanvas;
Romain Guy5bcdff42009-05-14 21:27:18 -07001388 if (mGL != null && canvas != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 mGL.glDisable(GL_SCISSOR_TEST);
1390 mGL.glClearColor(0, 0, 0, 0);
1391 mGL.glClear(GL_COLOR_BUFFER_BIT);
1392 mGL.glEnable(GL_SCISSOR_TEST);
1393
1394 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
Romain Guy5bcdff42009-05-14 21:27:18 -07001395 mAttachInfo.mIgnoreDirtyState = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 mView.mPrivateFlags |= View.DRAWN;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001397
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001398 int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
1399 try {
1400 canvas.translate(0, -yoff);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001401 if (mTranslator != null) {
1402 mTranslator.translateCanvas(canvas);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001403 }
Dianne Hackborn0d221012009-07-29 15:41:19 -07001404 canvas.setScreenDensity(scalingRequired
1405 ? DisplayMetrics.DENSITY_DEVICE : 0);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001406 mView.draw(canvas);
Romain Guy13922e02009-05-12 17:56:14 -07001407 if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
1408 mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
1409 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001410 } finally {
1411 canvas.restoreToCount(saveCount);
1412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413
Romain Guy5bcdff42009-05-14 21:27:18 -07001414 mAttachInfo.mIgnoreDirtyState = false;
1415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
1417 checkEglErrors();
1418
Mike Reedfd716532009-10-12 14:42:56 -04001419 if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 int now = (int)SystemClock.elapsedRealtime();
1421 if (sDrawTime != 0) {
1422 nativeShowFPS(canvas, now - sDrawTime);
1423 }
1424 sDrawTime = now;
1425 }
1426 }
1427 }
1428 if (scrolling) {
1429 mFullRedrawNeeded = true;
1430 scheduleTraversals();
1431 }
1432 return;
1433 }
1434
Romain Guy5bcdff42009-05-14 21:27:18 -07001435 if (fullRedrawNeeded) {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001436 mAttachInfo.mIgnoreDirtyState = true;
Mitsuru Oshima61324e52009-07-21 15:40:36 -07001437 dirty.union(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy5bcdff42009-05-14 21:27:18 -07001438 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439
1440 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001441 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 + mWindowAttributes.getTitle()
1443 + ": dirty={" + dirty.left + "," + dirty.top
1444 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001445 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
1446 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 }
1448
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001449 if (!dirty.isEmpty() || mIsAnimating) {
1450 Canvas canvas;
1451 try {
1452 int left = dirty.left;
1453 int top = dirty.top;
1454 int right = dirty.right;
1455 int bottom = dirty.bottom;
1456 canvas = surface.lockCanvas(dirty);
Romain Guy5bcdff42009-05-14 21:27:18 -07001457
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001458 if (left != dirty.left || top != dirty.top || right != dirty.right ||
1459 bottom != dirty.bottom) {
1460 mAttachInfo.mIgnoreDirtyState = true;
1461 }
1462
1463 // TODO: Do this in native
1464 canvas.setDensity(mDensity);
1465 } catch (Surface.OutOfResourcesException e) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001466 Log.e(TAG, "OutOfResourcesException locking surface", e);
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001467 // TODO: we should ask the window manager to do something!
1468 // for now we just do nothing
1469 return;
1470 } catch (IllegalArgumentException e) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001471 Log.e(TAG, "IllegalArgumentException locking surface", e);
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001472 // TODO: we should ask the window manager to do something!
1473 // for now we just do nothing
1474 return;
Romain Guy5bcdff42009-05-14 21:27:18 -07001475 }
1476
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001477 try {
1478 if (!dirty.isEmpty() || mIsAnimating) {
1479 long startTime = 0L;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001481 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001482 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001483 + canvas.getWidth() + ", h=" + canvas.getHeight());
1484 //canvas.drawARGB(255, 255, 0, 0);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001487 if (Config.DEBUG && ViewDebug.profileDrawing) {
1488 startTime = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001490
1491 // If this bitmap's format includes an alpha channel, we
1492 // need to clear it before drawing so that the child will
1493 // properly re-composite its drawing on a transparent
1494 // background. This automatically respects the clip/dirty region
1495 // or
1496 // If we are applying an offset, we need to clear the area
1497 // where the offset doesn't appear to avoid having garbage
1498 // left in the blank areas.
1499 if (!canvas.isOpaque() || yoff != 0) {
1500 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
1501 }
1502
1503 dirty.setEmpty();
1504 mIsAnimating = false;
1505 mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
1506 mView.mPrivateFlags |= View.DRAWN;
1507
1508 if (DEBUG_DRAW) {
1509 Context cxt = mView.getContext();
1510 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
1511 ", metrics=" + cxt.getResources().getDisplayMetrics() +
1512 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
1513 }
1514 int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
1515 try {
1516 canvas.translate(0, -yoff);
1517 if (mTranslator != null) {
1518 mTranslator.translateCanvas(canvas);
1519 }
1520 canvas.setScreenDensity(scalingRequired
1521 ? DisplayMetrics.DENSITY_DEVICE : 0);
1522 mView.draw(canvas);
Adam Powellb08013c2010-09-16 16:28:11 -07001523 if (mHasOverlay) {
1524 mView.onDrawOverlay(canvas);
1525 }
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001526 } finally {
1527 mAttachInfo.mIgnoreDirtyState = false;
1528 canvas.restoreToCount(saveCount);
1529 }
1530
1531 if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
1532 mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
1533 }
1534
1535 if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) {
1536 int now = (int)SystemClock.elapsedRealtime();
1537 if (sDrawTime != 0) {
1538 nativeShowFPS(canvas, now - sDrawTime);
1539 }
1540 sDrawTime = now;
1541 }
1542
1543 if (Config.DEBUG && ViewDebug.profileDrawing) {
1544 EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
1545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 }
1547
Mathias Agopiana62b09a2010-04-21 18:36:53 -07001548 } finally {
1549 surface.unlockCanvasAndPost(canvas);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 }
1552
1553 if (LOCAL_LOGV) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001554 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
Romain Guy8506ab42009-06-11 17:35:47 -07001556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 if (scrolling) {
1558 mFullRedrawNeeded = true;
1559 scheduleTraversals();
1560 }
1561 }
1562
1563 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
1564 final View.AttachInfo attachInfo = mAttachInfo;
1565 final Rect ci = attachInfo.mContentInsets;
1566 final Rect vi = attachInfo.mVisibleInsets;
1567 int scrollY = 0;
1568 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 if (vi.left > ci.left || vi.top > ci.top
1571 || vi.right > ci.right || vi.bottom > ci.bottom) {
1572 // We'll assume that we aren't going to change the scroll
1573 // offset, since we want to avoid that unless it is actually
1574 // going to make the focus visible... otherwise we scroll
1575 // all over the place.
1576 scrollY = mScrollY;
1577 // We can be called for two different situations: during a draw,
1578 // to update the scroll position if the focus has changed (in which
1579 // case 'rectangle' is null), or in response to a
1580 // requestChildRectangleOnScreen() call (in which case 'rectangle'
1581 // is non-null and we just want to scroll to whatever that
1582 // rectangle is).
1583 View focus = mRealFocusedView;
Romain Guye8b16522009-07-14 13:06:42 -07001584
1585 // When in touch mode, focus points to the previously focused view,
1586 // which may have been removed from the view hierarchy. The following
Joe Onoratob71193b2009-11-24 18:34:42 -05001587 // line checks whether the view is still in our hierarchy.
1588 if (focus == null || focus.mAttachInfo != mAttachInfo) {
Romain Guye8b16522009-07-14 13:06:42 -07001589 mRealFocusedView = null;
1590 return false;
1591 }
1592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 if (focus != mLastScrolledFocus) {
1594 // If the focus has changed, then ignore any requests to scroll
1595 // to a rectangle; first we want to make sure the entire focus
1596 // view is visible.
1597 rectangle = null;
1598 }
1599 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
1600 + " rectangle=" + rectangle + " ci=" + ci
1601 + " vi=" + vi);
1602 if (focus == mLastScrolledFocus && !mScrollMayChange
1603 && rectangle == null) {
1604 // Optimization: if the focus hasn't changed since last
1605 // time, and no layout has happened, then just leave things
1606 // as they are.
1607 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
1608 + mScrollY + " vi=" + vi.toShortString());
1609 } else if (focus != null) {
1610 // We need to determine if the currently focused view is
1611 // within the visible part of the window and, if not, apply
1612 // a pan so it can be seen.
1613 mLastScrolledFocus = focus;
1614 mScrollMayChange = false;
1615 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
1616 // Try to find the rectangle from the focus view.
1617 if (focus.getGlobalVisibleRect(mVisRect, null)) {
1618 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
1619 + mView.getWidth() + " h=" + mView.getHeight()
1620 + " ci=" + ci.toShortString()
1621 + " vi=" + vi.toShortString());
1622 if (rectangle == null) {
1623 focus.getFocusedRect(mTempRect);
1624 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
1625 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07001626 if (mView instanceof ViewGroup) {
1627 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
1628 focus, mTempRect);
1629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1631 "Focus in window: focusRect="
1632 + mTempRect.toShortString()
1633 + " visRect=" + mVisRect.toShortString());
1634 } else {
1635 mTempRect.set(rectangle);
1636 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1637 "Request scroll to rect: "
1638 + mTempRect.toShortString()
1639 + " visRect=" + mVisRect.toShortString());
1640 }
1641 if (mTempRect.intersect(mVisRect)) {
1642 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1643 "Focus window visible rect: "
1644 + mTempRect.toShortString());
1645 if (mTempRect.height() >
1646 (mView.getHeight()-vi.top-vi.bottom)) {
1647 // If the focus simply is not going to fit, then
1648 // best is probably just to leave things as-is.
1649 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1650 "Too tall; leaving scrollY=" + scrollY);
1651 } else if ((mTempRect.top-scrollY) < vi.top) {
1652 scrollY -= vi.top - (mTempRect.top-scrollY);
1653 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1654 "Top covered; scrollY=" + scrollY);
1655 } else if ((mTempRect.bottom-scrollY)
1656 > (mView.getHeight()-vi.bottom)) {
1657 scrollY += (mTempRect.bottom-scrollY)
1658 - (mView.getHeight()-vi.bottom);
1659 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
1660 "Bottom covered; scrollY=" + scrollY);
1661 }
1662 handled = true;
1663 }
1664 }
1665 }
1666 }
Romain Guy8506ab42009-06-11 17:35:47 -07001667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 if (scrollY != mScrollY) {
1669 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
1670 + mScrollY + " , new=" + scrollY);
1671 if (!immediate) {
1672 if (mScroller == null) {
1673 mScroller = new Scroller(mView.getContext());
1674 }
1675 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
1676 } else if (mScroller != null) {
1677 mScroller.abortAnimation();
1678 }
1679 mScrollY = scrollY;
1680 }
Romain Guy8506ab42009-06-11 17:35:47 -07001681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 return handled;
1683 }
Romain Guy8506ab42009-06-11 17:35:47 -07001684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 public void requestChildFocus(View child, View focused) {
1686 checkThread();
1687 if (mFocusedView != focused) {
1688 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
1689 scheduleTraversals();
1690 }
1691 mFocusedView = mRealFocusedView = focused;
1692 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
1693 + mFocusedView);
1694 }
1695
1696 public void clearChildFocus(View child) {
1697 checkThread();
1698
1699 View oldFocus = mFocusedView;
1700
1701 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
1702 mFocusedView = mRealFocusedView = null;
1703 if (mView != null && !mView.hasFocus()) {
1704 // If a view gets the focus, the listener will be invoked from requestChildFocus()
1705 if (!mView.requestFocus(View.FOCUS_FORWARD)) {
1706 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
1707 }
1708 } else if (oldFocus != null) {
1709 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
1710 }
1711 }
1712
1713
1714 public void focusableViewAvailable(View v) {
1715 checkThread();
1716
1717 if (mView != null && !mView.hasFocus()) {
1718 v.requestFocus();
1719 } else {
1720 // the one case where will transfer focus away from the current one
1721 // is if the current view is a view group that prefers to give focus
1722 // to its children first AND the view is a descendant of it.
1723 mFocusedView = mView.findFocus();
1724 boolean descendantsHaveDibsOnFocus =
1725 (mFocusedView instanceof ViewGroup) &&
1726 (((ViewGroup) mFocusedView).getDescendantFocusability() ==
1727 ViewGroup.FOCUS_AFTER_DESCENDANTS);
1728 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
1729 // If a view gets the focus, the listener will be invoked from requestChildFocus()
1730 v.requestFocus();
1731 }
1732 }
1733 }
1734
1735 public void recomputeViewAttributes(View child) {
1736 checkThread();
1737 if (mView == child) {
1738 mAttachInfo.mRecomputeGlobalAttributes = true;
1739 if (!mWillDrawSoon) {
1740 scheduleTraversals();
1741 }
1742 }
1743 }
1744
1745 void dispatchDetachedFromWindow() {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001746 if (Config.LOGV) Log.v(TAG, "Detaching in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747
1748 if (mView != null) {
1749 mView.dispatchDetachedFromWindow();
1750 }
1751
1752 mView = null;
1753 mAttachInfo.mRootView = null;
Mathias Agopian5583dc62009-07-09 16:28:11 -07001754 mAttachInfo.mSurface = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755
1756 if (mUseGL) {
1757 destroyGL();
1758 }
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07001759 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001761 if (mInputChannel != null) {
1762 if (mInputQueueCallback != null) {
1763 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
1764 mInputQueueCallback = null;
1765 } else {
1766 InputQueue.unregisterInputChannel(mInputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -07001767 }
1768 }
1769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 try {
1771 sWindowSession.remove(mWindow);
1772 } catch (RemoteException e) {
1773 }
Jeff Brown349703e2010-06-22 01:27:15 -07001774
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001775 // Dispose the input channel after removing the window so the Window Manager
1776 // doesn't interpret the input channel being closed as an abnormal termination.
1777 if (mInputChannel != null) {
1778 mInputChannel.dispose();
1779 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07001780 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 }
Romain Guy8506ab42009-06-11 17:35:47 -07001782
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001783 void updateConfiguration(Configuration config, boolean force) {
1784 if (DEBUG_CONFIGURATION) Log.v(TAG,
1785 "Applying new config to window "
1786 + mWindowAttributes.getTitle()
1787 + ": " + config);
1788 synchronized (sConfigCallbacks) {
1789 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
1790 sConfigCallbacks.get(i).onConfigurationChanged(config);
1791 }
1792 }
1793 if (mView != null) {
1794 // At this point the resources have been updated to
1795 // have the most recent config, whatever that is. Use
1796 // the on in them which may be newer.
1797 if (mView != null) {
1798 config = mView.getResources().getConfiguration();
1799 }
1800 if (force || mLastConfiguration.diff(config) != 0) {
1801 mLastConfiguration.setTo(config);
1802 mView.dispatchConfigurationChanged(config);
1803 }
1804 }
1805 }
1806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 /**
1808 * Return true if child is an ancestor of parent, (or equal to the parent).
1809 */
1810 private static boolean isViewDescendantOf(View child, View parent) {
1811 if (child == parent) {
1812 return true;
1813 }
1814
1815 final ViewParent theParent = child.getParent();
1816 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
1817 }
1818
Romain Guycdb86672010-03-18 18:54:50 -07001819 private static void forceLayout(View view) {
1820 view.forceLayout();
1821 if (view instanceof ViewGroup) {
1822 ViewGroup group = (ViewGroup) view;
1823 final int count = group.getChildCount();
1824 for (int i = 0; i < count; i++) {
1825 forceLayout(group.getChildAt(i));
1826 }
1827 }
1828 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829
1830 public final static int DO_TRAVERSAL = 1000;
1831 public final static int DIE = 1001;
1832 public final static int RESIZED = 1002;
1833 public final static int RESIZED_REPORT = 1003;
1834 public final static int WINDOW_FOCUS_CHANGED = 1004;
1835 public final static int DISPATCH_KEY = 1005;
1836 public final static int DISPATCH_POINTER = 1006;
1837 public final static int DISPATCH_TRACKBALL = 1007;
1838 public final static int DISPATCH_APP_VISIBILITY = 1008;
1839 public final static int DISPATCH_GET_NEW_SURFACE = 1009;
1840 public final static int FINISHED_EVENT = 1010;
1841 public final static int DISPATCH_KEY_FROM_IME = 1011;
1842 public final static int FINISH_INPUT_CONNECTION = 1012;
1843 public final static int CHECK_FOCUS = 1013;
Dianne Hackbornffa42482009-09-23 22:20:11 -07001844 public final static int CLOSE_SYSTEM_DIALOGS = 1014;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845
1846 @Override
1847 public void handleMessage(Message msg) {
1848 switch (msg.what) {
1849 case View.AttachInfo.INVALIDATE_MSG:
1850 ((View) msg.obj).invalidate();
1851 break;
1852 case View.AttachInfo.INVALIDATE_RECT_MSG:
1853 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
1854 info.target.invalidate(info.left, info.top, info.right, info.bottom);
1855 info.release();
1856 break;
1857 case DO_TRAVERSAL:
1858 if (mProfile) {
1859 Debug.startMethodTracing("ViewRoot");
1860 }
1861
1862 performTraversals();
1863
1864 if (mProfile) {
1865 Debug.stopMethodTracing();
1866 mProfile = false;
1867 }
1868 break;
1869 case FINISHED_EVENT:
1870 handleFinishedEvent(msg.arg1, msg.arg2 != 0);
1871 break;
1872 case DISPATCH_KEY:
1873 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001874 TAG, "Dispatching key "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 + msg.obj + " to " + mView);
Jeff Brown92ff1dd2010-08-11 16:16:06 -07001876 deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001878 case DISPATCH_POINTER: {
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001879 MotionEvent event = (MotionEvent) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 try {
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001881 deliverPointerEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 } finally {
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001883 event.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001886 } break;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07001887 case DISPATCH_TRACKBALL: {
1888 MotionEvent event = (MotionEvent) msg.obj;
1889 try {
1890 deliverTrackballEvent(event);
1891 } finally {
1892 event.recycle();
1893 }
1894 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 case DISPATCH_APP_VISIBILITY:
1896 handleAppVisibility(msg.arg1 != 0);
1897 break;
1898 case DISPATCH_GET_NEW_SURFACE:
1899 handleGetNewSurface();
1900 break;
1901 case RESIZED:
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001902 ResizedInfo ri = (ResizedInfo)msg.obj;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001905 && mPendingContentInsets.equals(ri.coveredInsets)
Dianne Hackbornd49258f2010-03-26 00:44:29 -07001906 && mPendingVisibleInsets.equals(ri.visibleInsets)
1907 && ((ResizedInfo)msg.obj).newConfig == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 break;
1909 }
1910 // fall through...
1911 case RESIZED_REPORT:
1912 if (mAdded) {
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001913 Configuration config = ((ResizedInfo)msg.obj).newConfig;
1914 if (config != null) {
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001915 updateConfiguration(config, false);
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 mWinFrame.left = 0;
1918 mWinFrame.right = msg.arg1;
1919 mWinFrame.top = 0;
1920 mWinFrame.bottom = msg.arg2;
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001921 mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
1922 mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 if (msg.what == RESIZED_REPORT) {
1924 mReportNextDraw = true;
1925 }
Romain Guycdb86672010-03-18 18:54:50 -07001926
1927 if (mView != null) {
1928 forceLayout(mView);
1929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 requestLayout();
1931 }
1932 break;
1933 case WINDOW_FOCUS_CHANGED: {
1934 if (mAdded) {
1935 boolean hasWindowFocus = msg.arg1 != 0;
1936 mAttachInfo.mHasWindowFocus = hasWindowFocus;
1937 if (hasWindowFocus) {
1938 boolean inTouchMode = msg.arg2 != 0;
Romain Guy2d4cff62010-04-09 15:39:00 -07001939 ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940
1941 if (mGlWanted) {
1942 checkEglErrors();
1943 // we lost the gl context, so recreate it.
1944 if (mGlWanted && !mUseGL) {
1945 initializeGL();
1946 if (mGlCanvas != null) {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001947 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001948 mGlCanvas.setViewport(
Mitsuru Oshima61324e52009-07-21 15:40:36 -07001949 (int) (mWidth * appScale + 0.5f),
1950 (int) (mHeight * appScale + 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 }
1952 }
1953 }
1954 }
Romain Guy8506ab42009-06-11 17:35:47 -07001955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 mLastWasImTarget = WindowManager.LayoutParams
1957 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07001958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 InputMethodManager imm = InputMethodManager.peekInstance();
1960 if (mView != null) {
1961 if (hasWindowFocus && imm != null && mLastWasImTarget) {
1962 imm.startGettingWindowFocus(mView);
1963 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001964 mAttachInfo.mKeyDispatchState.reset();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 mView.dispatchWindowFocusChanged(hasWindowFocus);
1966 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 // Note: must be done after the focus change callbacks,
1969 // so all of the view state is set up correctly.
1970 if (hasWindowFocus) {
1971 if (imm != null && mLastWasImTarget) {
1972 imm.onWindowFocus(mView, mView.findFocus(),
1973 mWindowAttributes.softInputMode,
1974 !mHasHadWindowFocus, mWindowAttributes.flags);
1975 }
1976 // Clear the forward bit. We can just do this directly, since
1977 // the window manager doesn't care about it.
1978 mWindowAttributes.softInputMode &=
1979 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
1980 ((WindowManager.LayoutParams)mView.getLayoutParams())
1981 .softInputMode &=
1982 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
1983 mHasHadWindowFocus = true;
1984 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001985
1986 if (hasWindowFocus && mView != null) {
1987 sendAccessibilityEvents();
1988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 }
1990 } break;
1991 case DIE:
Dianne Hackborn94d69142009-09-28 22:14:42 -07001992 doDie();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001994 case DISPATCH_KEY_FROM_IME: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001996 TAG, "Dispatching key "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 + msg.obj + " from IME to " + mView);
The Android Open Source Project10592532009-03-18 17:39:46 -07001998 KeyEvent event = (KeyEvent)msg.obj;
1999 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
2000 // The IME is trying to say this event is from the
2001 // system! Bad bad bad!
2002 event = KeyEvent.changeFlags(event,
2003 event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
2004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002006 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 case FINISH_INPUT_CONNECTION: {
2008 InputMethodManager imm = InputMethodManager.peekInstance();
2009 if (imm != null) {
2010 imm.reportFinishInputConnection((InputConnection)msg.obj);
2011 }
2012 } break;
2013 case CHECK_FOCUS: {
2014 InputMethodManager imm = InputMethodManager.peekInstance();
2015 if (imm != null) {
2016 imm.checkFocus();
2017 }
2018 } break;
Dianne Hackbornffa42482009-09-23 22:20:11 -07002019 case CLOSE_SYSTEM_DIALOGS: {
2020 if (mView != null) {
2021 mView.onCloseSystemDialogs((String)msg.obj);
2022 }
2023 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002026
2027 private void finishKeyEvent(KeyEvent event) {
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002028 if (LOCAL_LOGV) Log.v(TAG, "Telling window manager key is finished");
2029
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002030 if (mFinishedCallback != null) {
2031 mFinishedCallback.run();
2032 mFinishedCallback = null;
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002033 } else {
2034 Slog.w(TAG, "Attempted to tell the input queue that the current key event "
2035 + "is finished but there is no key event actually in progress.");
Jeff Brown46b9ac02010-04-22 18:58:52 -07002036 }
2037 }
2038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 /**
2040 * Something in the current window tells us we need to change the touch mode. For
2041 * example, we are not in touch mode, and the user touches the screen.
2042 *
2043 * If the touch mode has changed, tell the window manager, and handle it locally.
2044 *
2045 * @param inTouchMode Whether we want to be in touch mode.
2046 * @return True if the touch mode changed and focus changed was changed as a result
2047 */
2048 boolean ensureTouchMode(boolean inTouchMode) {
2049 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
2050 + "touch mode is " + mAttachInfo.mInTouchMode);
2051 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
2052
2053 // tell the window manager
2054 try {
2055 sWindowSession.setInTouchMode(inTouchMode);
2056 } catch (RemoteException e) {
2057 throw new RuntimeException(e);
2058 }
2059
2060 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07002061 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062 }
2063
2064 /**
2065 * Ensure that the touch mode for this window is set, and if it is changing,
2066 * take the appropriate action.
2067 * @param inTouchMode Whether we want to be in touch mode.
2068 * @return True if the touch mode changed and focus changed was changed as a result
2069 */
Romain Guy2d4cff62010-04-09 15:39:00 -07002070 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
2072 + "touch mode is " + mAttachInfo.mInTouchMode);
2073
2074 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
2075
2076 mAttachInfo.mInTouchMode = inTouchMode;
2077 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
2078
Romain Guy2d4cff62010-04-09 15:39:00 -07002079 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 }
2081
2082 private boolean enterTouchMode() {
2083 if (mView != null) {
2084 if (mView.hasFocus()) {
2085 // note: not relying on mFocusedView here because this could
2086 // be when the window is first being added, and mFocused isn't
2087 // set yet.
2088 final View focused = mView.findFocus();
2089 if (focused != null && !focused.isFocusableInTouchMode()) {
2090
2091 final ViewGroup ancestorToTakeFocus =
2092 findAncestorToTakeFocusInTouchMode(focused);
2093 if (ancestorToTakeFocus != null) {
2094 // there is an ancestor that wants focus after its descendants that
2095 // is focusable in touch mode.. give it focus
2096 return ancestorToTakeFocus.requestFocus();
2097 } else {
2098 // nothing appropriate to have focus in touch mode, clear it out
2099 mView.unFocus();
2100 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
2101 mFocusedView = null;
2102 return true;
2103 }
2104 }
2105 }
2106 }
2107 return false;
2108 }
2109
2110
2111 /**
2112 * Find an ancestor of focused that wants focus after its descendants and is
2113 * focusable in touch mode.
2114 * @param focused The currently focused view.
2115 * @return An appropriate view, or null if no such view exists.
2116 */
2117 private ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
2118 ViewParent parent = focused.getParent();
2119 while (parent instanceof ViewGroup) {
2120 final ViewGroup vgParent = (ViewGroup) parent;
2121 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2122 && vgParent.isFocusableInTouchMode()) {
2123 return vgParent;
2124 }
2125 if (vgParent.isRootNamespace()) {
2126 return null;
2127 } else {
2128 parent = vgParent.getParent();
2129 }
2130 }
2131 return null;
2132 }
2133
2134 private boolean leaveTouchMode() {
2135 if (mView != null) {
2136 if (mView.hasFocus()) {
2137 // i learned the hard way to not trust mFocusedView :)
2138 mFocusedView = mView.findFocus();
2139 if (!(mFocusedView instanceof ViewGroup)) {
2140 // some view has focus, let it keep it
2141 return false;
2142 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
2143 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2144 // some view group has focus, and doesn't prefer its children
2145 // over itself for focus, so let them keep it.
2146 return false;
2147 }
2148 }
2149
2150 // find the best view to give focus to in this brave new non-touch-mode
2151 // world
2152 final View focused = focusSearch(null, View.FOCUS_DOWN);
2153 if (focused != null) {
2154 return focused.requestFocus(View.FOCUS_DOWN);
2155 }
2156 }
2157 return false;
2158 }
2159
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002160 private void deliverPointerEvent(MotionEvent event) {
2161 if (mTranslator != null) {
2162 mTranslator.translateEventInScreenToAppWindow(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002164
2165 boolean handled;
2166 if (mView != null && mAdded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002168 // enter touch mode on the down
2169 boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
2170 if (isDown) {
2171 ensureTouchMode(true);
2172 }
2173 if(Config.LOGV) {
2174 captureMotionLog("captureDispatchPointer", event);
2175 }
2176 if (mCurScrollY != 0) {
2177 event.offsetLocation(0, mCurScrollY);
2178 }
2179 if (MEASURE_LATENCY) {
2180 lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
2181 }
2182 handled = mView.dispatchTouchEvent(event);
2183 if (MEASURE_LATENCY) {
2184 lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
2185 }
2186 if (!handled && isDown) {
2187 int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
2188
2189 final int edgeFlags = event.getEdgeFlags();
2190 int direction = View.FOCUS_UP;
2191 int x = (int)event.getX();
2192 int y = (int)event.getY();
2193 final int[] deltas = new int[2];
2194
2195 if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
2196 direction = View.FOCUS_DOWN;
2197 if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
2198 deltas[0] = edgeSlop;
2199 x += edgeSlop;
2200 } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
2201 deltas[0] = -edgeSlop;
2202 x -= edgeSlop;
2203 }
2204 } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
2205 direction = View.FOCUS_UP;
2206 if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
2207 deltas[0] = edgeSlop;
2208 x += edgeSlop;
2209 } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
2210 deltas[0] = -edgeSlop;
2211 x -= edgeSlop;
2212 }
2213 } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
2214 direction = View.FOCUS_RIGHT;
2215 } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
2216 direction = View.FOCUS_LEFT;
2217 }
2218
2219 if (edgeFlags != 0 && mView instanceof ViewGroup) {
2220 View nearest = FocusFinder.getInstance().findNearestTouchable(
2221 ((ViewGroup) mView), x, y, direction, deltas);
2222 if (nearest != null) {
2223 event.offsetLocation(deltas[0], deltas[1]);
2224 event.setEdgeFlags(0);
2225 mView.dispatchTouchEvent(event);
2226 }
2227 }
2228 }
2229 }
2230 }
2231
2232 private void deliverTrackballEvent(MotionEvent event) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
2234
2235 boolean handled = false;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002236 if (mView != null && mAdded) {
2237 handled = mView.dispatchTrackballEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 if (handled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 // If we reach this, we delivered a trackball event to mView and
2240 // mView consumed it. Because we will not translate the trackball
2241 // event into a key event, touch mode will not exit, so we exit
2242 // touch mode here.
2243 ensureTouchMode(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 return;
2245 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002246
2247 // Otherwise we could do something here, like changing the focus
2248 // or something?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249 }
2250
2251 final TrackballAxis x = mTrackballAxisX;
2252 final TrackballAxis y = mTrackballAxisY;
2253
2254 long curTime = SystemClock.uptimeMillis();
2255 if ((mLastTrackballTime+MAX_TRACKBALL_DELAY) < curTime) {
2256 // It has been too long since the last movement,
2257 // so restart at the beginning.
2258 x.reset(0);
2259 y.reset(0);
2260 mLastTrackballTime = curTime;
2261 }
2262
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002263 final int action = event.getAction();
2264 final int metastate = event.getMetaState();
2265 switch (action) {
2266 case MotionEvent.ACTION_DOWN:
2267 x.reset(2);
2268 y.reset(2);
2269 deliverKeyEvent(new KeyEvent(curTime, curTime,
2270 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
2271 0, metastate), false);
2272 break;
2273 case MotionEvent.ACTION_UP:
2274 x.reset(2);
2275 y.reset(2);
2276 deliverKeyEvent(new KeyEvent(curTime, curTime,
2277 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
2278 0, metastate), false);
2279 break;
2280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002282 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
2283 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
2284 + " move=" + event.getX()
2285 + " / Y=" + y.position + " step="
2286 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
2287 + " move=" + event.getY());
2288 final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
2289 final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002291 // Generate DPAD events based on the trackball movement.
2292 // We pick the axis that has moved the most as the direction of
2293 // the DPAD. When we generate DPAD events for one axis, then the
2294 // other axis is reset -- we don't want to perform DPAD jumps due
2295 // to slight movements in the trackball when making major movements
2296 // along the other axis.
2297 int keycode = 0;
2298 int movement = 0;
2299 float accel = 1;
2300 if (xOff > yOff) {
2301 movement = x.generate((2/event.getXPrecision()));
2302 if (movement != 0) {
2303 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
2304 : KeyEvent.KEYCODE_DPAD_LEFT;
2305 accel = x.acceleration;
2306 y.reset(2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002308 } else if (yOff > 0) {
2309 movement = y.generate((2/event.getYPrecision()));
2310 if (movement != 0) {
2311 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
2312 : KeyEvent.KEYCODE_DPAD_UP;
2313 accel = y.acceleration;
2314 x.reset(2);
2315 }
2316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002317
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002318 if (keycode != 0) {
2319 if (movement < 0) movement = -movement;
2320 int accelMovement = (int)(movement * accel);
2321 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
2322 + " accelMovement=" + accelMovement
2323 + " accel=" + accel);
2324 if (accelMovement > movement) {
2325 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
2326 + keycode);
2327 movement--;
2328 deliverKeyEvent(new KeyEvent(curTime, curTime,
2329 KeyEvent.ACTION_MULTIPLE, keycode,
2330 accelMovement-movement, metastate), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002332 while (movement > 0) {
2333 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
2334 + keycode);
2335 movement--;
2336 curTime = SystemClock.uptimeMillis();
2337 deliverKeyEvent(new KeyEvent(curTime, curTime,
2338 KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
2339 deliverKeyEvent(new KeyEvent(curTime, curTime,
2340 KeyEvent.ACTION_UP, keycode, 0, metastate), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002342 mLastTrackballTime = curTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 }
2344 }
2345
2346 /**
2347 * @param keyCode The key code
2348 * @return True if the key is directional.
2349 */
2350 static boolean isDirectional(int keyCode) {
2351 switch (keyCode) {
2352 case KeyEvent.KEYCODE_DPAD_LEFT:
2353 case KeyEvent.KEYCODE_DPAD_RIGHT:
2354 case KeyEvent.KEYCODE_DPAD_UP:
2355 case KeyEvent.KEYCODE_DPAD_DOWN:
2356 return true;
2357 }
2358 return false;
2359 }
2360
2361 /**
2362 * Returns true if this key is a keyboard key.
2363 * @param keyEvent The key event.
2364 * @return whether this key is a keyboard key.
2365 */
2366 private static boolean isKeyboardKey(KeyEvent keyEvent) {
2367 final int convertedKey = keyEvent.getUnicodeChar();
2368 return convertedKey > 0;
2369 }
2370
2371
2372
2373 /**
2374 * See if the key event means we should leave touch mode (and leave touch
2375 * mode if so).
2376 * @param event The key event.
2377 * @return Whether this key event should be consumed (meaning the act of
2378 * leaving touch mode alone is considered the event).
2379 */
2380 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Adam Powell51a6bee2010-03-15 14:07:28 -07002381 final int action = event.getAction();
2382 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 return false;
2384 }
2385 if ((event.getFlags()&KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
2386 return false;
2387 }
2388
2389 // only relevant if we are in touch mode
2390 if (!mAttachInfo.mInTouchMode) {
2391 return false;
2392 }
2393
2394 // if something like an edit text has focus and the user is typing,
2395 // leave touch mode
2396 //
2397 // note: the condition of not being a keyboard key is kind of a hacky
2398 // approximation of whether we think the focused view will want the
2399 // key; if we knew for sure whether the focused view would consume
2400 // the event, that would be better.
2401 if (isKeyboardKey(event) && mView != null && mView.hasFocus()) {
2402 mFocusedView = mView.findFocus();
2403 if ((mFocusedView instanceof ViewGroup)
2404 && ((ViewGroup) mFocusedView).getDescendantFocusability() ==
2405 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2406 // something has focus, but is holding it weakly as a container
2407 return false;
2408 }
2409 if (ensureTouchMode(false)) {
2410 throw new IllegalStateException("should not have changed focus "
2411 + "when leaving touch mode while a view has focus.");
2412 }
2413 return false;
2414 }
2415
2416 if (isDirectional(event.getKeyCode())) {
2417 // no view has focus, so we leave touch mode (and find something
2418 // to give focus to). the event is consumed if we were able to
2419 // find something to give focus to.
2420 return ensureTouchMode(false);
2421 }
2422 return false;
2423 }
2424
2425 /**
Romain Guy8506ab42009-06-11 17:35:47 -07002426 * log motion events
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 */
2428 private static void captureMotionLog(String subTag, MotionEvent ev) {
Romain Guy8506ab42009-06-11 17:35:47 -07002429 //check dynamic switch
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 if (ev == null ||
2431 SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
2432 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002433 }
Romain Guy8506ab42009-06-11 17:35:47 -07002434
2435 StringBuilder sb = new StringBuilder(subTag + ": ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002436 sb.append(ev.getDownTime()).append(',');
2437 sb.append(ev.getEventTime()).append(',');
2438 sb.append(ev.getAction()).append(',');
Romain Guy8506ab42009-06-11 17:35:47 -07002439 sb.append(ev.getX()).append(',');
2440 sb.append(ev.getY()).append(',');
2441 sb.append(ev.getPressure()).append(',');
2442 sb.append(ev.getSize()).append(',');
2443 sb.append(ev.getMetaState()).append(',');
2444 sb.append(ev.getXPrecision()).append(',');
2445 sb.append(ev.getYPrecision()).append(',');
2446 sb.append(ev.getDeviceId()).append(',');
2447 sb.append(ev.getEdgeFlags());
2448 Log.d(TAG, sb.toString());
2449 }
2450 /**
2451 * log motion events
2452 */
2453 private static void captureKeyLog(String subTag, KeyEvent ev) {
2454 //check dynamic switch
2455 if (ev == null ||
2456 SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
2457 return;
2458 }
2459 StringBuilder sb = new StringBuilder(subTag + ": ");
2460 sb.append(ev.getDownTime()).append(',');
2461 sb.append(ev.getEventTime()).append(',');
2462 sb.append(ev.getAction()).append(',');
2463 sb.append(ev.getKeyCode()).append(',');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002464 sb.append(ev.getRepeatCount()).append(',');
2465 sb.append(ev.getMetaState()).append(',');
2466 sb.append(ev.getDeviceId()).append(',');
2467 sb.append(ev.getScanCode());
Romain Guy8506ab42009-06-11 17:35:47 -07002468 Log.d(TAG, sb.toString());
2469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002470
2471 int enqueuePendingEvent(Object event, boolean sendDone) {
2472 int seq = mPendingEventSeq+1;
2473 if (seq < 0) seq = 0;
2474 mPendingEventSeq = seq;
2475 mPendingEvents.put(seq, event);
2476 return sendDone ? seq : -seq;
2477 }
2478
2479 Object retrievePendingEvent(int seq) {
2480 if (seq < 0) seq = -seq;
2481 Object event = mPendingEvents.get(seq);
2482 if (event != null) {
2483 mPendingEvents.remove(seq);
2484 }
2485 return event;
2486 }
Romain Guy8506ab42009-06-11 17:35:47 -07002487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002488 private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
2489 // If mView is null, we just consume the key event because it doesn't
2490 // make sense to do anything else with it.
2491 boolean handled = mView != null
2492 ? mView.dispatchKeyEventPreIme(event) : true;
2493 if (handled) {
2494 if (sendDone) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07002495 finishKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 }
2497 return;
2498 }
2499 // If it is possible for this window to interact with the input
2500 // method window, then we want to first dispatch our key events
2501 // to the input method.
2502 if (mLastWasImTarget) {
2503 InputMethodManager imm = InputMethodManager.peekInstance();
2504 if (imm != null && mView != null) {
2505 int seq = enqueuePendingEvent(event, sendDone);
2506 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
2507 + seq + " event=" + event);
2508 imm.dispatchKeyEvent(mView.getContext(), seq, event,
2509 mInputMethodCallback);
2510 return;
2511 }
2512 }
2513 deliverKeyEventToViewHierarchy(event, sendDone);
2514 }
2515
2516 void handleFinishedEvent(int seq, boolean handled) {
2517 final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
2518 if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
2519 + " handled=" + handled + " event=" + event);
2520 if (event != null) {
2521 final boolean sendDone = seq >= 0;
2522 if (!handled) {
2523 deliverKeyEventToViewHierarchy(event, sendDone);
2524 return;
2525 } else if (sendDone) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07002526 finishKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002527 } else {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002528 Log.w(TAG, "handleFinishedEvent(seq=" + seq
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 + " handled=" + handled + " ev=" + event
2530 + ") neither delivering nor finishing key");
2531 }
2532 }
2533 }
Romain Guy8506ab42009-06-11 17:35:47 -07002534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 private void deliverKeyEventToViewHierarchy(KeyEvent event, boolean sendDone) {
2536 try {
2537 if (mView != null && mAdded) {
2538 final int action = event.getAction();
2539 boolean isDown = (action == KeyEvent.ACTION_DOWN);
2540
2541 if (checkForLeavingTouchModeAndConsume(event)) {
2542 return;
Romain Guy8506ab42009-06-11 17:35:47 -07002543 }
2544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 if (Config.LOGV) {
2546 captureKeyLog("captureDispatchKeyEvent", event);
2547 }
2548 boolean keyHandled = mView.dispatchKeyEvent(event);
2549
2550 if (!keyHandled && isDown) {
2551 int direction = 0;
2552 switch (event.getKeyCode()) {
2553 case KeyEvent.KEYCODE_DPAD_LEFT:
2554 direction = View.FOCUS_LEFT;
2555 break;
2556 case KeyEvent.KEYCODE_DPAD_RIGHT:
2557 direction = View.FOCUS_RIGHT;
2558 break;
2559 case KeyEvent.KEYCODE_DPAD_UP:
2560 direction = View.FOCUS_UP;
2561 break;
2562 case KeyEvent.KEYCODE_DPAD_DOWN:
2563 direction = View.FOCUS_DOWN;
2564 break;
2565 }
2566
2567 if (direction != 0) {
2568
2569 View focused = mView != null ? mView.findFocus() : null;
2570 if (focused != null) {
2571 View v = focused.focusSearch(direction);
2572 boolean focusPassed = false;
2573 if (v != null && v != focused) {
2574 // do the math the get the interesting rect
2575 // of previous focused into the coord system of
2576 // newly focused view
2577 focused.getFocusedRect(mTempRect);
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002578 if (mView instanceof ViewGroup) {
2579 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2580 focused, mTempRect);
2581 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
2582 v, mTempRect);
2583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584 focusPassed = v.requestFocus(direction, mTempRect);
2585 }
2586
2587 if (!focusPassed) {
2588 mView.dispatchUnhandledMove(focused, direction);
2589 } else {
2590 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
2591 }
2592 }
2593 }
2594 }
2595 }
2596
2597 } finally {
2598 if (sendDone) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07002599 finishKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 }
2601 // Let the exception fall through -- the looper will catch
2602 // it and take care of the bad app for us.
2603 }
2604 }
2605
2606 private AudioManager getAudioManager() {
2607 if (mView == null) {
2608 throw new IllegalStateException("getAudioManager called when there is no mView");
2609 }
2610 if (mAudioManager == null) {
2611 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
2612 }
2613 return mAudioManager;
2614 }
2615
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002616 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
2617 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002618
2619 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002620 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002621 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07002622 restore = true;
2623 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002624 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002625 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002626 if (params != null) {
2627 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002628 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002629 mPendingConfiguration.seq = 0;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002630 int relayoutResult = sWindowSession.relayout(
2631 mWindow, params,
Mitsuru Oshima61324e52009-07-21 15:40:36 -07002632 (int) (mView.mMeasuredWidth * appScale + 0.5f),
2633 (int) (mView.mMeasuredHeight * appScale + 0.5f),
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002634 viewVisibility, insetsPending, mWinFrame,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002635 mPendingContentInsets, mPendingVisibleInsets,
2636 mPendingConfiguration, mSurface);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002637 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07002638 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002639 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002640
2641 if (mTranslator != null) {
2642 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
2643 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
2644 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002645 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002646 return relayoutResult;
2647 }
Romain Guy8506ab42009-06-11 17:35:47 -07002648
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002649 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 * {@inheritDoc}
2651 */
2652 public void playSoundEffect(int effectId) {
2653 checkThread();
2654
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07002655 try {
2656 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07002658 switch (effectId) {
2659 case SoundEffectConstants.CLICK:
2660 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
2661 return;
2662 case SoundEffectConstants.NAVIGATION_DOWN:
2663 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
2664 return;
2665 case SoundEffectConstants.NAVIGATION_LEFT:
2666 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
2667 return;
2668 case SoundEffectConstants.NAVIGATION_RIGHT:
2669 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
2670 return;
2671 case SoundEffectConstants.NAVIGATION_UP:
2672 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
2673 return;
2674 default:
2675 throw new IllegalArgumentException("unknown effect id " + effectId +
2676 " not defined in " + SoundEffectConstants.class.getCanonicalName());
2677 }
2678 } catch (IllegalStateException e) {
2679 // Exception thrown by getAudioManager() when mView is null
2680 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
2681 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 }
2683 }
2684
2685 /**
2686 * {@inheritDoc}
2687 */
2688 public boolean performHapticFeedback(int effectId, boolean always) {
2689 try {
2690 return sWindowSession.performHapticFeedback(mWindow, effectId, always);
2691 } catch (RemoteException e) {
2692 return false;
2693 }
2694 }
2695
2696 /**
2697 * {@inheritDoc}
2698 */
2699 public View focusSearch(View focused, int direction) {
2700 checkThread();
2701 if (!(mView instanceof ViewGroup)) {
2702 return null;
2703 }
2704 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
2705 }
2706
2707 public void debug() {
2708 mView.debug();
2709 }
2710
2711 public void die(boolean immediate) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07002712 if (immediate) {
2713 doDie();
2714 } else {
2715 sendEmptyMessage(DIE);
2716 }
2717 }
2718
2719 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720 checkThread();
Jeff Brownc5ed5912010-07-14 18:48:53 -07002721 if (Config.LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722 synchronized (this) {
2723 if (mAdded && !mFirst) {
2724 int viewVisibility = mView.getVisibility();
2725 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
2726 if (mWindowAttributesChanged || viewVisibilityChanged) {
2727 // If layout params have been changed, first give them
2728 // to the window manager to make sure it has the correct
2729 // animation info.
2730 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002731 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
2732 & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002733 sWindowSession.finishDrawing(mWindow);
2734 }
2735 } catch (RemoteException e) {
2736 }
2737 }
2738
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002739 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 }
2741 if (mAdded) {
2742 mAdded = false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07002743 dispatchDetachedFromWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 }
2745 }
2746 }
2747
2748 public void dispatchFinishedEvent(int seq, boolean handled) {
2749 Message msg = obtainMessage(FINISHED_EVENT);
2750 msg.arg1 = seq;
2751 msg.arg2 = handled ? 1 : 0;
2752 sendMessage(msg);
2753 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07002754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755 public void dispatchResized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002756 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
2758 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
2759 + " visibleInsets=" + visibleInsets.toShortString()
2760 + " reportDraw=" + reportDraw);
2761 Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002762 if (mTranslator != null) {
2763 mTranslator.translateRectInScreenToAppWindow(coveredInsets);
2764 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
2765 w *= mTranslator.applicationInvertedScale;
2766 h *= mTranslator.applicationInvertedScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002767 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002768 msg.arg1 = w;
2769 msg.arg2 = h;
Dianne Hackborne36d6e22010-02-17 19:46:25 -08002770 ResizedInfo ri = new ResizedInfo();
2771 ri.coveredInsets = new Rect(coveredInsets);
2772 ri.visibleInsets = new Rect(visibleInsets);
2773 ri.newConfig = newConfig;
2774 msg.obj = ri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 sendMessage(msg);
2776 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002777
2778 private Runnable mFinishedCallback;
2779
2780 private final InputHandler mInputHandler = new InputHandler() {
2781 public void handleKey(KeyEvent event, Runnable finishedCallback) {
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002782 if (mFinishedCallback != null) {
2783 Slog.w(TAG, "Received a new key event from the input queue but there is "
2784 + "already an unfinished key event in progress.");
2785 }
2786
Jeff Brown46b9ac02010-04-22 18:58:52 -07002787 mFinishedCallback = finishedCallback;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002788
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002789 dispatchKey(event, true);
Jeff Brown46b9ac02010-04-22 18:58:52 -07002790 }
2791
Jeff Brownc5ed5912010-07-14 18:48:53 -07002792 public void handleMotion(MotionEvent event, Runnable finishedCallback) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07002793 finishedCallback.run();
2794
Jeff Brownc5ed5912010-07-14 18:48:53 -07002795 dispatchMotion(event);
Jeff Brown46b9ac02010-04-22 18:58:52 -07002796 }
2797 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002798
2799 public void dispatchKey(KeyEvent event) {
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002800 dispatchKey(event, false);
2801 }
2802
2803 private void dispatchKey(KeyEvent event, boolean sendDone) {
2804 //noinspection ConstantConditions
2805 if (false && event.getAction() == KeyEvent.ACTION_DOWN) {
2806 if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002807 if (Config.LOGD) Log.d("keydisp",
2808 "===================================================");
2809 if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
2810 debug();
2811
2812 if (Config.LOGD) Log.d("keydisp",
2813 "===================================================");
2814 }
2815 }
2816
2817 Message msg = obtainMessage(DISPATCH_KEY);
2818 msg.obj = event;
Jeff Brown92ff1dd2010-08-11 16:16:06 -07002819 msg.arg1 = sendDone ? 1 : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820
2821 if (LOCAL_LOGV) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07002822 TAG, "sending key " + event + " to " + mView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823
2824 sendMessageAtTime(msg, event.getEventTime());
2825 }
Jeff Brownc5ed5912010-07-14 18:48:53 -07002826
2827 public void dispatchMotion(MotionEvent event) {
2828 int source = event.getSource();
2829 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
2830 dispatchPointer(event);
2831 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
2832 dispatchTrackball(event);
2833 } else {
2834 // TODO
2835 Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
2836 }
2837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002838
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002839 public void dispatchPointer(MotionEvent event) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 Message msg = obtainMessage(DISPATCH_POINTER);
2841 msg.obj = event;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002842 sendMessageAtTime(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 }
2844
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002845 public void dispatchTrackball(MotionEvent event) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002846 Message msg = obtainMessage(DISPATCH_TRACKBALL);
2847 msg.obj = event;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002848 sendMessageAtTime(msg, event.getEventTime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 public void dispatchAppVisibility(boolean visible) {
2852 Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
2853 msg.arg1 = visible ? 1 : 0;
2854 sendMessage(msg);
2855 }
2856
2857 public void dispatchGetNewSurface() {
2858 Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
2859 sendMessage(msg);
2860 }
2861
2862 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
2863 Message msg = Message.obtain();
2864 msg.what = WINDOW_FOCUS_CHANGED;
2865 msg.arg1 = hasFocus ? 1 : 0;
2866 msg.arg2 = inTouchMode ? 1 : 0;
2867 sendMessage(msg);
2868 }
2869
Dianne Hackbornffa42482009-09-23 22:20:11 -07002870 public void dispatchCloseSystemDialogs(String reason) {
2871 Message msg = Message.obtain();
2872 msg.what = CLOSE_SYSTEM_DIALOGS;
2873 msg.obj = reason;
2874 sendMessage(msg);
2875 }
2876
svetoslavganov75986cf2009-05-14 22:28:01 -07002877 /**
2878 * The window is getting focus so if there is anything focused/selected
2879 * send an {@link AccessibilityEvent} to announce that.
2880 */
2881 private void sendAccessibilityEvents() {
2882 if (!AccessibilityManager.getInstance(mView.getContext()).isEnabled()) {
2883 return;
2884 }
2885 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2886 View focusedView = mView.findFocus();
2887 if (focusedView != null && focusedView != mView) {
2888 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
2889 }
2890 }
2891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002892 public boolean showContextMenuForChild(View originalView) {
2893 return false;
2894 }
2895
2896 public void createContextMenu(ContextMenu menu) {
2897 }
2898
2899 public void childDrawableStateChanged(View child) {
2900 }
2901
2902 protected Rect getWindowFrame() {
2903 return mWinFrame;
2904 }
2905
2906 void checkThread() {
2907 if (mThread != Thread.currentThread()) {
2908 throw new CalledFromWrongThreadException(
2909 "Only the original thread that created a view hierarchy can touch its views.");
2910 }
2911 }
2912
2913 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
2914 // ViewRoot never intercepts touch event, so this can be a no-op
2915 }
2916
2917 public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
2918 boolean immediate) {
2919 return scrollToRectOrFocus(rectangle, immediate);
2920 }
Romain Guy8506ab42009-06-11 17:35:47 -07002921
Adam Powellb08013c2010-09-16 16:28:11 -07002922 /**
2923 * @hide
2924 */
2925 public void childOverlayStateChanged(View child) {
2926 final boolean oldState = mHasOverlay;
2927 mHasOverlay = child.isOverlayEnabled();
2928 // Invalidate the whole thing when we change overlay states just in case
2929 // something left chunks of data drawn someplace it shouldn't have.
2930 if (mHasOverlay != oldState) {
2931 child.invalidate();
2932 }
2933 }
2934
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002935 class TakenSurfaceHolder extends BaseSurfaceHolder {
2936 @Override
2937 public boolean onAllowLockCanvas() {
2938 return mDrawingAllowed;
2939 }
2940
2941 @Override
2942 public void onRelayoutContainer() {
2943 // Not currently interesting -- from changing between fixed and layout size.
2944 }
2945
2946 public void setFormat(int format) {
2947 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
2948 }
2949
2950 public void setType(int type) {
2951 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
2952 }
2953
2954 @Override
2955 public void onUpdateSurface() {
2956 // We take care of format and type changes on our own.
2957 throw new IllegalStateException("Shouldn't be here");
2958 }
2959
2960 public boolean isCreating() {
2961 return mIsCreating;
2962 }
2963
2964 @Override
2965 public void setFixedSize(int width, int height) {
2966 throw new UnsupportedOperationException(
2967 "Currently only support sizing from layout");
2968 }
2969
2970 public void setKeepScreenOn(boolean screenOn) {
2971 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
2972 }
2973 }
2974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 static class InputMethodCallback extends IInputMethodCallback.Stub {
2976 private WeakReference<ViewRoot> mViewRoot;
2977
2978 public InputMethodCallback(ViewRoot viewRoot) {
2979 mViewRoot = new WeakReference<ViewRoot>(viewRoot);
2980 }
Romain Guy8506ab42009-06-11 17:35:47 -07002981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982 public void finishedEvent(int seq, boolean handled) {
2983 final ViewRoot viewRoot = mViewRoot.get();
2984 if (viewRoot != null) {
2985 viewRoot.dispatchFinishedEvent(seq, handled);
2986 }
2987 }
2988
2989 public void sessionCreated(IInputMethodSession session) throws RemoteException {
2990 // Stub -- not for use in the client.
2991 }
2992 }
Romain Guy8506ab42009-06-11 17:35:47 -07002993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002994 static class W extends IWindow.Stub {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07002995 private final WeakReference<ViewRoot> mViewRoot;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002996
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07002997 public W(ViewRoot viewRoot, Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 mViewRoot = new WeakReference<ViewRoot>(viewRoot);
2999 }
3000
3001 public void resized(int w, int h, Rect coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08003002 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 final ViewRoot viewRoot = mViewRoot.get();
3004 if (viewRoot != null) {
3005 viewRoot.dispatchResized(w, h, coveredInsets,
Dianne Hackborne36d6e22010-02-17 19:46:25 -08003006 visibleInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 }
3008 }
3009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 public void dispatchAppVisibility(boolean visible) {
3011 final ViewRoot viewRoot = mViewRoot.get();
3012 if (viewRoot != null) {
3013 viewRoot.dispatchAppVisibility(visible);
3014 }
3015 }
3016
3017 public void dispatchGetNewSurface() {
3018 final ViewRoot viewRoot = mViewRoot.get();
3019 if (viewRoot != null) {
3020 viewRoot.dispatchGetNewSurface();
3021 }
3022 }
3023
3024 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
3025 final ViewRoot viewRoot = mViewRoot.get();
3026 if (viewRoot != null) {
3027 viewRoot.windowFocusChanged(hasFocus, inTouchMode);
3028 }
3029 }
3030
3031 private static int checkCallingPermission(String permission) {
3032 if (!Process.supportsProcesses()) {
3033 return PackageManager.PERMISSION_GRANTED;
3034 }
3035
3036 try {
3037 return ActivityManagerNative.getDefault().checkPermission(
3038 permission, Binder.getCallingPid(), Binder.getCallingUid());
3039 } catch (RemoteException e) {
3040 return PackageManager.PERMISSION_DENIED;
3041 }
3042 }
3043
3044 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
3045 final ViewRoot viewRoot = mViewRoot.get();
3046 if (viewRoot != null) {
3047 final View view = viewRoot.mView;
3048 if (view != null) {
3049 if (checkCallingPermission(Manifest.permission.DUMP) !=
3050 PackageManager.PERMISSION_GRANTED) {
3051 throw new SecurityException("Insufficient permissions to invoke"
3052 + " executeCommand() from pid=" + Binder.getCallingPid()
3053 + ", uid=" + Binder.getCallingUid());
3054 }
3055
3056 OutputStream clientStream = null;
3057 try {
3058 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
3059 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
3060 } catch (IOException e) {
3061 e.printStackTrace();
3062 } finally {
3063 if (clientStream != null) {
3064 try {
3065 clientStream.close();
3066 } catch (IOException e) {
3067 e.printStackTrace();
3068 }
3069 }
3070 }
3071 }
3072 }
3073 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07003074
Dianne Hackbornffa42482009-09-23 22:20:11 -07003075 public void closeSystemDialogs(String reason) {
3076 final ViewRoot viewRoot = mViewRoot.get();
3077 if (viewRoot != null) {
3078 viewRoot.dispatchCloseSystemDialogs(reason);
3079 }
3080 }
3081
Marco Nelissenbf6956b2009-11-09 15:21:13 -08003082 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
3083 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07003084 if (sync) {
3085 try {
3086 sWindowSession.wallpaperOffsetsComplete(asBinder());
3087 } catch (RemoteException e) {
3088 }
3089 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07003090 }
Dianne Hackborn75804932009-10-20 20:15:20 -07003091
3092 public void dispatchWallpaperCommand(String action, int x, int y,
3093 int z, Bundle extras, boolean sync) {
3094 if (sync) {
3095 try {
3096 sWindowSession.wallpaperCommandComplete(asBinder(), null);
3097 } catch (RemoteException e) {
3098 }
3099 }
3100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 }
3102
3103 /**
3104 * Maintains state information for a single trackball axis, generating
3105 * discrete (DPAD) movements based on raw trackball motion.
3106 */
3107 static final class TrackballAxis {
3108 /**
3109 * The maximum amount of acceleration we will apply.
3110 */
3111 static final float MAX_ACCELERATION = 20;
Romain Guy8506ab42009-06-11 17:35:47 -07003112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113 /**
3114 * The maximum amount of time (in milliseconds) between events in order
3115 * for us to consider the user to be doing fast trackball movements,
3116 * and thus apply an acceleration.
3117 */
3118 static final long FAST_MOVE_TIME = 150;
Romain Guy8506ab42009-06-11 17:35:47 -07003119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003120 /**
3121 * Scaling factor to the time (in milliseconds) between events to how
3122 * much to multiple/divide the current acceleration. When movement
3123 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
3124 * FAST_MOVE_TIME it divides it.
3125 */
3126 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
Romain Guy8506ab42009-06-11 17:35:47 -07003127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 float position;
3129 float absPosition;
3130 float acceleration = 1;
3131 long lastMoveTime = 0;
3132 int step;
3133 int dir;
3134 int nonAccelMovement;
3135
3136 void reset(int _step) {
3137 position = 0;
3138 acceleration = 1;
3139 lastMoveTime = 0;
3140 step = _step;
3141 dir = 0;
3142 }
3143
3144 /**
3145 * Add trackball movement into the state. If the direction of movement
3146 * has been reversed, the state is reset before adding the
3147 * movement (so that you don't have to compensate for any previously
3148 * collected movement before see the result of the movement in the
3149 * new direction).
3150 *
3151 * @return Returns the absolute value of the amount of movement
3152 * collected so far.
3153 */
3154 float collect(float off, long time, String axis) {
3155 long normTime;
3156 if (off > 0) {
3157 normTime = (long)(off * FAST_MOVE_TIME);
3158 if (dir < 0) {
3159 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
3160 position = 0;
3161 step = 0;
3162 acceleration = 1;
3163 lastMoveTime = 0;
3164 }
3165 dir = 1;
3166 } else if (off < 0) {
3167 normTime = (long)((-off) * FAST_MOVE_TIME);
3168 if (dir > 0) {
3169 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
3170 position = 0;
3171 step = 0;
3172 acceleration = 1;
3173 lastMoveTime = 0;
3174 }
3175 dir = -1;
3176 } else {
3177 normTime = 0;
3178 }
Romain Guy8506ab42009-06-11 17:35:47 -07003179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 // The number of milliseconds between each movement that is
3181 // considered "normal" and will not result in any acceleration
3182 // or deceleration, scaled by the offset we have here.
3183 if (normTime > 0) {
3184 long delta = time - lastMoveTime;
3185 lastMoveTime = time;
3186 float acc = acceleration;
3187 if (delta < normTime) {
3188 // The user is scrolling rapidly, so increase acceleration.
3189 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
3190 if (scale > 1) acc *= scale;
3191 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
3192 + off + " normTime=" + normTime + " delta=" + delta
3193 + " scale=" + scale + " acc=" + acc);
3194 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
3195 } else {
3196 // The user is scrolling slowly, so decrease acceleration.
3197 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
3198 if (scale > 1) acc /= scale;
3199 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
3200 + off + " normTime=" + normTime + " delta=" + delta
3201 + " scale=" + scale + " acc=" + acc);
3202 acceleration = acc > 1 ? acc : 1;
3203 }
3204 }
3205 position += off;
3206 return (absPosition = Math.abs(position));
3207 }
3208
3209 /**
3210 * Generate the number of discrete movement events appropriate for
3211 * the currently collected trackball movement.
3212 *
3213 * @param precision The minimum movement required to generate the
3214 * first discrete movement.
3215 *
3216 * @return Returns the number of discrete movements, either positive
3217 * or negative, or 0 if there is not enough trackball movement yet
3218 * for a discrete movement.
3219 */
3220 int generate(float precision) {
3221 int movement = 0;
3222 nonAccelMovement = 0;
3223 do {
3224 final int dir = position >= 0 ? 1 : -1;
3225 switch (step) {
3226 // If we are going to execute the first step, then we want
3227 // to do this as soon as possible instead of waiting for
3228 // a full movement, in order to make things look responsive.
3229 case 0:
3230 if (absPosition < precision) {
3231 return movement;
3232 }
3233 movement += dir;
3234 nonAccelMovement += dir;
3235 step = 1;
3236 break;
3237 // If we have generated the first movement, then we need
3238 // to wait for the second complete trackball motion before
3239 // generating the second discrete movement.
3240 case 1:
3241 if (absPosition < 2) {
3242 return movement;
3243 }
3244 movement += dir;
3245 nonAccelMovement += dir;
3246 position += dir > 0 ? -2 : 2;
3247 absPosition = Math.abs(position);
3248 step = 2;
3249 break;
3250 // After the first two, we generate discrete movements
3251 // consistently with the trackball, applying an acceleration
3252 // if the trackball is moving quickly. This is a simple
3253 // acceleration on top of what we already compute based
3254 // on how quickly the wheel is being turned, to apply
3255 // a longer increasing acceleration to continuous movement
3256 // in one direction.
3257 default:
3258 if (absPosition < 1) {
3259 return movement;
3260 }
3261 movement += dir;
3262 position += dir >= 0 ? -1 : 1;
3263 absPosition = Math.abs(position);
3264 float acc = acceleration;
3265 acc *= 1.1f;
3266 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
3267 break;
3268 }
3269 } while (true);
3270 }
3271 }
3272
3273 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
3274 public CalledFromWrongThreadException(String msg) {
3275 super(msg);
3276 }
3277 }
3278
3279 private SurfaceHolder mHolder = new SurfaceHolder() {
3280 // we only need a SurfaceHolder for opengl. it would be nice
3281 // to implement everything else though, especially the callback
3282 // support (opengl doesn't make use of it right now, but eventually
3283 // will).
3284 public Surface getSurface() {
3285 return mSurface;
3286 }
3287
3288 public boolean isCreating() {
3289 return false;
3290 }
3291
3292 public void addCallback(Callback callback) {
3293 }
3294
3295 public void removeCallback(Callback callback) {
3296 }
3297
3298 public void setFixedSize(int width, int height) {
3299 }
3300
3301 public void setSizeFromLayout() {
3302 }
3303
3304 public void setFormat(int format) {
3305 }
3306
3307 public void setType(int type) {
3308 }
3309
3310 public void setKeepScreenOn(boolean screenOn) {
3311 }
3312
3313 public Canvas lockCanvas() {
3314 return null;
3315 }
3316
3317 public Canvas lockCanvas(Rect dirty) {
3318 return null;
3319 }
3320
3321 public void unlockCanvasAndPost(Canvas canvas) {
3322 }
3323 public Rect getSurfaceFrame() {
3324 return null;
3325 }
3326 };
3327
3328 static RunQueue getRunQueue() {
3329 RunQueue rq = sRunQueues.get();
3330 if (rq != null) {
3331 return rq;
3332 }
3333 rq = new RunQueue();
3334 sRunQueues.set(rq);
3335 return rq;
3336 }
Romain Guy8506ab42009-06-11 17:35:47 -07003337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 /**
3339 * @hide
3340 */
3341 static final class RunQueue {
3342 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
3343
3344 void post(Runnable action) {
3345 postDelayed(action, 0);
3346 }
3347
3348 void postDelayed(Runnable action, long delayMillis) {
3349 HandlerAction handlerAction = new HandlerAction();
3350 handlerAction.action = action;
3351 handlerAction.delay = delayMillis;
3352
3353 synchronized (mActions) {
3354 mActions.add(handlerAction);
3355 }
3356 }
3357
3358 void removeCallbacks(Runnable action) {
3359 final HandlerAction handlerAction = new HandlerAction();
3360 handlerAction.action = action;
3361
3362 synchronized (mActions) {
3363 final ArrayList<HandlerAction> actions = mActions;
3364
3365 while (actions.remove(handlerAction)) {
3366 // Keep going
3367 }
3368 }
3369 }
3370
3371 void executeActions(Handler handler) {
3372 synchronized (mActions) {
3373 final ArrayList<HandlerAction> actions = mActions;
3374 final int count = actions.size();
3375
3376 for (int i = 0; i < count; i++) {
3377 final HandlerAction handlerAction = actions.get(i);
3378 handler.postDelayed(handlerAction.action, handlerAction.delay);
3379 }
3380
Romain Guy15df6702009-08-17 20:17:30 -07003381 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 }
3383 }
3384
3385 private static class HandlerAction {
3386 Runnable action;
3387 long delay;
3388
3389 @Override
3390 public boolean equals(Object o) {
3391 if (this == o) return true;
3392 if (o == null || getClass() != o.getClass()) return false;
3393
3394 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 return !(action != null ? !action.equals(that.action) : that.action != null);
3396
3397 }
3398
3399 @Override
3400 public int hashCode() {
3401 int result = action != null ? action.hashCode() : 0;
3402 result = 31 * result + (int) (delay ^ (delay >>> 32));
3403 return result;
3404 }
3405 }
3406 }
3407
3408 private static native void nativeShowFPS(Canvas canvas, int durationMillis);
3409
3410 // inform skia to just abandon its texture cache IDs
3411 // doesn't call glDeleteTextures
3412 private static native void nativeAbandonGlCaches();
3413}