blob: 2e16157fa294c4be9b868ae261396d748b4e6ea5 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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 com.android.server;
18
19import static android.os.LocalPowerManager.CHEEK_EVENT;
20import static android.os.LocalPowerManager.OTHER_EVENT;
21import static android.os.LocalPowerManager.TOUCH_EVENT;
The Android Open Source Projectc2ad2412009-03-19 23:08:54 -070022import static android.os.LocalPowerManager.LONG_TOUCH_EVENT;
23import static android.os.LocalPowerManager.TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
25import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
26import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
27import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
28import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
29import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
30import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
31import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
32import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
33import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
34import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
35import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
36import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
37import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
38import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
39import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
40import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
41
42import com.android.internal.app.IBatteryStats;
43import com.android.internal.policy.PolicyManager;
44import com.android.internal.view.IInputContext;
45import com.android.internal.view.IInputMethodClient;
46import com.android.internal.view.IInputMethodManager;
47import com.android.server.KeyInputQueue.QueuedEvent;
48import com.android.server.am.BatteryStatsService;
49
50import android.Manifest;
51import android.app.ActivityManagerNative;
52import android.app.IActivityManager;
53import android.content.Context;
54import android.content.pm.ActivityInfo;
55import android.content.pm.PackageManager;
56import android.content.res.Configuration;
57import android.graphics.Matrix;
58import android.graphics.PixelFormat;
59import android.graphics.Rect;
60import android.graphics.Region;
61import android.os.BatteryStats;
62import android.os.Binder;
63import android.os.Debug;
64import android.os.Handler;
65import android.os.IBinder;
66import android.os.LocalPowerManager;
67import android.os.Looper;
68import android.os.Message;
69import android.os.Parcel;
70import android.os.ParcelFileDescriptor;
71import android.os.Power;
72import android.os.PowerManager;
73import android.os.Process;
74import android.os.RemoteException;
75import android.os.ServiceManager;
76import android.os.SystemClock;
77import android.os.SystemProperties;
78import android.os.TokenWatcher;
79import android.provider.Settings;
80import android.util.Config;
81import android.util.EventLog;
82import android.util.Log;
83import android.util.SparseIntArray;
84import android.view.Display;
85import android.view.Gravity;
86import android.view.IApplicationToken;
87import android.view.IOnKeyguardExitResult;
88import android.view.IRotationWatcher;
89import android.view.IWindow;
90import android.view.IWindowManager;
91import android.view.IWindowSession;
92import android.view.KeyEvent;
93import android.view.MotionEvent;
94import android.view.RawInputEvent;
95import android.view.Surface;
96import android.view.SurfaceSession;
97import android.view.View;
98import android.view.ViewTreeObserver;
99import android.view.WindowManager;
100import android.view.WindowManagerImpl;
101import android.view.WindowManagerPolicy;
102import android.view.WindowManager.LayoutParams;
103import android.view.animation.Animation;
104import android.view.animation.AnimationUtils;
105import android.view.animation.Transformation;
106
107import java.io.BufferedWriter;
108import java.io.File;
109import java.io.FileDescriptor;
110import java.io.IOException;
111import java.io.OutputStream;
112import java.io.OutputStreamWriter;
113import java.io.PrintWriter;
114import java.io.StringWriter;
115import java.net.Socket;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121
122/** {@hide} */
123public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
124 static final String TAG = "WindowManager";
125 static final boolean DEBUG = false;
126 static final boolean DEBUG_FOCUS = false;
127 static final boolean DEBUG_ANIM = false;
128 static final boolean DEBUG_LAYERS = false;
129 static final boolean DEBUG_INPUT = false;
130 static final boolean DEBUG_INPUT_METHOD = false;
131 static final boolean DEBUG_VISIBILITY = false;
132 static final boolean DEBUG_ORIENTATION = false;
133 static final boolean DEBUG_APP_TRANSITIONS = false;
134 static final boolean DEBUG_STARTING_WINDOW = false;
135 static final boolean DEBUG_REORDER = false;
136 static final boolean SHOW_TRANSACTIONS = false;
137
138 static final boolean PROFILE_ORIENTATION = false;
139 static final boolean BLUR = true;
140 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
141
142 static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
143
144 /** How long to wait for first key repeat, in milliseconds */
145 static final int KEY_REPEAT_FIRST_DELAY = 750;
146
147 /** How long to wait for subsequent key repeats, in milliseconds */
148 static final int KEY_REPEAT_DELAY = 50;
149
150 /** How much to multiply the policy's type layer, to reserve room
151 * for multiple windows of the same type and Z-ordering adjustment
152 * with TYPE_LAYER_OFFSET. */
153 static final int TYPE_LAYER_MULTIPLIER = 10000;
154
155 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
156 * or below others in the same layer. */
157 static final int TYPE_LAYER_OFFSET = 1000;
158
159 /** How much to increment the layer for each window, to reserve room
160 * for effect surfaces between them.
161 */
162 static final int WINDOW_LAYER_MULTIPLIER = 5;
163
164 /** The maximum length we will accept for a loaded animation duration:
165 * this is 10 seconds.
166 */
167 static final int MAX_ANIMATION_DURATION = 10*1000;
168
169 /** Amount of time (in milliseconds) to animate the dim surface from one
170 * value to another, when no window animation is driving it.
171 */
172 static final int DEFAULT_DIM_DURATION = 200;
173
174 /** Adjustment to time to perform a dim, to make it more dramatic.
175 */
176 static final int DIM_DURATION_MULTIPLIER = 6;
177
178 static final int UPDATE_FOCUS_NORMAL = 0;
179 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
180 static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
181 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
182
183 private static final String SYSTEM_SECURE = "ro.secure";
184
185 /**
186 * Condition waited on by {@link #reenableKeyguard} to know the call to
187 * the window policy has finished.
188 */
189 private boolean mWaitingUntilKeyguardReenabled = false;
190
191
192 final TokenWatcher mKeyguardDisabled = new TokenWatcher(
193 new Handler(), "WindowManagerService.mKeyguardDisabled") {
194 public void acquired() {
195 mPolicy.enableKeyguard(false);
196 }
197 public void released() {
198 synchronized (mKeyguardDisabled) {
199 mPolicy.enableKeyguard(true);
200 mWaitingUntilKeyguardReenabled = false;
201 mKeyguardDisabled.notifyAll();
202 }
203 }
204 };
205
206 final Context mContext;
207
208 final boolean mHaveInputMethods;
209
210 final boolean mLimitedAlphaCompositing;
211
212 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
213
214 final IActivityManager mActivityManager;
215
216 final IBatteryStats mBatteryStats;
217
218 /**
219 * All currently active sessions with clients.
220 */
221 final HashSet<Session> mSessions = new HashSet<Session>();
222
223 /**
224 * Mapping from an IWindow IBinder to the server's Window object.
225 * This is also used as the lock for all of our state.
226 */
227 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
228
229 /**
230 * Mapping from a token IBinder to a WindowToken object.
231 */
232 final HashMap<IBinder, WindowToken> mTokenMap =
233 new HashMap<IBinder, WindowToken>();
234
235 /**
236 * The same tokens as mTokenMap, stored in a list for efficient iteration
237 * over them.
238 */
239 final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
240
241 /**
242 * Window tokens that are in the process of exiting, but still
243 * on screen for animations.
244 */
245 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
246
247 /**
248 * Z-ordered (bottom-most first) list of all application tokens, for
249 * controlling the ordering of windows in different applications. This
250 * contains WindowToken objects.
251 */
252 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
253
254 /**
255 * Application tokens that are in the process of exiting, but still
256 * on screen for animations.
257 */
258 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
259
260 /**
261 * List of window tokens that have finished starting their application,
262 * and now need to have the policy remove their windows.
263 */
264 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
265
266 /**
267 * Z-ordered (bottom-most first) list of all Window objects.
268 */
269 final ArrayList mWindows = new ArrayList();
270
271 /**
272 * Windows that are being resized. Used so we can tell the client about
273 * the resize after closing the transaction in which we resized the
274 * underlying surface.
275 */
276 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
277
278 /**
279 * Windows whose animations have ended and now must be removed.
280 */
281 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
282
283 /**
284 * Windows whose surface should be destroyed.
285 */
286 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
287
288 /**
289 * Windows that have lost input focus and are waiting for the new
290 * focus window to be displayed before they are told about this.
291 */
292 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
293
294 /**
295 * This is set when we have run out of memory, and will either be an empty
296 * list or contain windows that need to be force removed.
297 */
298 ArrayList<WindowState> mForceRemoves;
299
300 IInputMethodManager mInputMethodManager;
301
302 SurfaceSession mFxSession;
303 Surface mDimSurface;
304 boolean mDimShown;
305 float mDimCurrentAlpha;
306 float mDimTargetAlpha;
307 float mDimDeltaPerMs;
308 long mLastDimAnimTime;
309 Surface mBlurSurface;
310 boolean mBlurShown;
311
312 int mTransactionSequence = 0;
313
314 final float[] mTmpFloats = new float[9];
315
316 boolean mSafeMode;
317 boolean mDisplayEnabled = false;
318 boolean mSystemBooted = false;
319 int mRotation = 0;
320 int mRequestedRotation = 0;
321 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Dianne Hackborncc956672009-03-26 00:04:52 -0700322 int mLastRotationFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 ArrayList<IRotationWatcher> mRotationWatchers
324 = new ArrayList<IRotationWatcher>();
325
326 boolean mLayoutNeeded = true;
327 boolean mAnimationPending = false;
328 boolean mDisplayFrozen = false;
329 boolean mWindowsFreezingScreen = false;
330 long mFreezeGcPending = 0;
331 int mAppsFreezingScreen = 0;
332
333 // This is held as long as we have the screen frozen, to give us time to
334 // perform a rotation animation when turning off shows the lock screen which
335 // changes the orientation.
336 PowerManager.WakeLock mScreenFrozenLock;
337
338 // State management of app transitions. When we are preparing for a
339 // transition, mNextAppTransition will be the kind of transition to
340 // perform or TRANSIT_NONE if we are not waiting. If we are waiting,
341 // mOpeningApps and mClosingApps are the lists of tokens that will be
342 // made visible or hidden at the next transition.
343 int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
344 boolean mAppTransitionReady = false;
345 boolean mAppTransitionTimeout = false;
346 boolean mStartingIconInTransition = false;
347 boolean mSkipAppTransitionAnimation = false;
348 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
349 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
350
351 //flag to detect fat touch events
352 boolean mFatTouch = false;
353 Display mDisplay;
354
355 H mH = new H();
356
357 WindowState mCurrentFocus = null;
358 WindowState mLastFocus = null;
359
360 // This just indicates the window the input method is on top of, not
361 // necessarily the window its input is going to.
362 WindowState mInputMethodTarget = null;
363 WindowState mUpcomingInputMethodTarget = null;
364 boolean mInputMethodTargetWaitingAnim;
365 int mInputMethodAnimLayerAdjustment;
366
367 WindowState mInputMethodWindow = null;
368 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
369
370 AppWindowToken mFocusedApp = null;
371
372 PowerManagerService mPowerManager;
373
374 float mWindowAnimationScale = 1.0f;
375 float mTransitionAnimationScale = 1.0f;
376
377 final KeyWaiter mKeyWaiter = new KeyWaiter();
378 final KeyQ mQueue;
379 final InputDispatcherThread mInputThread;
380
381 // Who is holding the screen on.
382 Session mHoldingScreenOn;
383
384 /**
385 * Whether the UI is currently running in touch mode (not showing
386 * navigational focus because the user is directly pressing the screen).
387 */
388 boolean mInTouchMode = false;
389
390 private ViewServer mViewServer;
391
392 final Rect mTempRect = new Rect();
393
Dianne Hackborn9d4de632009-03-24 19:37:25 -0700394 final Configuration mTempConfiguration = new Configuration();
395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 public static WindowManagerService main(Context context,
397 PowerManagerService pm, boolean haveInputMethods) {
398 WMThread thr = new WMThread(context, pm, haveInputMethods);
399 thr.start();
400
401 synchronized (thr) {
402 while (thr.mService == null) {
403 try {
404 thr.wait();
405 } catch (InterruptedException e) {
406 }
407 }
408 }
409
410 return thr.mService;
411 }
412
413 static class WMThread extends Thread {
414 WindowManagerService mService;
415
416 private final Context mContext;
417 private final PowerManagerService mPM;
418 private final boolean mHaveInputMethods;
419
420 public WMThread(Context context, PowerManagerService pm,
421 boolean haveInputMethods) {
422 super("WindowManager");
423 mContext = context;
424 mPM = pm;
425 mHaveInputMethods = haveInputMethods;
426 }
427
428 public void run() {
429 Looper.prepare();
430 WindowManagerService s = new WindowManagerService(mContext, mPM,
431 mHaveInputMethods);
432 android.os.Process.setThreadPriority(
433 android.os.Process.THREAD_PRIORITY_DISPLAY);
434
435 synchronized (this) {
436 mService = s;
437 notifyAll();
438 }
439
440 Looper.loop();
441 }
442 }
443
444 static class PolicyThread extends Thread {
445 private final WindowManagerPolicy mPolicy;
446 private final WindowManagerService mService;
447 private final Context mContext;
448 private final PowerManagerService mPM;
449 boolean mRunning = false;
450
451 public PolicyThread(WindowManagerPolicy policy,
452 WindowManagerService service, Context context,
453 PowerManagerService pm) {
454 super("WindowManagerPolicy");
455 mPolicy = policy;
456 mService = service;
457 mContext = context;
458 mPM = pm;
459 }
460
461 public void run() {
462 Looper.prepare();
463 //Looper.myLooper().setMessageLogging(new LogPrinter(
464 // Log.VERBOSE, "WindowManagerPolicy"));
465 android.os.Process.setThreadPriority(
466 android.os.Process.THREAD_PRIORITY_FOREGROUND);
467 mPolicy.init(mContext, mService, mPM);
468
469 synchronized (this) {
470 mRunning = true;
471 notifyAll();
472 }
473
474 Looper.loop();
475 }
476 }
477
478 private WindowManagerService(Context context, PowerManagerService pm,
479 boolean haveInputMethods) {
480 mContext = context;
481 mHaveInputMethods = haveInputMethods;
482 mLimitedAlphaCompositing = context.getResources().getBoolean(
483 com.android.internal.R.bool.config_sf_limitedAlpha);
484
485 mPowerManager = pm;
486 mPowerManager.setPolicy(mPolicy);
487 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
488 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
489 "SCREEN_FROZEN");
490 mScreenFrozenLock.setReferenceCounted(false);
491
492 mActivityManager = ActivityManagerNative.getDefault();
493 mBatteryStats = BatteryStatsService.getService();
494
495 // Get persisted window scale setting
496 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
497 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
498 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
499 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
500
501 mQueue = new KeyQ();
502
503 mInputThread = new InputDispatcherThread();
504
505 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
506 thr.start();
507
508 synchronized (thr) {
509 while (!thr.mRunning) {
510 try {
511 thr.wait();
512 } catch (InterruptedException e) {
513 }
514 }
515 }
516
517 mInputThread.start();
518
519 // Add ourself to the Watchdog monitors.
520 Watchdog.getInstance().addMonitor(this);
521 }
522
523 @Override
524 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
525 throws RemoteException {
526 try {
527 return super.onTransact(code, data, reply, flags);
528 } catch (RuntimeException e) {
529 // The window manager only throws security exceptions, so let's
530 // log all others.
531 if (!(e instanceof SecurityException)) {
532 Log.e(TAG, "Window Manager Crash", e);
533 }
534 throw e;
535 }
536 }
537
538 private void placeWindowAfter(Object pos, WindowState window) {
539 final int i = mWindows.indexOf(pos);
540 if (localLOGV || DEBUG_FOCUS) Log.v(
541 TAG, "Adding window " + window + " at "
542 + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
543 mWindows.add(i+1, window);
544 }
545
546 private void placeWindowBefore(Object pos, WindowState window) {
547 final int i = mWindows.indexOf(pos);
548 if (localLOGV || DEBUG_FOCUS) Log.v(
549 TAG, "Adding window " + window + " at "
550 + i + " of " + mWindows.size() + " (before " + pos + ")");
551 mWindows.add(i, window);
552 }
553
554 //This method finds out the index of a window that has the same app token as
555 //win. used for z ordering the windows in mWindows
556 private int findIdxBasedOnAppTokens(WindowState win) {
557 //use a local variable to cache mWindows
558 ArrayList localmWindows = mWindows;
559 int jmax = localmWindows.size();
560 if(jmax == 0) {
561 return -1;
562 }
563 for(int j = (jmax-1); j >= 0; j--) {
564 WindowState wentry = (WindowState)localmWindows.get(j);
565 if(wentry.mAppToken == win.mAppToken) {
566 return j;
567 }
568 }
569 return -1;
570 }
571
572 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
573 final IWindow client = win.mClient;
574 final WindowToken token = win.mToken;
575 final ArrayList localmWindows = mWindows;
576
577 final int N = localmWindows.size();
578 final WindowState attached = win.mAttachedWindow;
579 int i;
580 if (attached == null) {
581 int tokenWindowsPos = token.windows.size();
582 if (token.appWindowToken != null) {
583 int index = tokenWindowsPos-1;
584 if (index >= 0) {
585 // If this application has existing windows, we
586 // simply place the new window on top of them... but
587 // keep the starting window on top.
588 if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
589 // Base windows go behind everything else.
590 placeWindowBefore(token.windows.get(0), win);
591 tokenWindowsPos = 0;
592 } else {
593 AppWindowToken atoken = win.mAppToken;
594 if (atoken != null &&
595 token.windows.get(index) == atoken.startingWindow) {
596 placeWindowBefore(token.windows.get(index), win);
597 tokenWindowsPos--;
598 } else {
599 int newIdx = findIdxBasedOnAppTokens(win);
600 if(newIdx != -1) {
601 //there is a window above this one associated with the same
602 //apptoken note that the window could be a floating window
603 //that was created later or a window at the top of the list of
604 //windows associated with this token.
605 localmWindows.add(newIdx+1, win);
606 }
607 }
608 }
609 } else {
610 if (localLOGV) Log.v(
611 TAG, "Figuring out where to add app window "
612 + client.asBinder() + " (token=" + token + ")");
613 // Figure out where the window should go, based on the
614 // order of applications.
615 final int NA = mAppTokens.size();
616 Object pos = null;
617 for (i=NA-1; i>=0; i--) {
618 AppWindowToken t = mAppTokens.get(i);
619 if (t == token) {
620 i--;
621 break;
622 }
623 if (t.windows.size() > 0) {
624 pos = t.windows.get(0);
625 }
626 }
627 // We now know the index into the apps. If we found
628 // an app window above, that gives us the position; else
629 // we need to look some more.
630 if (pos != null) {
631 // Move behind any windows attached to this one.
632 WindowToken atoken =
633 mTokenMap.get(((WindowState)pos).mClient.asBinder());
634 if (atoken != null) {
635 final int NC = atoken.windows.size();
636 if (NC > 0) {
637 WindowState bottom = atoken.windows.get(0);
638 if (bottom.mSubLayer < 0) {
639 pos = bottom;
640 }
641 }
642 }
643 placeWindowBefore(pos, win);
644 } else {
645 while (i >= 0) {
646 AppWindowToken t = mAppTokens.get(i);
647 final int NW = t.windows.size();
648 if (NW > 0) {
649 pos = t.windows.get(NW-1);
650 break;
651 }
652 i--;
653 }
654 if (pos != null) {
655 // Move in front of any windows attached to this
656 // one.
657 WindowToken atoken =
658 mTokenMap.get(((WindowState)pos).mClient.asBinder());
659 if (atoken != null) {
660 final int NC = atoken.windows.size();
661 if (NC > 0) {
662 WindowState top = atoken.windows.get(NC-1);
663 if (top.mSubLayer >= 0) {
664 pos = top;
665 }
666 }
667 }
668 placeWindowAfter(pos, win);
669 } else {
670 // Just search for the start of this layer.
671 final int myLayer = win.mBaseLayer;
672 for (i=0; i<N; i++) {
673 WindowState w = (WindowState)localmWindows.get(i);
674 if (w.mBaseLayer > myLayer) {
675 break;
676 }
677 }
678 if (localLOGV || DEBUG_FOCUS) Log.v(
679 TAG, "Adding window " + win + " at "
680 + i + " of " + N);
681 localmWindows.add(i, win);
682 }
683 }
684 }
685 } else {
686 // Figure out where window should go, based on layer.
687 final int myLayer = win.mBaseLayer;
688 for (i=N-1; i>=0; i--) {
689 if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
690 i++;
691 break;
692 }
693 }
694 if (i < 0) i = 0;
695 if (localLOGV || DEBUG_FOCUS) Log.v(
696 TAG, "Adding window " + win + " at "
697 + i + " of " + N);
698 localmWindows.add(i, win);
699 }
700 if (addToToken) {
701 token.windows.add(tokenWindowsPos, win);
702 }
703
704 } else {
705 // Figure out this window's ordering relative to the window
706 // it is attached to.
707 final int NA = token.windows.size();
708 final int sublayer = win.mSubLayer;
709 int largestSublayer = Integer.MIN_VALUE;
710 WindowState windowWithLargestSublayer = null;
711 for (i=0; i<NA; i++) {
712 WindowState w = token.windows.get(i);
713 final int wSublayer = w.mSubLayer;
714 if (wSublayer >= largestSublayer) {
715 largestSublayer = wSublayer;
716 windowWithLargestSublayer = w;
717 }
718 if (sublayer < 0) {
719 // For negative sublayers, we go below all windows
720 // in the same sublayer.
721 if (wSublayer >= sublayer) {
722 if (addToToken) {
723 token.windows.add(i, win);
724 }
725 placeWindowBefore(
726 wSublayer >= 0 ? attached : w, win);
727 break;
728 }
729 } else {
730 // For positive sublayers, we go above all windows
731 // in the same sublayer.
732 if (wSublayer > sublayer) {
733 if (addToToken) {
734 token.windows.add(i, win);
735 }
736 placeWindowBefore(w, win);
737 break;
738 }
739 }
740 }
741 if (i >= NA) {
742 if (addToToken) {
743 token.windows.add(win);
744 }
745 if (sublayer < 0) {
746 placeWindowBefore(attached, win);
747 } else {
748 placeWindowAfter(largestSublayer >= 0
749 ? windowWithLargestSublayer
750 : attached,
751 win);
752 }
753 }
754 }
755
756 if (win.mAppToken != null && addToToken) {
757 win.mAppToken.allAppWindows.add(win);
758 }
759 }
760
761 static boolean canBeImeTarget(WindowState w) {
762 final int fl = w.mAttrs.flags
763 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
764 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
765 return w.isVisibleOrAdding();
766 }
767 return false;
768 }
769
770 int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
771 final ArrayList localmWindows = mWindows;
772 final int N = localmWindows.size();
773 WindowState w = null;
774 int i = N;
775 while (i > 0) {
776 i--;
777 w = (WindowState)localmWindows.get(i);
778
779 //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
780 // + Integer.toHexString(w.mAttrs.flags));
781 if (canBeImeTarget(w)) {
782 //Log.i(TAG, "Putting input method here!");
783
784 // Yet more tricksyness! If this window is a "starting"
785 // window, we do actually want to be on top of it, but
786 // it is not -really- where input will go. So if the caller
787 // is not actually looking to move the IME, look down below
788 // for a real window to target...
789 if (!willMove
790 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
791 && i > 0) {
792 WindowState wb = (WindowState)localmWindows.get(i-1);
793 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
794 i--;
795 w = wb;
796 }
797 }
798 break;
799 }
800 }
801
802 mUpcomingInputMethodTarget = w;
803
804 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
805 + w + " willMove=" + willMove);
806
807 if (willMove && w != null) {
808 final WindowState curTarget = mInputMethodTarget;
809 if (curTarget != null && curTarget.mAppToken != null) {
810
811 // Now some fun for dealing with window animations that
812 // modify the Z order. We need to look at all windows below
813 // the current target that are in this app, finding the highest
814 // visible one in layering.
815 AppWindowToken token = curTarget.mAppToken;
816 WindowState highestTarget = null;
817 int highestPos = 0;
818 if (token.animating || token.animation != null) {
819 int pos = 0;
820 pos = localmWindows.indexOf(curTarget);
821 while (pos >= 0) {
822 WindowState win = (WindowState)localmWindows.get(pos);
823 if (win.mAppToken != token) {
824 break;
825 }
826 if (!win.mRemoved) {
827 if (highestTarget == null || win.mAnimLayer >
828 highestTarget.mAnimLayer) {
829 highestTarget = win;
830 highestPos = pos;
831 }
832 }
833 pos--;
834 }
835 }
836
837 if (highestTarget != null) {
838 if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
839 + mNextAppTransition + " " + highestTarget
840 + " animating=" + highestTarget.isAnimating()
841 + " layer=" + highestTarget.mAnimLayer
842 + " new layer=" + w.mAnimLayer);
843
844 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
845 // If we are currently setting up for an animation,
846 // hold everything until we can find out what will happen.
847 mInputMethodTargetWaitingAnim = true;
848 mInputMethodTarget = highestTarget;
849 return highestPos + 1;
850 } else if (highestTarget.isAnimating() &&
851 highestTarget.mAnimLayer > w.mAnimLayer) {
852 // If the window we are currently targeting is involved
853 // with an animation, and it is on top of the next target
854 // we will be over, then hold off on moving until
855 // that is done.
856 mInputMethodTarget = highestTarget;
857 return highestPos + 1;
858 }
859 }
860 }
861 }
862
863 //Log.i(TAG, "Placing input method @" + (i+1));
864 if (w != null) {
865 if (willMove) {
866 RuntimeException e = new RuntimeException();
867 e.fillInStackTrace();
868 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
869 + mInputMethodTarget + " to " + w, e);
870 mInputMethodTarget = w;
871 if (w.mAppToken != null) {
872 setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
873 } else {
874 setInputMethodAnimLayerAdjustment(0);
875 }
876 }
877 return i+1;
878 }
879 if (willMove) {
880 RuntimeException e = new RuntimeException();
881 e.fillInStackTrace();
882 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
883 + mInputMethodTarget + " to null", e);
884 mInputMethodTarget = null;
885 setInputMethodAnimLayerAdjustment(0);
886 }
887 return -1;
888 }
889
890 void addInputMethodWindowToListLocked(WindowState win) {
891 int pos = findDesiredInputMethodWindowIndexLocked(true);
892 if (pos >= 0) {
893 win.mTargetAppToken = mInputMethodTarget.mAppToken;
894 mWindows.add(pos, win);
895 moveInputMethodDialogsLocked(pos+1);
896 return;
897 }
898 win.mTargetAppToken = null;
899 addWindowToListInOrderLocked(win, true);
900 moveInputMethodDialogsLocked(pos);
901 }
902
903 void setInputMethodAnimLayerAdjustment(int adj) {
904 if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
905 mInputMethodAnimLayerAdjustment = adj;
906 WindowState imw = mInputMethodWindow;
907 if (imw != null) {
908 imw.mAnimLayer = imw.mLayer + adj;
909 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
910 + " anim layer: " + imw.mAnimLayer);
911 int wi = imw.mChildWindows.size();
912 while (wi > 0) {
913 wi--;
914 WindowState cw = (WindowState)imw.mChildWindows.get(wi);
915 cw.mAnimLayer = cw.mLayer + adj;
916 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
917 + " anim layer: " + cw.mAnimLayer);
918 }
919 }
920 int di = mInputMethodDialogs.size();
921 while (di > 0) {
922 di --;
923 imw = mInputMethodDialogs.get(di);
924 imw.mAnimLayer = imw.mLayer + adj;
925 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
926 + " anim layer: " + imw.mAnimLayer);
927 }
928 }
929
930 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
931 int wpos = mWindows.indexOf(win);
932 if (wpos >= 0) {
933 if (wpos < interestingPos) interestingPos--;
934 mWindows.remove(wpos);
935 int NC = win.mChildWindows.size();
936 while (NC > 0) {
937 NC--;
938 WindowState cw = (WindowState)win.mChildWindows.get(NC);
939 int cpos = mWindows.indexOf(cw);
940 if (cpos >= 0) {
941 if (cpos < interestingPos) interestingPos--;
942 mWindows.remove(cpos);
943 }
944 }
945 }
946 return interestingPos;
947 }
948
949 private void reAddWindowToListInOrderLocked(WindowState win) {
950 addWindowToListInOrderLocked(win, false);
951 // This is a hack to get all of the child windows added as well
952 // at the right position. Child windows should be rare and
953 // this case should be rare, so it shouldn't be that big a deal.
954 int wpos = mWindows.indexOf(win);
955 if (wpos >= 0) {
956 mWindows.remove(wpos);
957 reAddWindowLocked(wpos, win);
958 }
959 }
960
961 void logWindowList(String prefix) {
962 int N = mWindows.size();
963 while (N > 0) {
964 N--;
965 Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
966 }
967 }
968
969 void moveInputMethodDialogsLocked(int pos) {
970 ArrayList<WindowState> dialogs = mInputMethodDialogs;
971
972 final int N = dialogs.size();
973 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
974 for (int i=0; i<N; i++) {
975 pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
976 }
977 if (DEBUG_INPUT_METHOD) {
978 Log.v(TAG, "Window list w/pos=" + pos);
979 logWindowList(" ");
980 }
981
982 if (pos >= 0) {
983 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
984 if (pos < mWindows.size()) {
985 WindowState wp = (WindowState)mWindows.get(pos);
986 if (wp == mInputMethodWindow) {
987 pos++;
988 }
989 }
990 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
991 for (int i=0; i<N; i++) {
992 WindowState win = dialogs.get(i);
993 win.mTargetAppToken = targetAppToken;
994 pos = reAddWindowLocked(pos, win);
995 }
996 if (DEBUG_INPUT_METHOD) {
997 Log.v(TAG, "Final window list:");
998 logWindowList(" ");
999 }
1000 return;
1001 }
1002 for (int i=0; i<N; i++) {
1003 WindowState win = dialogs.get(i);
1004 win.mTargetAppToken = null;
1005 reAddWindowToListInOrderLocked(win);
1006 if (DEBUG_INPUT_METHOD) {
1007 Log.v(TAG, "No IM target, final list:");
1008 logWindowList(" ");
1009 }
1010 }
1011 }
1012
1013 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
1014 final WindowState imWin = mInputMethodWindow;
1015 final int DN = mInputMethodDialogs.size();
1016 if (imWin == null && DN == 0) {
1017 return false;
1018 }
1019
1020 int imPos = findDesiredInputMethodWindowIndexLocked(true);
1021 if (imPos >= 0) {
1022 // In this case, the input method windows are to be placed
1023 // immediately above the window they are targeting.
1024
1025 // First check to see if the input method windows are already
1026 // located here, and contiguous.
1027 final int N = mWindows.size();
1028 WindowState firstImWin = imPos < N
1029 ? (WindowState)mWindows.get(imPos) : null;
1030
1031 // Figure out the actual input method window that should be
1032 // at the bottom of their stack.
1033 WindowState baseImWin = imWin != null
1034 ? imWin : mInputMethodDialogs.get(0);
1035 if (baseImWin.mChildWindows.size() > 0) {
1036 WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
1037 if (cw.mSubLayer < 0) baseImWin = cw;
1038 }
1039
1040 if (firstImWin == baseImWin) {
1041 // The windows haven't moved... but are they still contiguous?
1042 // First find the top IM window.
1043 int pos = imPos+1;
1044 while (pos < N) {
1045 if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
1046 break;
1047 }
1048 pos++;
1049 }
1050 pos++;
1051 // Now there should be no more input method windows above.
1052 while (pos < N) {
1053 if (((WindowState)mWindows.get(pos)).mIsImWindow) {
1054 break;
1055 }
1056 pos++;
1057 }
1058 if (pos >= N) {
1059 // All is good!
1060 return false;
1061 }
1062 }
1063
1064 if (imWin != null) {
1065 if (DEBUG_INPUT_METHOD) {
1066 Log.v(TAG, "Moving IM from " + imPos);
1067 logWindowList(" ");
1068 }
1069 imPos = tmpRemoveWindowLocked(imPos, imWin);
1070 if (DEBUG_INPUT_METHOD) {
1071 Log.v(TAG, "List after moving with new pos " + imPos + ":");
1072 logWindowList(" ");
1073 }
1074 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
1075 reAddWindowLocked(imPos, imWin);
1076 if (DEBUG_INPUT_METHOD) {
1077 Log.v(TAG, "List after moving IM to " + imPos + ":");
1078 logWindowList(" ");
1079 }
1080 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
1081 } else {
1082 moveInputMethodDialogsLocked(imPos);
1083 }
1084
1085 } else {
1086 // In this case, the input method windows go in a fixed layer,
1087 // because they aren't currently associated with a focus window.
1088
1089 if (imWin != null) {
1090 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
1091 tmpRemoveWindowLocked(0, imWin);
1092 imWin.mTargetAppToken = null;
1093 reAddWindowToListInOrderLocked(imWin);
1094 if (DEBUG_INPUT_METHOD) {
1095 Log.v(TAG, "List with no IM target:");
1096 logWindowList(" ");
1097 }
1098 if (DN > 0) moveInputMethodDialogsLocked(-1);;
1099 } else {
1100 moveInputMethodDialogsLocked(-1);;
1101 }
1102
1103 }
1104
1105 if (needAssignLayers) {
1106 assignLayersLocked();
1107 }
1108
1109 return true;
1110 }
1111
1112 void adjustInputMethodDialogsLocked() {
1113 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
1114 }
1115
1116 public int addWindow(Session session, IWindow client,
1117 WindowManager.LayoutParams attrs, int viewVisibility,
1118 Rect outContentInsets) {
1119 int res = mPolicy.checkAddPermission(attrs);
1120 if (res != WindowManagerImpl.ADD_OKAY) {
1121 return res;
1122 }
1123
1124 boolean reportNewConfig = false;
1125 WindowState attachedWindow = null;
1126 WindowState win = null;
1127
1128 synchronized(mWindowMap) {
1129 // Instantiating a Display requires talking with the simulator,
1130 // so don't do it until we know the system is mostly up and
1131 // running.
1132 if (mDisplay == null) {
1133 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1134 mDisplay = wm.getDefaultDisplay();
1135 mQueue.setDisplay(mDisplay);
1136 reportNewConfig = true;
1137 }
1138
1139 if (mWindowMap.containsKey(client.asBinder())) {
1140 Log.w(TAG, "Window " + client + " is already added");
1141 return WindowManagerImpl.ADD_DUPLICATE_ADD;
1142 }
1143
1144 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
1145 attachedWindow = windowForClientLocked(null, attrs.token);
1146 if (attachedWindow == null) {
1147 Log.w(TAG, "Attempted to add window with token that is not a window: "
1148 + attrs.token + ". Aborting.");
1149 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1150 }
1151 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
1152 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1153 Log.w(TAG, "Attempted to add window with token that is a sub-window: "
1154 + attrs.token + ". Aborting.");
1155 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1156 }
1157 }
1158
1159 boolean addToken = false;
1160 WindowToken token = mTokenMap.get(attrs.token);
1161 if (token == null) {
1162 if (attrs.type >= FIRST_APPLICATION_WINDOW
1163 && attrs.type <= LAST_APPLICATION_WINDOW) {
1164 Log.w(TAG, "Attempted to add application window with unknown token "
1165 + attrs.token + ". Aborting.");
1166 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1167 }
1168 if (attrs.type == TYPE_INPUT_METHOD) {
1169 Log.w(TAG, "Attempted to add input method window with unknown token "
1170 + attrs.token + ". Aborting.");
1171 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1172 }
1173 token = new WindowToken(attrs.token, -1, false);
1174 addToken = true;
1175 } else if (attrs.type >= FIRST_APPLICATION_WINDOW
1176 && attrs.type <= LAST_APPLICATION_WINDOW) {
1177 AppWindowToken atoken = token.appWindowToken;
1178 if (atoken == null) {
1179 Log.w(TAG, "Attempted to add window with non-application token "
1180 + token + ". Aborting.");
1181 return WindowManagerImpl.ADD_NOT_APP_TOKEN;
1182 } else if (atoken.removed) {
1183 Log.w(TAG, "Attempted to add window with exiting application token "
1184 + token + ". Aborting.");
1185 return WindowManagerImpl.ADD_APP_EXITING;
1186 }
1187 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
1188 // No need for this guy!
1189 if (localLOGV) Log.v(
1190 TAG, "**** NO NEED TO START: " + attrs.getTitle());
1191 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
1192 }
1193 } else if (attrs.type == TYPE_INPUT_METHOD) {
1194 if (token.windowType != TYPE_INPUT_METHOD) {
1195 Log.w(TAG, "Attempted to add input method window with bad token "
1196 + attrs.token + ". Aborting.");
1197 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1198 }
1199 }
1200
1201 win = new WindowState(session, client, token,
1202 attachedWindow, attrs, viewVisibility);
1203 if (win.mDeathRecipient == null) {
1204 // Client has apparently died, so there is no reason to
1205 // continue.
1206 Log.w(TAG, "Adding window client " + client.asBinder()
1207 + " that is dead, aborting.");
1208 return WindowManagerImpl.ADD_APP_EXITING;
1209 }
1210
1211 mPolicy.adjustWindowParamsLw(win.mAttrs);
1212
1213 res = mPolicy.prepareAddWindowLw(win, attrs);
1214 if (res != WindowManagerImpl.ADD_OKAY) {
1215 return res;
1216 }
1217
1218 // From now on, no exceptions or errors allowed!
1219
1220 res = WindowManagerImpl.ADD_OKAY;
1221
1222 final long origId = Binder.clearCallingIdentity();
1223
1224 if (addToken) {
1225 mTokenMap.put(attrs.token, token);
1226 mTokenList.add(token);
1227 }
1228 win.attach();
1229 mWindowMap.put(client.asBinder(), win);
1230
1231 if (attrs.type == TYPE_APPLICATION_STARTING &&
1232 token.appWindowToken != null) {
1233 token.appWindowToken.startingWindow = win;
1234 }
1235
1236 boolean imMayMove = true;
1237
1238 if (attrs.type == TYPE_INPUT_METHOD) {
1239 mInputMethodWindow = win;
1240 addInputMethodWindowToListLocked(win);
1241 imMayMove = false;
1242 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
1243 mInputMethodDialogs.add(win);
1244 addWindowToListInOrderLocked(win, true);
1245 adjustInputMethodDialogsLocked();
1246 imMayMove = false;
1247 } else {
1248 addWindowToListInOrderLocked(win, true);
1249 }
1250
1251 win.mEnterAnimationPending = true;
1252
1253 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
1254
1255 if (mInTouchMode) {
1256 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
1257 }
1258 if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
1259 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
1260 }
1261
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001262 boolean focusChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 if (win.canReceiveKeys()) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001264 if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
1265 == true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 imMayMove = false;
1267 }
1268 }
1269
1270 if (imMayMove) {
1271 moveInputMethodWindowsIfNeededLocked(false);
1272 }
1273
1274 assignLayersLocked();
1275 // Don't do layout here, the window must call
1276 // relayout to be displayed, so we'll do it there.
1277
1278 //dump();
1279
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001280 if (focusChanged) {
1281 if (mCurrentFocus != null) {
1282 mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
1283 }
1284 }
1285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 if (localLOGV) Log.v(
1287 TAG, "New client " + client.asBinder()
1288 + ": window=" + win);
1289 }
1290
1291 // sendNewConfiguration() checks caller permissions so we must call it with
1292 // privilege. updateOrientationFromAppTokens() clears and resets the caller
1293 // identity anyway, so it's safe to just clear & restore around this whole
1294 // block.
1295 final long origId = Binder.clearCallingIdentity();
1296 if (reportNewConfig) {
1297 sendNewConfiguration();
1298 } else {
1299 // Update Orientation after adding a window, only if the window needs to be
1300 // displayed right away
1301 if (win.isVisibleOrAdding()) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001302 if (updateOrientationFromAppTokens(null, null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 sendNewConfiguration();
1304 }
1305 }
1306 }
1307 Binder.restoreCallingIdentity(origId);
1308
1309 return res;
1310 }
1311
1312 public void removeWindow(Session session, IWindow client) {
1313 synchronized(mWindowMap) {
1314 WindowState win = windowForClientLocked(session, client);
1315 if (win == null) {
1316 return;
1317 }
1318 removeWindowLocked(session, win);
1319 }
1320 }
1321
1322 public void removeWindowLocked(Session session, WindowState win) {
1323
1324 if (localLOGV || DEBUG_FOCUS) Log.v(
1325 TAG, "Remove " + win + " client="
1326 + Integer.toHexString(System.identityHashCode(
1327 win.mClient.asBinder()))
1328 + ", surface=" + win.mSurface);
1329
1330 final long origId = Binder.clearCallingIdentity();
1331
1332 if (DEBUG_APP_TRANSITIONS) Log.v(
1333 TAG, "Remove " + win + ": mSurface=" + win.mSurface
1334 + " mExiting=" + win.mExiting
1335 + " isAnimating=" + win.isAnimating()
1336 + " app-animation="
1337 + (win.mAppToken != null ? win.mAppToken.animation : null)
1338 + " inPendingTransaction="
1339 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
1340 + " mDisplayFrozen=" + mDisplayFrozen);
1341 // Visibility of the removed window. Will be used later to update orientation later on.
1342 boolean wasVisible = false;
1343 // First, see if we need to run an animation. If we do, we have
1344 // to hold off on removing the window until the animation is done.
1345 // If the display is frozen, just remove immediately, since the
1346 // animation wouldn't be seen.
1347 if (win.mSurface != null && !mDisplayFrozen) {
1348 // If we are not currently running the exit animation, we
1349 // need to see about starting one.
1350 if (wasVisible=win.isWinVisibleLw()) {
1351
1352 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1353 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1354 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1355 }
1356 // Try starting an animation.
1357 if (applyAnimationLocked(win, transit, false)) {
1358 win.mExiting = true;
1359 }
1360 }
1361 if (win.mExiting || win.isAnimating()) {
1362 // The exit animation is running... wait for it!
1363 //Log.i(TAG, "*** Running exit animation...");
1364 win.mExiting = true;
1365 win.mRemoveOnExit = true;
1366 mLayoutNeeded = true;
1367 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
1368 performLayoutAndPlaceSurfacesLocked();
1369 if (win.mAppToken != null) {
1370 win.mAppToken.updateReportedVisibilityLocked();
1371 }
1372 //dump();
1373 Binder.restoreCallingIdentity(origId);
1374 return;
1375 }
1376 }
1377
1378 removeWindowInnerLocked(session, win);
1379 // Removing a visible window will effect the computed orientation
1380 // So just update orientation if needed.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001381 if (wasVisible && computeForcedAppOrientationLocked()
1382 != mForcedAppOrientation) {
1383 mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1386 Binder.restoreCallingIdentity(origId);
1387 }
1388
1389 private void removeWindowInnerLocked(Session session, WindowState win) {
1390 mKeyWaiter.releasePendingPointerLocked(win.mSession);
1391 mKeyWaiter.releasePendingTrackballLocked(win.mSession);
1392
1393 win.mRemoved = true;
1394
1395 if (mInputMethodTarget == win) {
1396 moveInputMethodWindowsIfNeededLocked(false);
1397 }
1398
1399 mPolicy.removeWindowLw(win);
1400 win.removeLocked();
1401
1402 mWindowMap.remove(win.mClient.asBinder());
1403 mWindows.remove(win);
1404
1405 if (mInputMethodWindow == win) {
1406 mInputMethodWindow = null;
1407 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
1408 mInputMethodDialogs.remove(win);
1409 }
1410
1411 final WindowToken token = win.mToken;
1412 final AppWindowToken atoken = win.mAppToken;
1413 token.windows.remove(win);
1414 if (atoken != null) {
1415 atoken.allAppWindows.remove(win);
1416 }
1417 if (localLOGV) Log.v(
1418 TAG, "**** Removing window " + win + ": count="
1419 + token.windows.size());
1420 if (token.windows.size() == 0) {
1421 if (!token.explicit) {
1422 mTokenMap.remove(token.token);
1423 mTokenList.remove(token);
1424 } else if (atoken != null) {
1425 atoken.firstWindowDrawn = false;
1426 }
1427 }
1428
1429 if (atoken != null) {
1430 if (atoken.startingWindow == win) {
1431 atoken.startingWindow = null;
1432 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
1433 // If this is the last window and we had requested a starting
1434 // transition window, well there is no point now.
1435 atoken.startingData = null;
1436 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
1437 // If this is the last window except for a starting transition
1438 // window, we need to get rid of the starting transition.
1439 if (DEBUG_STARTING_WINDOW) {
1440 Log.v(TAG, "Schedule remove starting " + token
1441 + ": no more real windows");
1442 }
1443 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
1444 mH.sendMessage(m);
1445 }
1446 }
1447
1448 if (!mInLayout) {
1449 assignLayersLocked();
1450 mLayoutNeeded = true;
1451 performLayoutAndPlaceSurfacesLocked();
1452 if (win.mAppToken != null) {
1453 win.mAppToken.updateReportedVisibilityLocked();
1454 }
1455 }
1456 }
1457
1458 private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
1459 long origId = Binder.clearCallingIdentity();
1460 try {
1461 synchronized (mWindowMap) {
1462 WindowState w = windowForClientLocked(session, client);
1463 if ((w != null) && (w.mSurface != null)) {
1464 Surface.openTransaction();
1465 try {
1466 w.mSurface.setTransparentRegionHint(region);
1467 } finally {
1468 Surface.closeTransaction();
1469 }
1470 }
1471 }
1472 } finally {
1473 Binder.restoreCallingIdentity(origId);
1474 }
1475 }
1476
1477 void setInsetsWindow(Session session, IWindow client,
1478 int touchableInsets, Rect contentInsets,
1479 Rect visibleInsets) {
1480 long origId = Binder.clearCallingIdentity();
1481 try {
1482 synchronized (mWindowMap) {
1483 WindowState w = windowForClientLocked(session, client);
1484 if (w != null) {
1485 w.mGivenInsetsPending = false;
1486 w.mGivenContentInsets.set(contentInsets);
1487 w.mGivenVisibleInsets.set(visibleInsets);
1488 w.mTouchableInsets = touchableInsets;
1489 mLayoutNeeded = true;
1490 performLayoutAndPlaceSurfacesLocked();
1491 }
1492 }
1493 } finally {
1494 Binder.restoreCallingIdentity(origId);
1495 }
1496 }
1497
1498 public void getWindowDisplayFrame(Session session, IWindow client,
1499 Rect outDisplayFrame) {
1500 synchronized(mWindowMap) {
1501 WindowState win = windowForClientLocked(session, client);
1502 if (win == null) {
1503 outDisplayFrame.setEmpty();
1504 return;
1505 }
1506 outDisplayFrame.set(win.mDisplayFrame);
1507 }
1508 }
1509
1510 public int relayoutWindow(Session session, IWindow client,
1511 WindowManager.LayoutParams attrs, int requestedWidth,
1512 int requestedHeight, int viewVisibility, boolean insetsPending,
1513 Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
1514 Surface outSurface) {
1515 boolean displayed = false;
1516 boolean inTouchMode;
1517 Configuration newConfig = null;
1518 long origId = Binder.clearCallingIdentity();
1519
1520 synchronized(mWindowMap) {
1521 WindowState win = windowForClientLocked(session, client);
1522 if (win == null) {
1523 return 0;
1524 }
1525 win.mRequestedWidth = requestedWidth;
1526 win.mRequestedHeight = requestedHeight;
1527
1528 if (attrs != null) {
1529 mPolicy.adjustWindowParamsLw(attrs);
1530 }
1531
1532 int attrChanges = 0;
1533 int flagChanges = 0;
1534 if (attrs != null) {
1535 flagChanges = win.mAttrs.flags ^= attrs.flags;
1536 attrChanges = win.mAttrs.copyFrom(attrs);
1537 }
1538
1539 if (localLOGV) Log.v(
1540 TAG, "Relayout given client " + client.asBinder()
1541 + " (" + win.mAttrs.getTitle() + ")");
1542
1543
1544 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
1545 win.mAlpha = attrs.alpha;
1546 }
1547
1548 final boolean scaledWindow =
1549 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
1550
1551 if (scaledWindow) {
1552 // requested{Width|Height} Surface's physical size
1553 // attrs.{width|height} Size on screen
1554 win.mHScale = (attrs.width != requestedWidth) ?
1555 (attrs.width / (float)requestedWidth) : 1.0f;
1556 win.mVScale = (attrs.height != requestedHeight) ?
1557 (attrs.height / (float)requestedHeight) : 1.0f;
1558 }
1559
1560 boolean imMayMove = (flagChanges&(
1561 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
1562 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
1563
1564 boolean focusMayChange = win.mViewVisibility != viewVisibility
1565 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
1566 || (!win.mRelayoutCalled);
1567
1568 win.mRelayoutCalled = true;
1569 final int oldVisibility = win.mViewVisibility;
1570 win.mViewVisibility = viewVisibility;
1571 if (viewVisibility == View.VISIBLE &&
1572 (win.mAppToken == null || !win.mAppToken.clientHidden)) {
1573 displayed = !win.isVisibleLw();
1574 if (win.mExiting) {
1575 win.mExiting = false;
1576 win.mAnimation = null;
1577 }
1578 if (win.mDestroying) {
1579 win.mDestroying = false;
1580 mDestroySurface.remove(win);
1581 }
1582 if (oldVisibility == View.GONE) {
1583 win.mEnterAnimationPending = true;
1584 }
1585 if (displayed && win.mSurface != null && !win.mDrawPending
1586 && !win.mCommitDrawPending && !mDisplayFrozen) {
1587 applyEnterAnimationLocked(win);
1588 }
1589 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
1590 // To change the format, we need to re-build the surface.
1591 win.destroySurfaceLocked();
1592 displayed = true;
1593 }
1594 try {
1595 Surface surface = win.createSurfaceLocked();
1596 if (surface != null) {
1597 outSurface.copyFrom(surface);
1598 } else {
1599 outSurface.clear();
1600 }
1601 } catch (Exception e) {
1602 Log.w(TAG, "Exception thrown when creating surface for client "
1603 + client + " (" + win.mAttrs.getTitle() + ")",
1604 e);
1605 Binder.restoreCallingIdentity(origId);
1606 return 0;
1607 }
1608 if (displayed) {
1609 focusMayChange = true;
1610 }
1611 if (win.mAttrs.type == TYPE_INPUT_METHOD
1612 && mInputMethodWindow == null) {
1613 mInputMethodWindow = win;
1614 imMayMove = true;
1615 }
1616 } else {
1617 win.mEnterAnimationPending = false;
1618 if (win.mSurface != null) {
1619 // If we are not currently running the exit animation, we
1620 // need to see about starting one.
1621 if (!win.mExiting) {
1622 // Try starting an animation; if there isn't one, we
1623 // can destroy the surface right away.
1624 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1625 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1626 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1627 }
1628 if (win.isWinVisibleLw() &&
1629 applyAnimationLocked(win, transit, false)) {
1630 win.mExiting = true;
1631 mKeyWaiter.finishedKey(session, client, true,
1632 KeyWaiter.RETURN_NOTHING);
1633 } else if (win.isAnimating()) {
1634 // Currently in a hide animation... turn this into
1635 // an exit.
1636 win.mExiting = true;
1637 } else {
1638 if (mInputMethodWindow == win) {
1639 mInputMethodWindow = null;
1640 }
1641 win.destroySurfaceLocked();
1642 }
1643 }
1644 }
1645 outSurface.clear();
1646 }
1647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 if (focusMayChange) {
1649 //System.out.println("Focus may change: " + win.mAttrs.getTitle());
1650 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 imMayMove = false;
1652 }
1653 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
1654 }
1655
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001656 // updateFocusedWindowLocked() already assigned layers so we only need to
1657 // reassign them at this point if the IM window state gets shuffled
1658 boolean assignLayers = false;
1659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 if (imMayMove) {
1661 if (moveInputMethodWindowsIfNeededLocked(false)) {
1662 assignLayers = true;
1663 }
1664 }
1665
1666 mLayoutNeeded = true;
1667 win.mGivenInsetsPending = insetsPending;
1668 if (assignLayers) {
1669 assignLayersLocked();
1670 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001671 newConfig = updateOrientationFromAppTokensLocked(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 performLayoutAndPlaceSurfacesLocked();
1673 if (win.mAppToken != null) {
1674 win.mAppToken.updateReportedVisibilityLocked();
1675 }
1676 outFrame.set(win.mFrame);
1677 outContentInsets.set(win.mContentInsets);
1678 outVisibleInsets.set(win.mVisibleInsets);
1679 if (localLOGV) Log.v(
1680 TAG, "Relayout given client " + client.asBinder()
1681 + ", requestedWidth=" + requestedWidth
1682 + ", requestedHeight=" + requestedHeight
1683 + ", viewVisibility=" + viewVisibility
1684 + "\nRelayout returning frame=" + outFrame
1685 + ", surface=" + outSurface);
1686
1687 if (localLOGV || DEBUG_FOCUS) Log.v(
1688 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
1689
1690 inTouchMode = mInTouchMode;
1691 }
1692
1693 if (newConfig != null) {
1694 sendNewConfiguration();
1695 }
1696
1697 Binder.restoreCallingIdentity(origId);
1698
1699 return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
1700 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
1701 }
1702
1703 public void finishDrawingWindow(Session session, IWindow client) {
1704 final long origId = Binder.clearCallingIdentity();
1705 synchronized(mWindowMap) {
1706 WindowState win = windowForClientLocked(session, client);
1707 if (win != null && win.finishDrawingLocked()) {
1708 mLayoutNeeded = true;
1709 performLayoutAndPlaceSurfacesLocked();
1710 }
1711 }
1712 Binder.restoreCallingIdentity(origId);
1713 }
1714
1715 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
1716 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
1717 + (lp != null ? lp.packageName : null)
1718 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
1719 if (lp != null && lp.windowAnimations != 0) {
1720 // If this is a system resource, don't try to load it from the
1721 // application resources. It is nice to avoid loading application
1722 // resources if we can.
1723 String packageName = lp.packageName != null ? lp.packageName : "android";
1724 int resId = lp.windowAnimations;
1725 if ((resId&0xFF000000) == 0x01000000) {
1726 packageName = "android";
1727 }
1728 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
1729 + packageName);
1730 return AttributeCache.instance().get(packageName, resId,
1731 com.android.internal.R.styleable.WindowAnimation);
1732 }
1733 return null;
1734 }
1735
1736 private void applyEnterAnimationLocked(WindowState win) {
1737 int transit = WindowManagerPolicy.TRANSIT_SHOW;
1738 if (win.mEnterAnimationPending) {
1739 win.mEnterAnimationPending = false;
1740 transit = WindowManagerPolicy.TRANSIT_ENTER;
1741 }
1742
1743 applyAnimationLocked(win, transit, true);
1744 }
1745
1746 private boolean applyAnimationLocked(WindowState win,
1747 int transit, boolean isEntrance) {
1748 if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
1749 // If we are trying to apply an animation, but already running
1750 // an animation of the same type, then just leave that one alone.
1751 return true;
1752 }
1753
1754 // Only apply an animation if the display isn't frozen. If it is
1755 // frozen, there is no reason to animate and it can cause strange
1756 // artifacts when we unfreeze the display if some different animation
1757 // is running.
1758 if (!mDisplayFrozen) {
1759 int anim = mPolicy.selectAnimationLw(win, transit);
1760 int attr = -1;
1761 Animation a = null;
1762 if (anim != 0) {
1763 a = AnimationUtils.loadAnimation(mContext, anim);
1764 } else {
1765 switch (transit) {
1766 case WindowManagerPolicy.TRANSIT_ENTER:
1767 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
1768 break;
1769 case WindowManagerPolicy.TRANSIT_EXIT:
1770 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
1771 break;
1772 case WindowManagerPolicy.TRANSIT_SHOW:
1773 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
1774 break;
1775 case WindowManagerPolicy.TRANSIT_HIDE:
1776 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
1777 break;
1778 }
1779 if (attr >= 0) {
1780 a = loadAnimation(win.mAttrs, attr);
1781 }
1782 }
1783 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
1784 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
1785 + " mAnimation=" + win.mAnimation
1786 + " isEntrance=" + isEntrance);
1787 if (a != null) {
1788 if (DEBUG_ANIM) {
1789 RuntimeException e = new RuntimeException();
1790 e.fillInStackTrace();
1791 Log.v(TAG, "Loaded animation " + a + " for " + win, e);
1792 }
1793 win.setAnimation(a);
1794 win.mAnimationIsEntrance = isEntrance;
1795 }
1796 } else {
1797 win.clearAnimation();
1798 }
1799
1800 return win.mAnimation != null;
1801 }
1802
1803 private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
1804 int anim = 0;
1805 Context context = mContext;
1806 if (animAttr >= 0) {
1807 AttributeCache.Entry ent = getCachedAnimations(lp);
1808 if (ent != null) {
1809 context = ent.context;
1810 anim = ent.array.getResourceId(animAttr, 0);
1811 }
1812 }
1813 if (anim != 0) {
1814 return AnimationUtils.loadAnimation(context, anim);
1815 }
1816 return null;
1817 }
1818
1819 private boolean applyAnimationLocked(AppWindowToken wtoken,
1820 WindowManager.LayoutParams lp, int transit, boolean enter) {
1821 // Only apply an animation if the display isn't frozen. If it is
1822 // frozen, there is no reason to animate and it can cause strange
1823 // artifacts when we unfreeze the display if some different animation
1824 // is running.
1825 if (!mDisplayFrozen) {
1826 int animAttr = 0;
1827 switch (transit) {
1828 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
1829 animAttr = enter
1830 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
1831 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
1832 break;
1833 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
1834 animAttr = enter
1835 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
1836 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
1837 break;
1838 case WindowManagerPolicy.TRANSIT_TASK_OPEN:
1839 animAttr = enter
1840 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
1841 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
1842 break;
1843 case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
1844 animAttr = enter
1845 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
1846 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
1847 break;
1848 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
1849 animAttr = enter
1850 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
1851 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
1852 break;
1853 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
1854 animAttr = enter
1855 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
1856 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
1857 break;
1858 }
1859 Animation a = loadAnimation(lp, animAttr);
1860 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
1861 + " anim=" + a
1862 + " animAttr=0x" + Integer.toHexString(animAttr)
1863 + " transit=" + transit);
1864 if (a != null) {
1865 if (DEBUG_ANIM) {
1866 RuntimeException e = new RuntimeException();
1867 e.fillInStackTrace();
1868 Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
1869 }
1870 wtoken.setAnimation(a);
1871 }
1872 } else {
1873 wtoken.clearAnimation();
1874 }
1875
1876 return wtoken.animation != null;
1877 }
1878
1879 // -------------------------------------------------------------
1880 // Application Window Tokens
1881 // -------------------------------------------------------------
1882
1883 public void validateAppTokens(List tokens) {
1884 int v = tokens.size()-1;
1885 int m = mAppTokens.size()-1;
1886 while (v >= 0 && m >= 0) {
1887 AppWindowToken wtoken = mAppTokens.get(m);
1888 if (wtoken.removed) {
1889 m--;
1890 continue;
1891 }
1892 if (tokens.get(v) != wtoken.token) {
1893 Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
1894 + " @ " + v + ", internal is " + wtoken.token + " @ " + m);
1895 }
1896 v--;
1897 m--;
1898 }
1899 while (v >= 0) {
1900 Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
1901 v--;
1902 }
1903 while (m >= 0) {
1904 AppWindowToken wtoken = mAppTokens.get(m);
1905 if (!wtoken.removed) {
1906 Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
1907 }
1908 m--;
1909 }
1910 }
1911
1912 boolean checkCallingPermission(String permission, String func) {
1913 // Quick check: if the calling permission is me, it's all okay.
1914 if (Binder.getCallingPid() == Process.myPid()) {
1915 return true;
1916 }
1917
1918 if (mContext.checkCallingPermission(permission)
1919 == PackageManager.PERMISSION_GRANTED) {
1920 return true;
1921 }
1922 String msg = "Permission Denial: " + func + " from pid="
1923 + Binder.getCallingPid()
1924 + ", uid=" + Binder.getCallingUid()
1925 + " requires " + permission;
1926 Log.w(TAG, msg);
1927 return false;
1928 }
1929
1930 AppWindowToken findAppWindowToken(IBinder token) {
1931 WindowToken wtoken = mTokenMap.get(token);
1932 if (wtoken == null) {
1933 return null;
1934 }
1935 return wtoken.appWindowToken;
1936 }
1937
1938 public void addWindowToken(IBinder token, int type) {
1939 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1940 "addWindowToken()")) {
1941 return;
1942 }
1943
1944 synchronized(mWindowMap) {
1945 WindowToken wtoken = mTokenMap.get(token);
1946 if (wtoken != null) {
1947 Log.w(TAG, "Attempted to add existing input method token: " + token);
1948 return;
1949 }
1950 wtoken = new WindowToken(token, type, true);
1951 mTokenMap.put(token, wtoken);
1952 mTokenList.add(wtoken);
1953 }
1954 }
1955
1956 public void removeWindowToken(IBinder token) {
1957 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1958 "removeWindowToken()")) {
1959 return;
1960 }
1961
1962 final long origId = Binder.clearCallingIdentity();
1963 synchronized(mWindowMap) {
1964 WindowToken wtoken = mTokenMap.remove(token);
1965 mTokenList.remove(wtoken);
1966 if (wtoken != null) {
1967 boolean delayed = false;
1968 if (!wtoken.hidden) {
1969 wtoken.hidden = true;
1970
1971 final int N = wtoken.windows.size();
1972 boolean changed = false;
1973
1974 for (int i=0; i<N; i++) {
1975 WindowState win = wtoken.windows.get(i);
1976
1977 if (win.isAnimating()) {
1978 delayed = true;
1979 }
1980
1981 if (win.isVisibleNow()) {
1982 applyAnimationLocked(win,
1983 WindowManagerPolicy.TRANSIT_EXIT, false);
1984 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
1985 KeyWaiter.RETURN_NOTHING);
1986 changed = true;
1987 }
1988 }
1989
1990 if (changed) {
1991 mLayoutNeeded = true;
1992 performLayoutAndPlaceSurfacesLocked();
1993 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1994 }
1995
1996 if (delayed) {
1997 mExitingTokens.add(wtoken);
1998 }
1999 }
2000
2001 } else {
2002 Log.w(TAG, "Attempted to remove non-existing token: " + token);
2003 }
2004 }
2005 Binder.restoreCallingIdentity(origId);
2006 }
2007
2008 public void addAppToken(int addPos, IApplicationToken token,
2009 int groupId, int requestedOrientation, boolean fullscreen) {
2010 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2011 "addAppToken()")) {
2012 return;
2013 }
2014
2015 synchronized(mWindowMap) {
2016 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2017 if (wtoken != null) {
2018 Log.w(TAG, "Attempted to add existing app token: " + token);
2019 return;
2020 }
2021 wtoken = new AppWindowToken(token);
2022 wtoken.groupId = groupId;
2023 wtoken.appFullscreen = fullscreen;
2024 wtoken.requestedOrientation = requestedOrientation;
2025 mAppTokens.add(addPos, wtoken);
2026 if (Config.LOGV) Log.v(TAG, "Adding new app token: " + wtoken);
2027 mTokenMap.put(token.asBinder(), wtoken);
2028 mTokenList.add(wtoken);
2029
2030 // Application tokens start out hidden.
2031 wtoken.hidden = true;
2032 wtoken.hiddenRequested = true;
2033
2034 //dump();
2035 }
2036 }
2037
2038 public void setAppGroupId(IBinder token, int groupId) {
2039 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2040 "setAppStartingIcon()")) {
2041 return;
2042 }
2043
2044 synchronized(mWindowMap) {
2045 AppWindowToken wtoken = findAppWindowToken(token);
2046 if (wtoken == null) {
2047 Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
2048 return;
2049 }
2050 wtoken.groupId = groupId;
2051 }
2052 }
2053
2054 public int getOrientationFromWindowsLocked() {
2055 int pos = mWindows.size() - 1;
2056 while (pos >= 0) {
2057 WindowState wtoken = (WindowState) mWindows.get(pos);
2058 pos--;
2059 if (wtoken.mAppToken != null) {
2060 // We hit an application window. so the orientation will be determined by the
2061 // app window. No point in continuing further.
2062 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2063 }
2064 if (!wtoken.isVisibleLw()) {
2065 continue;
2066 }
2067 int req = wtoken.mAttrs.screenOrientation;
2068 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
2069 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
2070 continue;
2071 } else {
2072 return req;
2073 }
2074 }
2075 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2076 }
2077
2078 public int getOrientationFromAppTokensLocked() {
2079 int pos = mAppTokens.size() - 1;
2080 int curGroup = 0;
2081 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2082 boolean haveGroup = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002083 boolean lastFullscreen = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084 while (pos >= 0) {
2085 AppWindowToken wtoken = mAppTokens.get(pos);
2086 pos--;
The Android Open Source Project10592532009-03-18 17:39:46 -07002087 // if we're about to tear down this window, don't use it for orientation
2088 if (!wtoken.hidden && wtoken.hiddenRequested) {
2089 continue;
2090 }
2091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 if (!haveGroup) {
2093 // We ignore any hidden applications on the top.
2094 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
2095 continue;
2096 }
2097 haveGroup = true;
2098 curGroup = wtoken.groupId;
2099 lastOrientation = wtoken.requestedOrientation;
2100 } else if (curGroup != wtoken.groupId) {
2101 // If we have hit a new application group, and the bottom
2102 // of the previous group didn't explicitly say to use
The Android Open Source Project4df24232009-03-05 14:34:35 -08002103 // the orientation behind it, and the last app was
2104 // full screen, then we'll stick with the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 // user's orientation.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002106 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
2107 && lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 return lastOrientation;
2109 }
2110 }
2111 int or = wtoken.requestedOrientation;
2112 // If this application is fullscreen, then just take whatever
2113 // orientation it has and ignores whatever is under it.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002114 lastFullscreen = wtoken.appFullscreen;
2115 if (lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 return or;
2117 }
2118 // If this application has requested an explicit orientation,
2119 // then use it.
2120 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
2121 or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
2122 or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
2123 or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
2124 or == ActivityInfo.SCREEN_ORIENTATION_USER) {
2125 return or;
2126 }
2127 }
2128 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2129 }
2130
2131 public Configuration updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002132 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 Configuration config;
2134 long ident = Binder.clearCallingIdentity();
2135 synchronized(mWindowMap) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002136 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 }
2138 if (config != null) {
2139 mLayoutNeeded = true;
2140 performLayoutAndPlaceSurfacesLocked();
2141 }
2142 Binder.restoreCallingIdentity(ident);
2143 return config;
2144 }
2145
2146 /*
2147 * The orientation is computed from non-application windows first. If none of
2148 * the non-application windows specify orientation, the orientation is computed from
2149 * application tokens.
2150 * @see android.view.IWindowManager#updateOrientationFromAppTokens(
2151 * android.os.IBinder)
2152 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002153 Configuration updateOrientationFromAppTokensLocked(
The Android Open Source Project10592532009-03-18 17:39:46 -07002154 Configuration appConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 boolean changed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 long ident = Binder.clearCallingIdentity();
2157 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002158 int req = computeForcedAppOrientationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159
2160 if (req != mForcedAppOrientation) {
2161 changed = true;
2162 mForcedAppOrientation = req;
2163 //send a message to Policy indicating orientation change to take
2164 //action like disabling/enabling sensors etc.,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002165 mPolicy.setCurrentOrientationLw(req);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166 }
2167
2168 if (changed) {
2169 changed = setRotationUncheckedLocked(
Dianne Hackborncc956672009-03-26 00:04:52 -07002170 WindowManagerPolicy.USE_LAST_ROTATION,
2171 mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 if (changed) {
2173 if (freezeThisOneIfNeeded != null) {
2174 AppWindowToken wtoken = findAppWindowToken(
2175 freezeThisOneIfNeeded);
2176 if (wtoken != null) {
2177 startAppFreezingScreenLocked(wtoken,
2178 ActivityInfo.CONFIG_ORIENTATION);
2179 }
2180 }
Dianne Hackborn9d4de632009-03-24 19:37:25 -07002181 return computeNewConfigurationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 }
2183 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002184
2185 // No obvious action we need to take, but if our current
2186 // state mismatches the activity maanager's, update it
2187 if (appConfig != null) {
Dianne Hackborn9d4de632009-03-24 19:37:25 -07002188 mTempConfiguration.setToDefaults();
2189 if (computeNewConfigurationLocked(mTempConfiguration)) {
2190 if (appConfig.diff(mTempConfiguration) != 0) {
2191 Log.i(TAG, "Config changed: " + mTempConfiguration);
2192 return new Configuration(mTempConfiguration);
2193 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002194 }
2195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 } finally {
2197 Binder.restoreCallingIdentity(ident);
2198 }
2199
2200 return null;
2201 }
2202
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002203 int computeForcedAppOrientationLocked() {
2204 int req = getOrientationFromWindowsLocked();
2205 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
2206 req = getOrientationFromAppTokensLocked();
2207 }
2208 return req;
2209 }
2210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
2212 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2213 "setAppOrientation()")) {
2214 return;
2215 }
2216
2217 synchronized(mWindowMap) {
2218 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2219 if (wtoken == null) {
2220 Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
2221 return;
2222 }
2223
2224 wtoken.requestedOrientation = requestedOrientation;
2225 }
2226 }
2227
2228 public int getAppOrientation(IApplicationToken token) {
2229 synchronized(mWindowMap) {
2230 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2231 if (wtoken == null) {
2232 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2233 }
2234
2235 return wtoken.requestedOrientation;
2236 }
2237 }
2238
2239 public void setFocusedApp(IBinder token, boolean moveFocusNow) {
2240 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2241 "setFocusedApp()")) {
2242 return;
2243 }
2244
2245 synchronized(mWindowMap) {
2246 boolean changed = false;
2247 if (token == null) {
2248 if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
2249 changed = mFocusedApp != null;
2250 mFocusedApp = null;
2251 mKeyWaiter.tickle();
2252 } else {
2253 AppWindowToken newFocus = findAppWindowToken(token);
2254 if (newFocus == null) {
2255 Log.w(TAG, "Attempted to set focus to non-existing app token: " + token);
2256 return;
2257 }
2258 changed = mFocusedApp != newFocus;
2259 mFocusedApp = newFocus;
2260 if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp);
2261 mKeyWaiter.tickle();
2262 }
2263
2264 if (moveFocusNow && changed) {
2265 final long origId = Binder.clearCallingIdentity();
2266 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2267 Binder.restoreCallingIdentity(origId);
2268 }
2269 }
2270 }
2271
2272 public void prepareAppTransition(int transit) {
2273 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2274 "prepareAppTransition()")) {
2275 return;
2276 }
2277
2278 synchronized(mWindowMap) {
2279 if (DEBUG_APP_TRANSITIONS) Log.v(
2280 TAG, "Prepare app transition: transit=" + transit
2281 + " mNextAppTransition=" + mNextAppTransition);
2282 if (!mDisplayFrozen) {
2283 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
2284 mNextAppTransition = transit;
2285 }
2286 mAppTransitionReady = false;
2287 mAppTransitionTimeout = false;
2288 mStartingIconInTransition = false;
2289 mSkipAppTransitionAnimation = false;
2290 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2291 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
2292 5000);
2293 }
2294 }
2295 }
2296
2297 public int getPendingAppTransition() {
2298 return mNextAppTransition;
2299 }
2300
2301 public void executeAppTransition() {
2302 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2303 "executeAppTransition()")) {
2304 return;
2305 }
2306
2307 synchronized(mWindowMap) {
2308 if (DEBUG_APP_TRANSITIONS) Log.v(
2309 TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
2310 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2311 mAppTransitionReady = true;
2312 final long origId = Binder.clearCallingIdentity();
2313 performLayoutAndPlaceSurfacesLocked();
2314 Binder.restoreCallingIdentity(origId);
2315 }
2316 }
2317 }
2318
2319 public void setAppStartingWindow(IBinder token, String pkg,
2320 int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
2321 IBinder transferFrom, boolean createIfNeeded) {
2322 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2323 "setAppStartingIcon()")) {
2324 return;
2325 }
2326
2327 synchronized(mWindowMap) {
2328 if (DEBUG_STARTING_WINDOW) Log.v(
2329 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
2330 + " transferFrom=" + transferFrom);
2331
2332 AppWindowToken wtoken = findAppWindowToken(token);
2333 if (wtoken == null) {
2334 Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
2335 return;
2336 }
2337
2338 // If the display is frozen, we won't do anything until the
2339 // actual window is displayed so there is no reason to put in
2340 // the starting window.
2341 if (mDisplayFrozen) {
2342 return;
2343 }
2344
2345 if (wtoken.startingData != null) {
2346 return;
2347 }
2348
2349 if (transferFrom != null) {
2350 AppWindowToken ttoken = findAppWindowToken(transferFrom);
2351 if (ttoken != null) {
2352 WindowState startingWindow = ttoken.startingWindow;
2353 if (startingWindow != null) {
2354 if (mStartingIconInTransition) {
2355 // In this case, the starting icon has already
2356 // been displayed, so start letting windows get
2357 // shown immediately without any more transitions.
2358 mSkipAppTransitionAnimation = true;
2359 }
2360 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2361 "Moving existing starting from " + ttoken
2362 + " to " + wtoken);
2363 final long origId = Binder.clearCallingIdentity();
2364
2365 // Transfer the starting window over to the new
2366 // token.
2367 wtoken.startingData = ttoken.startingData;
2368 wtoken.startingView = ttoken.startingView;
2369 wtoken.startingWindow = startingWindow;
2370 ttoken.startingData = null;
2371 ttoken.startingView = null;
2372 ttoken.startingWindow = null;
2373 ttoken.startingMoved = true;
2374 startingWindow.mToken = wtoken;
The Android Open Source Projectc2ad2412009-03-19 23:08:54 -07002375 startingWindow.mRootToken = wtoken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002376 startingWindow.mAppToken = wtoken;
2377 mWindows.remove(startingWindow);
2378 ttoken.windows.remove(startingWindow);
2379 ttoken.allAppWindows.remove(startingWindow);
2380 addWindowToListInOrderLocked(startingWindow, true);
2381 wtoken.allAppWindows.add(startingWindow);
2382
2383 // Propagate other interesting state between the
2384 // tokens. If the old token is displayed, we should
2385 // immediately force the new one to be displayed. If
2386 // it is animating, we need to move that animation to
2387 // the new one.
2388 if (ttoken.allDrawn) {
2389 wtoken.allDrawn = true;
2390 }
2391 if (ttoken.firstWindowDrawn) {
2392 wtoken.firstWindowDrawn = true;
2393 }
2394 if (!ttoken.hidden) {
2395 wtoken.hidden = false;
2396 wtoken.hiddenRequested = false;
2397 wtoken.willBeHidden = false;
2398 }
2399 if (wtoken.clientHidden != ttoken.clientHidden) {
2400 wtoken.clientHidden = ttoken.clientHidden;
2401 wtoken.sendAppVisibilityToClients();
2402 }
2403 if (ttoken.animation != null) {
2404 wtoken.animation = ttoken.animation;
2405 wtoken.animating = ttoken.animating;
2406 wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
2407 ttoken.animation = null;
2408 ttoken.animLayerAdjustment = 0;
2409 wtoken.updateLayers();
2410 ttoken.updateLayers();
2411 }
2412
2413 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 mLayoutNeeded = true;
2415 performLayoutAndPlaceSurfacesLocked();
2416 Binder.restoreCallingIdentity(origId);
2417 return;
2418 } else if (ttoken.startingData != null) {
2419 // The previous app was getting ready to show a
2420 // starting window, but hasn't yet done so. Steal it!
2421 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2422 "Moving pending starting from " + ttoken
2423 + " to " + wtoken);
2424 wtoken.startingData = ttoken.startingData;
2425 ttoken.startingData = null;
2426 ttoken.startingMoved = true;
2427 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2428 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2429 // want to process the message ASAP, before any other queued
2430 // messages.
2431 mH.sendMessageAtFrontOfQueue(m);
2432 return;
2433 }
2434 }
2435 }
2436
2437 // There is no existing starting window, and the caller doesn't
2438 // want us to create one, so that's it!
2439 if (!createIfNeeded) {
2440 return;
2441 }
2442
2443 mStartingIconInTransition = true;
2444 wtoken.startingData = new StartingData(
2445 pkg, theme, nonLocalizedLabel,
2446 labelRes, icon);
2447 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2448 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2449 // want to process the message ASAP, before any other queued
2450 // messages.
2451 mH.sendMessageAtFrontOfQueue(m);
2452 }
2453 }
2454
2455 public void setAppWillBeHidden(IBinder token) {
2456 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2457 "setAppWillBeHidden()")) {
2458 return;
2459 }
2460
2461 AppWindowToken wtoken;
2462
2463 synchronized(mWindowMap) {
2464 wtoken = findAppWindowToken(token);
2465 if (wtoken == null) {
2466 Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
2467 return;
2468 }
2469 wtoken.willBeHidden = true;
2470 }
2471 }
2472
2473 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
2474 boolean visible, int transit, boolean performLayout) {
2475 boolean delayed = false;
2476
2477 if (wtoken.clientHidden == visible) {
2478 wtoken.clientHidden = !visible;
2479 wtoken.sendAppVisibilityToClients();
2480 }
2481
2482 wtoken.willBeHidden = false;
2483 if (wtoken.hidden == visible) {
2484 final int N = wtoken.allAppWindows.size();
2485 boolean changed = false;
2486 if (DEBUG_APP_TRANSITIONS) Log.v(
2487 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
2488 + " performLayout=" + performLayout);
2489
2490 boolean runningAppAnimation = false;
2491
2492 if (transit != WindowManagerPolicy.TRANSIT_NONE) {
2493 if (wtoken.animation == sDummyAnimation) {
2494 wtoken.animation = null;
2495 }
2496 applyAnimationLocked(wtoken, lp, transit, visible);
2497 changed = true;
2498 if (wtoken.animation != null) {
2499 delayed = runningAppAnimation = true;
2500 }
2501 }
2502
2503 for (int i=0; i<N; i++) {
2504 WindowState win = wtoken.allAppWindows.get(i);
2505 if (win == wtoken.startingWindow) {
2506 continue;
2507 }
2508
2509 if (win.isAnimating()) {
2510 delayed = true;
2511 }
2512
2513 //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
2514 //win.dump(" ");
2515 if (visible) {
2516 if (!win.isVisibleNow()) {
2517 if (!runningAppAnimation) {
2518 applyAnimationLocked(win,
2519 WindowManagerPolicy.TRANSIT_ENTER, true);
2520 }
2521 changed = true;
2522 }
2523 } else if (win.isVisibleNow()) {
2524 if (!runningAppAnimation) {
2525 applyAnimationLocked(win,
2526 WindowManagerPolicy.TRANSIT_EXIT, false);
2527 }
2528 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2529 KeyWaiter.RETURN_NOTHING);
2530 changed = true;
2531 }
2532 }
2533
2534 wtoken.hidden = wtoken.hiddenRequested = !visible;
2535 if (!visible) {
2536 unsetAppFreezingScreenLocked(wtoken, true, true);
2537 } else {
2538 // If we are being set visible, and the starting window is
2539 // not yet displayed, then make sure it doesn't get displayed.
2540 WindowState swin = wtoken.startingWindow;
2541 if (swin != null && (swin.mDrawPending
2542 || swin.mCommitDrawPending)) {
2543 swin.mPolicyVisibility = false;
2544 swin.mPolicyVisibilityAfterAnim = false;
2545 }
2546 }
2547
2548 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
2549 + ": hidden=" + wtoken.hidden + " hiddenRequested="
2550 + wtoken.hiddenRequested);
2551
2552 if (changed && performLayout) {
2553 mLayoutNeeded = true;
2554 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 performLayoutAndPlaceSurfacesLocked();
2556 }
2557 }
2558
2559 if (wtoken.animation != null) {
2560 delayed = true;
2561 }
2562
2563 return delayed;
2564 }
2565
2566 public void setAppVisibility(IBinder token, boolean visible) {
2567 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2568 "setAppVisibility()")) {
2569 return;
2570 }
2571
2572 AppWindowToken wtoken;
2573
2574 synchronized(mWindowMap) {
2575 wtoken = findAppWindowToken(token);
2576 if (wtoken == null) {
2577 Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
2578 return;
2579 }
2580
2581 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
2582 RuntimeException e = new RuntimeException();
2583 e.fillInStackTrace();
2584 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
2585 + "): mNextAppTransition=" + mNextAppTransition
2586 + " hidden=" + wtoken.hidden
2587 + " hiddenRequested=" + wtoken.hiddenRequested, e);
2588 }
2589
2590 // If we are preparing an app transition, then delay changing
2591 // the visibility of this token until we execute that transition.
2592 if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2593 // Already in requested state, don't do anything more.
2594 if (wtoken.hiddenRequested != visible) {
2595 return;
2596 }
2597 wtoken.hiddenRequested = !visible;
2598
2599 if (DEBUG_APP_TRANSITIONS) Log.v(
2600 TAG, "Setting dummy animation on: " + wtoken);
2601 wtoken.setDummyAnimation();
2602 mOpeningApps.remove(wtoken);
2603 mClosingApps.remove(wtoken);
2604 wtoken.inPendingTransaction = true;
2605 if (visible) {
2606 mOpeningApps.add(wtoken);
2607 wtoken.allDrawn = false;
2608 wtoken.startingDisplayed = false;
2609 wtoken.startingMoved = false;
2610
2611 if (wtoken.clientHidden) {
2612 // In the case where we are making an app visible
2613 // but holding off for a transition, we still need
2614 // to tell the client to make its windows visible so
2615 // they get drawn. Otherwise, we will wait on
2616 // performing the transition until all windows have
2617 // been drawn, they never will be, and we are sad.
2618 wtoken.clientHidden = false;
2619 wtoken.sendAppVisibilityToClients();
2620 }
2621 } else {
2622 mClosingApps.add(wtoken);
2623 }
2624 return;
2625 }
2626
2627 final long origId = Binder.clearCallingIdentity();
2628 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
2629 wtoken.updateReportedVisibilityLocked();
2630 Binder.restoreCallingIdentity(origId);
2631 }
2632 }
2633
2634 void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
2635 boolean unfreezeSurfaceNow, boolean force) {
2636 if (wtoken.freezingScreen) {
2637 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
2638 + " force=" + force);
2639 final int N = wtoken.allAppWindows.size();
2640 boolean unfrozeWindows = false;
2641 for (int i=0; i<N; i++) {
2642 WindowState w = wtoken.allAppWindows.get(i);
2643 if (w.mAppFreezing) {
2644 w.mAppFreezing = false;
2645 if (w.mSurface != null && !w.mOrientationChanging) {
2646 w.mOrientationChanging = true;
2647 }
2648 unfrozeWindows = true;
2649 }
2650 }
2651 if (force || unfrozeWindows) {
2652 if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
2653 wtoken.freezingScreen = false;
2654 mAppsFreezingScreen--;
2655 }
2656 if (unfreezeSurfaceNow) {
2657 if (unfrozeWindows) {
2658 mLayoutNeeded = true;
2659 performLayoutAndPlaceSurfacesLocked();
2660 }
2661 if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
2662 stopFreezingDisplayLocked();
2663 }
2664 }
2665 }
2666 }
2667
2668 public void startAppFreezingScreenLocked(AppWindowToken wtoken,
2669 int configChanges) {
2670 if (DEBUG_ORIENTATION) {
2671 RuntimeException e = new RuntimeException();
2672 e.fillInStackTrace();
2673 Log.i(TAG, "Set freezing of " + wtoken.appToken
2674 + ": hidden=" + wtoken.hidden + " freezing="
2675 + wtoken.freezingScreen, e);
2676 }
2677 if (!wtoken.hiddenRequested) {
2678 if (!wtoken.freezingScreen) {
2679 wtoken.freezingScreen = true;
2680 mAppsFreezingScreen++;
2681 if (mAppsFreezingScreen == 1) {
2682 startFreezingDisplayLocked();
2683 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
2684 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
2685 5000);
2686 }
2687 }
2688 final int N = wtoken.allAppWindows.size();
2689 for (int i=0; i<N; i++) {
2690 WindowState w = wtoken.allAppWindows.get(i);
2691 w.mAppFreezing = true;
2692 }
2693 }
2694 }
2695
2696 public void startAppFreezingScreen(IBinder token, int configChanges) {
2697 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2698 "setAppFreezingScreen()")) {
2699 return;
2700 }
2701
2702 synchronized(mWindowMap) {
2703 if (configChanges == 0 && !mDisplayFrozen) {
2704 if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
2705 return;
2706 }
2707
2708 AppWindowToken wtoken = findAppWindowToken(token);
2709 if (wtoken == null || wtoken.appToken == null) {
2710 Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
2711 return;
2712 }
2713 final long origId = Binder.clearCallingIdentity();
2714 startAppFreezingScreenLocked(wtoken, configChanges);
2715 Binder.restoreCallingIdentity(origId);
2716 }
2717 }
2718
2719 public void stopAppFreezingScreen(IBinder token, boolean force) {
2720 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2721 "setAppFreezingScreen()")) {
2722 return;
2723 }
2724
2725 synchronized(mWindowMap) {
2726 AppWindowToken wtoken = findAppWindowToken(token);
2727 if (wtoken == null || wtoken.appToken == null) {
2728 return;
2729 }
2730 final long origId = Binder.clearCallingIdentity();
2731 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
2732 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
2733 unsetAppFreezingScreenLocked(wtoken, true, force);
2734 Binder.restoreCallingIdentity(origId);
2735 }
2736 }
2737
2738 public void removeAppToken(IBinder token) {
2739 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2740 "removeAppToken()")) {
2741 return;
2742 }
2743
2744 AppWindowToken wtoken = null;
2745 AppWindowToken startingToken = null;
2746 boolean delayed = false;
2747
2748 final long origId = Binder.clearCallingIdentity();
2749 synchronized(mWindowMap) {
2750 WindowToken basewtoken = mTokenMap.remove(token);
2751 mTokenList.remove(basewtoken);
2752 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
2753 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
2754 delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
2755 wtoken.inPendingTransaction = false;
2756 mOpeningApps.remove(wtoken);
2757 if (mClosingApps.contains(wtoken)) {
2758 delayed = true;
2759 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2760 mClosingApps.add(wtoken);
2761 delayed = true;
2762 }
2763 if (DEBUG_APP_TRANSITIONS) Log.v(
2764 TAG, "Removing app " + wtoken + " delayed=" + delayed
2765 + " animation=" + wtoken.animation
2766 + " animating=" + wtoken.animating);
2767 if (delayed) {
2768 // set the token aside because it has an active animation to be finished
2769 mExitingAppTokens.add(wtoken);
2770 }
2771 mAppTokens.remove(wtoken);
2772 wtoken.removed = true;
2773 if (wtoken.startingData != null) {
2774 startingToken = wtoken;
2775 }
2776 unsetAppFreezingScreenLocked(wtoken, true, true);
2777 if (mFocusedApp == wtoken) {
2778 if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
2779 mFocusedApp = null;
2780 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2781 mKeyWaiter.tickle();
2782 }
2783 } else {
2784 Log.w(TAG, "Attempted to remove non-existing app token: " + token);
2785 }
2786
2787 if (!delayed && wtoken != null) {
2788 wtoken.updateReportedVisibilityLocked();
2789 }
2790 }
2791 Binder.restoreCallingIdentity(origId);
2792
2793 if (startingToken != null) {
2794 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
2795 + startingToken + ": app token removed");
2796 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
2797 mH.sendMessage(m);
2798 }
2799 }
2800
2801 private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
2802 final int NW = token.windows.size();
2803 for (int i=0; i<NW; i++) {
2804 WindowState win = token.windows.get(i);
2805 mWindows.remove(win);
2806 int j = win.mChildWindows.size();
2807 while (j > 0) {
2808 j--;
2809 mWindows.remove(win.mChildWindows.get(j));
2810 }
2811 }
2812 return NW > 0;
2813 }
2814
2815 void dumpAppTokensLocked() {
2816 for (int i=mAppTokens.size()-1; i>=0; i--) {
2817 Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
2818 }
2819 }
2820
2821 void dumpWindowsLocked() {
2822 for (int i=mWindows.size()-1; i>=0; i--) {
2823 Log.v(TAG, " #" + i + ": " + mWindows.get(i));
2824 }
2825 }
2826
2827 private int findWindowOffsetLocked(int tokenPos) {
2828 final int NW = mWindows.size();
2829
2830 if (tokenPos >= mAppTokens.size()) {
2831 int i = NW;
2832 while (i > 0) {
2833 i--;
2834 WindowState win = (WindowState)mWindows.get(i);
2835 if (win.getAppToken() != null) {
2836 return i+1;
2837 }
2838 }
2839 }
2840
2841 while (tokenPos > 0) {
2842 // Find the first app token below the new position that has
2843 // a window displayed.
2844 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
2845 if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
2846 + tokenPos + " -- " + wtoken.token);
2847 int i = wtoken.windows.size();
2848 while (i > 0) {
2849 i--;
2850 WindowState win = wtoken.windows.get(i);
2851 int j = win.mChildWindows.size();
2852 while (j > 0) {
2853 j--;
2854 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2855 if (cwin.mSubLayer >= 0 ) {
2856 for (int pos=NW-1; pos>=0; pos--) {
2857 if (mWindows.get(pos) == cwin) {
2858 if (DEBUG_REORDER) Log.v(TAG,
2859 "Found child win @" + (pos+1));
2860 return pos+1;
2861 }
2862 }
2863 }
2864 }
2865 for (int pos=NW-1; pos>=0; pos--) {
2866 if (mWindows.get(pos) == win) {
2867 if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
2868 return pos+1;
2869 }
2870 }
2871 }
2872 tokenPos--;
2873 }
2874
2875 return 0;
2876 }
2877
2878 private final int reAddWindowLocked(int index, WindowState win) {
2879 final int NCW = win.mChildWindows.size();
2880 boolean added = false;
2881 for (int j=0; j<NCW; j++) {
2882 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2883 if (!added && cwin.mSubLayer >= 0) {
2884 mWindows.add(index, win);
2885 index++;
2886 added = true;
2887 }
2888 mWindows.add(index, cwin);
2889 index++;
2890 }
2891 if (!added) {
2892 mWindows.add(index, win);
2893 index++;
2894 }
2895 return index;
2896 }
2897
2898 private final int reAddAppWindowsLocked(int index, WindowToken token) {
2899 final int NW = token.windows.size();
2900 for (int i=0; i<NW; i++) {
2901 index = reAddWindowLocked(index, token.windows.get(i));
2902 }
2903 return index;
2904 }
2905
2906 public void moveAppToken(int index, IBinder token) {
2907 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2908 "moveAppToken()")) {
2909 return;
2910 }
2911
2912 synchronized(mWindowMap) {
2913 if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
2914 if (DEBUG_REORDER) dumpAppTokensLocked();
2915 final AppWindowToken wtoken = findAppWindowToken(token);
2916 if (wtoken == null || !mAppTokens.remove(wtoken)) {
2917 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
2918 + token + " (" + wtoken + ")");
2919 return;
2920 }
2921 mAppTokens.add(index, wtoken);
2922 if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
2923 if (DEBUG_REORDER) dumpAppTokensLocked();
2924
2925 final long origId = Binder.clearCallingIdentity();
2926 if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
2927 if (DEBUG_REORDER) dumpWindowsLocked();
2928 if (tmpRemoveAppWindowsLocked(wtoken)) {
2929 if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:");
2930 if (DEBUG_REORDER) dumpWindowsLocked();
2931 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
2932 if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
2933 if (DEBUG_REORDER) dumpWindowsLocked();
2934 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 mLayoutNeeded = true;
2936 performLayoutAndPlaceSurfacesLocked();
2937 }
2938 Binder.restoreCallingIdentity(origId);
2939 }
2940 }
2941
2942 private void removeAppTokensLocked(List<IBinder> tokens) {
2943 // XXX This should be done more efficiently!
2944 // (take advantage of the fact that both lists should be
2945 // ordered in the same way.)
2946 int N = tokens.size();
2947 for (int i=0; i<N; i++) {
2948 IBinder token = tokens.get(i);
2949 final AppWindowToken wtoken = findAppWindowToken(token);
2950 if (!mAppTokens.remove(wtoken)) {
2951 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
2952 + token + " (" + wtoken + ")");
2953 i--;
2954 N--;
2955 }
2956 }
2957 }
2958
2959 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
2960 // First remove all of the windows from the list.
2961 final int N = tokens.size();
2962 int i;
2963 for (i=0; i<N; i++) {
2964 WindowToken token = mTokenMap.get(tokens.get(i));
2965 if (token != null) {
2966 tmpRemoveAppWindowsLocked(token);
2967 }
2968 }
2969
2970 // Where to start adding?
2971 int pos = findWindowOffsetLocked(tokenPos);
2972
2973 // And now add them back at the correct place.
2974 for (i=0; i<N; i++) {
2975 WindowToken token = mTokenMap.get(tokens.get(i));
2976 if (token != null) {
2977 pos = reAddAppWindowsLocked(pos, token);
2978 }
2979 }
2980
2981 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982 mLayoutNeeded = true;
2983 performLayoutAndPlaceSurfacesLocked();
2984
2985 //dump();
2986 }
2987
2988 public void moveAppTokensToTop(List<IBinder> tokens) {
2989 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2990 "moveAppTokensToTop()")) {
2991 return;
2992 }
2993
2994 final long origId = Binder.clearCallingIdentity();
2995 synchronized(mWindowMap) {
2996 removeAppTokensLocked(tokens);
2997 final int N = tokens.size();
2998 for (int i=0; i<N; i++) {
2999 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3000 if (wt != null) {
3001 mAppTokens.add(wt);
3002 }
3003 }
3004 moveAppWindowsLocked(tokens, mAppTokens.size());
3005 }
3006 Binder.restoreCallingIdentity(origId);
3007 }
3008
3009 public void moveAppTokensToBottom(List<IBinder> tokens) {
3010 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3011 "moveAppTokensToBottom()")) {
3012 return;
3013 }
3014
3015 final long origId = Binder.clearCallingIdentity();
3016 synchronized(mWindowMap) {
3017 removeAppTokensLocked(tokens);
3018 final int N = tokens.size();
3019 int pos = 0;
3020 for (int i=0; i<N; i++) {
3021 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3022 if (wt != null) {
3023 mAppTokens.add(pos, wt);
3024 pos++;
3025 }
3026 }
3027 moveAppWindowsLocked(tokens, 0);
3028 }
3029 Binder.restoreCallingIdentity(origId);
3030 }
3031
3032 // -------------------------------------------------------------
3033 // Misc IWindowSession methods
3034 // -------------------------------------------------------------
3035
3036 public void disableKeyguard(IBinder token, String tag) {
3037 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3038 != PackageManager.PERMISSION_GRANTED) {
3039 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3040 }
3041 mKeyguardDisabled.acquire(token, tag);
3042 }
3043
3044 public void reenableKeyguard(IBinder token) {
3045 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3046 != PackageManager.PERMISSION_GRANTED) {
3047 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3048 }
3049 synchronized (mKeyguardDisabled) {
3050 mKeyguardDisabled.release(token);
3051
3052 if (!mKeyguardDisabled.isAcquired()) {
3053 // if we are the last one to reenable the keyguard wait until
3054 // we have actaully finished reenabling until returning
3055 mWaitingUntilKeyguardReenabled = true;
3056 while (mWaitingUntilKeyguardReenabled) {
3057 try {
3058 mKeyguardDisabled.wait();
3059 } catch (InterruptedException e) {
3060 Thread.currentThread().interrupt();
3061 }
3062 }
3063 }
3064 }
3065 }
3066
3067 /**
3068 * @see android.app.KeyguardManager#exitKeyguardSecurely
3069 */
3070 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
3071 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3072 != PackageManager.PERMISSION_GRANTED) {
3073 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3074 }
3075 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
3076 public void onKeyguardExitResult(boolean success) {
3077 try {
3078 callback.onKeyguardExitResult(success);
3079 } catch (RemoteException e) {
3080 // Client has died, we don't care.
3081 }
3082 }
3083 });
3084 }
3085
3086 public boolean inKeyguardRestrictedInputMode() {
3087 return mPolicy.inKeyguardRestrictedKeyInputMode();
3088 }
3089
3090 static float fixScale(float scale) {
3091 if (scale < 0) scale = 0;
3092 else if (scale > 20) scale = 20;
3093 return Math.abs(scale);
3094 }
3095
3096 public void setAnimationScale(int which, float scale) {
3097 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3098 "setAnimationScale()")) {
3099 return;
3100 }
3101
3102 if (scale < 0) scale = 0;
3103 else if (scale > 20) scale = 20;
3104 scale = Math.abs(scale);
3105 switch (which) {
3106 case 0: mWindowAnimationScale = fixScale(scale); break;
3107 case 1: mTransitionAnimationScale = fixScale(scale); break;
3108 }
3109
3110 // Persist setting
3111 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3112 }
3113
3114 public void setAnimationScales(float[] scales) {
3115 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3116 "setAnimationScale()")) {
3117 return;
3118 }
3119
3120 if (scales != null) {
3121 if (scales.length >= 1) {
3122 mWindowAnimationScale = fixScale(scales[0]);
3123 }
3124 if (scales.length >= 2) {
3125 mTransitionAnimationScale = fixScale(scales[1]);
3126 }
3127 }
3128
3129 // Persist setting
3130 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3131 }
3132
3133 public float getAnimationScale(int which) {
3134 switch (which) {
3135 case 0: return mWindowAnimationScale;
3136 case 1: return mTransitionAnimationScale;
3137 }
3138 return 0;
3139 }
3140
3141 public float[] getAnimationScales() {
3142 return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
3143 }
3144
3145 public int getSwitchState(int sw) {
3146 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3147 "getSwitchState()")) {
3148 return -1;
3149 }
3150 return KeyInputQueue.getSwitchState(sw);
3151 }
3152
3153 public int getSwitchStateForDevice(int devid, int sw) {
3154 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3155 "getSwitchStateForDevice()")) {
3156 return -1;
3157 }
3158 return KeyInputQueue.getSwitchState(devid, sw);
3159 }
3160
3161 public int getScancodeState(int sw) {
3162 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3163 "getScancodeState()")) {
3164 return -1;
3165 }
3166 return KeyInputQueue.getScancodeState(sw);
3167 }
3168
3169 public int getScancodeStateForDevice(int devid, int sw) {
3170 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3171 "getScancodeStateForDevice()")) {
3172 return -1;
3173 }
3174 return KeyInputQueue.getScancodeState(devid, sw);
3175 }
3176
3177 public int getKeycodeState(int sw) {
3178 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3179 "getKeycodeState()")) {
3180 return -1;
3181 }
3182 return KeyInputQueue.getKeycodeState(sw);
3183 }
3184
3185 public int getKeycodeStateForDevice(int devid, int sw) {
3186 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3187 "getKeycodeStateForDevice()")) {
3188 return -1;
3189 }
3190 return KeyInputQueue.getKeycodeState(devid, sw);
3191 }
3192
3193 public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
3194 return KeyInputQueue.hasKeys(keycodes, keyExists);
3195 }
3196
3197 public void enableScreenAfterBoot() {
3198 synchronized(mWindowMap) {
3199 if (mSystemBooted) {
3200 return;
3201 }
3202 mSystemBooted = true;
3203 }
3204
3205 performEnableScreen();
3206 }
3207
3208 public void enableScreenIfNeededLocked() {
3209 if (mDisplayEnabled) {
3210 return;
3211 }
3212 if (!mSystemBooted) {
3213 return;
3214 }
3215 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
3216 }
3217
3218 public void performEnableScreen() {
3219 synchronized(mWindowMap) {
3220 if (mDisplayEnabled) {
3221 return;
3222 }
3223 if (!mSystemBooted) {
3224 return;
3225 }
3226
3227 // Don't enable the screen until all existing windows
3228 // have been drawn.
3229 final int N = mWindows.size();
3230 for (int i=0; i<N; i++) {
3231 WindowState w = (WindowState)mWindows.get(i);
3232 if (w.isVisibleLw() && !w.isDisplayedLw()) {
3233 return;
3234 }
3235 }
3236
3237 mDisplayEnabled = true;
3238 if (false) {
3239 Log.i(TAG, "ENABLING SCREEN!");
3240 StringWriter sw = new StringWriter();
3241 PrintWriter pw = new PrintWriter(sw);
3242 this.dump(null, pw, null);
3243 Log.i(TAG, sw.toString());
3244 }
3245 try {
3246 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
3247 if (surfaceFlinger != null) {
3248 //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
3249 Parcel data = Parcel.obtain();
3250 data.writeInterfaceToken("android.ui.ISurfaceComposer");
3251 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
3252 data, null, 0);
3253 data.recycle();
3254 }
3255 } catch (RemoteException ex) {
3256 Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
3257 }
3258 }
3259
3260 mPolicy.enableScreenAfterBoot();
3261
3262 // Make sure the last requested orientation has been applied.
Dianne Hackborncc956672009-03-26 00:04:52 -07003263 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
3264 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 }
3266
3267 public void setInTouchMode(boolean mode) {
3268 synchronized(mWindowMap) {
3269 mInTouchMode = mode;
3270 }
3271 }
3272
3273 public void setRotation(int rotation,
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003274 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003276 "setRotation()")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 return;
3278 }
3279
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003280 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 }
3282
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003283 public void setRotationUnchecked(int rotation,
3284 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 if(DEBUG_ORIENTATION) Log.v(TAG,
3286 "alwaysSendConfiguration set to "+alwaysSendConfiguration);
3287
3288 long origId = Binder.clearCallingIdentity();
3289 boolean changed;
3290 synchronized(mWindowMap) {
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003291 changed = setRotationUncheckedLocked(rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292 }
3293
3294 if (changed) {
3295 sendNewConfiguration();
3296 synchronized(mWindowMap) {
3297 mLayoutNeeded = true;
3298 performLayoutAndPlaceSurfacesLocked();
3299 }
3300 } else if (alwaysSendConfiguration) {
3301 //update configuration ignoring orientation change
3302 sendNewConfiguration();
3303 }
3304
3305 Binder.restoreCallingIdentity(origId);
3306 }
3307
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003308 public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 boolean changed;
3310 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
3311 rotation = mRequestedRotation;
3312 } else {
3313 mRequestedRotation = rotation;
Dianne Hackborncc956672009-03-26 00:04:52 -07003314 mLastRotationFlags = animFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 }
3316 if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07003317 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318 mRotation, mDisplayEnabled);
3319 if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
3320 changed = mDisplayEnabled && mRotation != rotation;
3321
3322 if (changed) {
3323 if (DEBUG_ORIENTATION) Log.v(TAG,
3324 "Rotation changed to " + rotation
3325 + " from " + mRotation
3326 + " (forceApp=" + mForcedAppOrientation
3327 + ", req=" + mRequestedRotation + ")");
3328 mRotation = rotation;
3329 mWindowsFreezingScreen = true;
3330 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
3331 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
3332 2000);
3333 startFreezingDisplayLocked();
Dianne Hackborn02771bc2009-03-25 22:39:21 -07003334 Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 mQueue.setOrientation(rotation);
3336 if (mDisplayEnabled) {
Dianne Hackborncc956672009-03-26 00:04:52 -07003337 Surface.setOrientation(0, rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 }
3339 for (int i=mWindows.size()-1; i>=0; i--) {
3340 WindowState w = (WindowState)mWindows.get(i);
3341 if (w.mSurface != null) {
3342 w.mOrientationChanging = true;
3343 }
3344 }
3345 for (int i=mRotationWatchers.size()-1; i>=0; i--) {
3346 try {
3347 mRotationWatchers.get(i).onRotationChanged(rotation);
3348 } catch (RemoteException e) {
3349 }
3350 }
3351 } //end if changed
3352
3353 return changed;
3354 }
3355
3356 public int getRotation() {
3357 return mRotation;
3358 }
3359
3360 public int watchRotation(IRotationWatcher watcher) {
3361 final IBinder watcherBinder = watcher.asBinder();
3362 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
3363 public void binderDied() {
3364 synchronized (mWindowMap) {
3365 for (int i=0; i<mRotationWatchers.size(); i++) {
3366 if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
3367 mRotationWatchers.remove(i);
3368 i--;
3369 }
3370 }
3371 }
3372 }
3373 };
3374
3375 synchronized (mWindowMap) {
3376 try {
3377 watcher.asBinder().linkToDeath(dr, 0);
3378 mRotationWatchers.add(watcher);
3379 } catch (RemoteException e) {
3380 // Client died, no cleanup needed.
3381 }
3382
3383 return mRotation;
3384 }
3385 }
3386
3387 /**
3388 * Starts the view server on the specified port.
3389 *
3390 * @param port The port to listener to.
3391 *
3392 * @return True if the server was successfully started, false otherwise.
3393 *
3394 * @see com.android.server.ViewServer
3395 * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
3396 */
3397 public boolean startViewServer(int port) {
3398 if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
3399 return false;
3400 }
3401
3402 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
3403 return false;
3404 }
3405
3406 if (port < 1024) {
3407 return false;
3408 }
3409
3410 if (mViewServer != null) {
3411 if (!mViewServer.isRunning()) {
3412 try {
3413 return mViewServer.start();
3414 } catch (IOException e) {
3415 Log.w(TAG, "View server did not start");
3416 }
3417 }
3418 return false;
3419 }
3420
3421 try {
3422 mViewServer = new ViewServer(this, port);
3423 return mViewServer.start();
3424 } catch (IOException e) {
3425 Log.w(TAG, "View server did not start");
3426 }
3427 return false;
3428 }
3429
3430 /**
3431 * Stops the view server if it exists.
3432 *
3433 * @return True if the server stopped, false if it wasn't started or
3434 * couldn't be stopped.
3435 *
3436 * @see com.android.server.ViewServer
3437 */
3438 public boolean stopViewServer() {
3439 if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
3440 return false;
3441 }
3442
3443 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
3444 return false;
3445 }
3446
3447 if (mViewServer != null) {
3448 return mViewServer.stop();
3449 }
3450 return false;
3451 }
3452
3453 /**
3454 * Indicates whether the view server is running.
3455 *
3456 * @return True if the server is running, false otherwise.
3457 *
3458 * @see com.android.server.ViewServer
3459 */
3460 public boolean isViewServerRunning() {
3461 if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
3462 return false;
3463 }
3464
3465 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
3466 return false;
3467 }
3468
3469 return mViewServer != null && mViewServer.isRunning();
3470 }
3471
3472 /**
3473 * Lists all availble windows in the system. The listing is written in the
3474 * specified Socket's output stream with the following syntax:
3475 * windowHashCodeInHexadecimal windowName
3476 * Each line of the ouput represents a different window.
3477 *
3478 * @param client The remote client to send the listing to.
3479 * @return False if an error occured, true otherwise.
3480 */
3481 boolean viewServerListWindows(Socket client) {
3482 if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
3483 return false;
3484 }
3485
3486 boolean result = true;
3487
3488 Object[] windows;
3489 synchronized (mWindowMap) {
3490 windows = new Object[mWindows.size()];
3491 //noinspection unchecked
3492 windows = mWindows.toArray(windows);
3493 }
3494
3495 BufferedWriter out = null;
3496
3497 // Any uncaught exception will crash the system process
3498 try {
3499 OutputStream clientStream = client.getOutputStream();
3500 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
3501
3502 final int count = windows.length;
3503 for (int i = 0; i < count; i++) {
3504 final WindowState w = (WindowState) windows[i];
3505 out.write(Integer.toHexString(System.identityHashCode(w)));
3506 out.write(' ');
3507 out.append(w.mAttrs.getTitle());
3508 out.write('\n');
3509 }
3510
3511 out.write("DONE.\n");
3512 out.flush();
3513 } catch (Exception e) {
3514 result = false;
3515 } finally {
3516 if (out != null) {
3517 try {
3518 out.close();
3519 } catch (IOException e) {
3520 result = false;
3521 }
3522 }
3523 }
3524
3525 return result;
3526 }
3527
3528 /**
3529 * Sends a command to a target window. The result of the command, if any, will be
3530 * written in the output stream of the specified socket.
3531 *
3532 * The parameters must follow this syntax:
3533 * windowHashcode extra
3534 *
3535 * Where XX is the length in characeters of the windowTitle.
3536 *
3537 * The first parameter is the target window. The window with the specified hashcode
3538 * will be the target. If no target can be found, nothing happens. The extra parameters
3539 * will be delivered to the target window and as parameters to the command itself.
3540 *
3541 * @param client The remote client to sent the result, if any, to.
3542 * @param command The command to execute.
3543 * @param parameters The command parameters.
3544 *
3545 * @return True if the command was successfully delivered, false otherwise. This does
3546 * not indicate whether the command itself was successful.
3547 */
3548 boolean viewServerWindowCommand(Socket client, String command, String parameters) {
3549 if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
3550 return false;
3551 }
3552
3553 boolean success = true;
3554 Parcel data = null;
3555 Parcel reply = null;
3556
3557 // Any uncaught exception will crash the system process
3558 try {
3559 // Find the hashcode of the window
3560 int index = parameters.indexOf(' ');
3561 if (index == -1) {
3562 index = parameters.length();
3563 }
3564 final String code = parameters.substring(0, index);
3565 int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
3566
3567 // Extract the command's parameter after the window description
3568 if (index < parameters.length()) {
3569 parameters = parameters.substring(index + 1);
3570 } else {
3571 parameters = "";
3572 }
3573
3574 final WindowManagerService.WindowState window = findWindow(hashCode);
3575 if (window == null) {
3576 return false;
3577 }
3578
3579 data = Parcel.obtain();
3580 data.writeInterfaceToken("android.view.IWindow");
3581 data.writeString(command);
3582 data.writeString(parameters);
3583 data.writeInt(1);
3584 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
3585
3586 reply = Parcel.obtain();
3587
3588 final IBinder binder = window.mClient.asBinder();
3589 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
3590 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
3591
3592 reply.readException();
3593
3594 } catch (Exception e) {
3595 Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
3596 success = false;
3597 } finally {
3598 if (data != null) {
3599 data.recycle();
3600 }
3601 if (reply != null) {
3602 reply.recycle();
3603 }
3604 }
3605
3606 return success;
3607 }
3608
3609 private WindowState findWindow(int hashCode) {
3610 if (hashCode == -1) {
3611 return getFocusedWindow();
3612 }
3613
3614 synchronized (mWindowMap) {
3615 final ArrayList windows = mWindows;
3616 final int count = windows.size();
3617
3618 for (int i = 0; i < count; i++) {
3619 WindowState w = (WindowState) windows.get(i);
3620 if (System.identityHashCode(w) == hashCode) {
3621 return w;
3622 }
3623 }
3624 }
3625
3626 return null;
3627 }
3628
3629 /*
3630 * Instruct the Activity Manager to fetch the current configuration and broadcast
3631 * that to config-changed listeners if appropriate.
3632 */
3633 void sendNewConfiguration() {
3634 try {
3635 mActivityManager.updateConfiguration(null);
3636 } catch (RemoteException e) {
3637 }
3638 }
3639
3640 public Configuration computeNewConfiguration() {
3641 synchronized (mWindowMap) {
Dianne Hackborn9d4de632009-03-24 19:37:25 -07003642 return computeNewConfigurationLocked();
3643 }
3644 }
3645
3646 Configuration computeNewConfigurationLocked() {
3647 Configuration config = new Configuration();
3648 if (!computeNewConfigurationLocked(config)) {
3649 return null;
3650 }
3651 Log.i(TAG, "Config changed: " + config);
3652 long now = SystemClock.uptimeMillis();
3653 //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
3654 if (mFreezeGcPending != 0) {
3655 if (now > (mFreezeGcPending+1000)) {
3656 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
3657 mH.removeMessages(H.FORCE_GC);
3658 Runtime.getRuntime().gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 mFreezeGcPending = now;
3660 }
Dianne Hackborn9d4de632009-03-24 19:37:25 -07003661 } else {
3662 mFreezeGcPending = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 }
Dianne Hackborn9d4de632009-03-24 19:37:25 -07003664 return config;
3665 }
3666
3667 boolean computeNewConfigurationLocked(Configuration config) {
3668 if (mDisplay == null) {
3669 return false;
3670 }
3671 mQueue.getInputConfiguration(config);
3672 final int dw = mDisplay.getWidth();
3673 final int dh = mDisplay.getHeight();
3674 int orientation = Configuration.ORIENTATION_SQUARE;
3675 if (dw < dh) {
3676 orientation = Configuration.ORIENTATION_PORTRAIT;
3677 } else if (dw > dh) {
3678 orientation = Configuration.ORIENTATION_LANDSCAPE;
3679 }
3680 config.orientation = orientation;
3681 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
3682 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
3683 mPolicy.adjustConfigurationLw(config);
3684 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003685 }
3686
3687 // -------------------------------------------------------------
3688 // Input Events and Focus Management
3689 // -------------------------------------------------------------
3690
3691 private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
3692 if (targetWin == null ||
3693 targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
3694 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, eventType);
3695 }
3696 }
3697
3698 // tells if it's a cheek event or not -- this function is stateful
3699 private static final int EVENT_NONE = 0;
3700 private static final int EVENT_UNKNOWN = 0;
3701 private static final int EVENT_CHEEK = 0;
3702 private static final int EVENT_IGNORE_DURATION = 300; // ms
3703 private static final float CHEEK_THRESHOLD = 0.6f;
3704 private int mEventState = EVENT_NONE;
3705 private float mEventSize;
The Android Open Source Projectc2ad2412009-03-19 23:08:54 -07003706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 private int eventType(MotionEvent ev) {
3708 float size = ev.getSize();
3709 switch (ev.getAction()) {
3710 case MotionEvent.ACTION_DOWN:
3711 mEventSize = size;
3712 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
3713 case MotionEvent.ACTION_UP:
3714 if (size > mEventSize) mEventSize = size;
The Android Open Source Projectc2ad2412009-03-19 23:08:54 -07003715 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003716 case MotionEvent.ACTION_MOVE:
3717 final int N = ev.getHistorySize();
3718 if (size > mEventSize) mEventSize = size;
3719 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3720 for (int i=0; i<N; i++) {
3721 size = ev.getHistoricalSize(i);
3722 if (size > mEventSize) mEventSize = size;
3723 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3724 }
3725 if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
3726 return TOUCH_EVENT;
3727 } else {
The Android Open Source Projectc2ad2412009-03-19 23:08:54 -07003728 return LONG_TOUCH_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003729 }
3730 default:
3731 // not good
3732 return OTHER_EVENT;
3733 }
3734 }
3735
3736 /**
3737 * @return Returns true if event was dispatched, false if it was dropped for any reason
3738 */
3739 private boolean dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
3740 if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
3741 "dispatchPointer " + ev);
3742
3743 Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
3744 ev, true, false);
3745
3746 int action = ev.getAction();
3747
3748 if (action == MotionEvent.ACTION_UP) {
3749 // let go of our target
3750 mKeyWaiter.mMotionTarget = null;
3751 mPowerManager.logPointerUpEvent();
3752 } else if (action == MotionEvent.ACTION_DOWN) {
3753 mPowerManager.logPointerDownEvent();
3754 }
3755
3756 if (targetObj == null) {
3757 // In this case we are either dropping the event, or have received
3758 // a move or up without a down. It is common to receive move
3759 // events in such a way, since this means the user is moving the
3760 // pointer without actually pressing down. All other cases should
3761 // be atypical, so let's log them.
3762 if (ev.getAction() != MotionEvent.ACTION_MOVE) {
3763 Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
3764 }
3765 if (qev != null) {
3766 mQueue.recycleEvent(qev);
3767 }
3768 ev.recycle();
3769 return false;
3770 }
3771 if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3772 if (qev != null) {
3773 mQueue.recycleEvent(qev);
3774 }
3775 ev.recycle();
3776 return true;
3777 }
3778
3779 WindowState target = (WindowState)targetObj;
3780
3781 final long eventTime = ev.getEventTime();
3782
3783 //Log.i(TAG, "Sending " + ev + " to " + target);
3784
3785 if (uid != 0 && uid != target.mSession.mUid) {
3786 if (mContext.checkPermission(
3787 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3788 != PackageManager.PERMISSION_GRANTED) {
3789 Log.w(TAG, "Permission denied: injecting pointer event from pid "
3790 + pid + " uid " + uid + " to window " + target
3791 + " owned by uid " + target.mSession.mUid);
3792 if (qev != null) {
3793 mQueue.recycleEvent(qev);
3794 }
3795 ev.recycle();
3796 return false;
3797 }
3798 }
3799
3800 if ((target.mAttrs.flags &
3801 WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
3802 //target wants to ignore fat touch events
3803 boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
3804 //explicit flag to return without processing event further
3805 boolean returnFlag = false;
3806 if((action == MotionEvent.ACTION_DOWN)) {
3807 mFatTouch = false;
3808 if(cheekPress) {
3809 mFatTouch = true;
3810 returnFlag = true;
3811 }
3812 } else {
3813 if(action == MotionEvent.ACTION_UP) {
3814 if(mFatTouch) {
3815 //earlier even was invalid doesnt matter if current up is cheekpress or not
3816 mFatTouch = false;
3817 returnFlag = true;
3818 } else if(cheekPress) {
3819 //cancel the earlier event
3820 ev.setAction(MotionEvent.ACTION_CANCEL);
3821 action = MotionEvent.ACTION_CANCEL;
3822 }
3823 } else if(action == MotionEvent.ACTION_MOVE) {
3824 if(mFatTouch) {
3825 //two cases here
3826 //an invalid down followed by 0 or moves(valid or invalid)
3827 //a valid down, invalid move, more moves. want to ignore till up
3828 returnFlag = true;
3829 } else if(cheekPress) {
3830 //valid down followed by invalid moves
3831 //an invalid move have to cancel earlier action
3832 ev.setAction(MotionEvent.ACTION_CANCEL);
3833 action = MotionEvent.ACTION_CANCEL;
3834 if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE");
3835 //note that the subsequent invalid moves will not get here
3836 mFatTouch = true;
3837 }
3838 }
3839 } //else if action
3840 if(returnFlag) {
3841 //recycle que, ev
3842 if (qev != null) {
3843 mQueue.recycleEvent(qev);
3844 }
3845 ev.recycle();
3846 return false;
3847 }
3848 } //end if target
3849
3850 synchronized(mWindowMap) {
3851 if (qev != null && action == MotionEvent.ACTION_MOVE) {
3852 mKeyWaiter.bindTargetWindowLocked(target,
3853 KeyWaiter.RETURN_PENDING_POINTER, qev);
3854 ev = null;
3855 } else {
3856 if (action == MotionEvent.ACTION_DOWN) {
3857 WindowState out = mKeyWaiter.mOutsideTouchTargets;
3858 if (out != null) {
3859 MotionEvent oev = MotionEvent.obtain(ev);
3860 oev.setAction(MotionEvent.ACTION_OUTSIDE);
3861 do {
3862 final Rect frame = out.mFrame;
3863 oev.offsetLocation(-(float)frame.left, -(float)frame.top);
3864 try {
3865 out.mClient.dispatchPointer(oev, eventTime);
3866 } catch (android.os.RemoteException e) {
3867 Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
3868 }
3869 oev.offsetLocation((float)frame.left, (float)frame.top);
3870 out = out.mNextOutsideTouch;
3871 } while (out != null);
3872 mKeyWaiter.mOutsideTouchTargets = null;
3873 }
3874 }
3875 final Rect frame = target.mFrame;
3876 ev.offsetLocation(-(float)frame.left, -(float)frame.top);
3877 mKeyWaiter.bindTargetWindowLocked(target);
3878 }
3879 }
3880
3881 // finally offset the event to the target's coordinate system and
3882 // dispatch the event.
3883 try {
3884 if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
3885 Log.v(TAG, "Delivering pointer " + qev + " to " + target);
3886 }
3887 target.mClient.dispatchPointer(ev, eventTime);
3888 return true;
3889 } catch (android.os.RemoteException e) {
3890 Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
3891 mKeyWaiter.mMotionTarget = null;
3892 try {
3893 removeWindow(target.mSession, target.mClient);
3894 } catch (java.util.NoSuchElementException ex) {
3895 // This will happen if the window has already been
3896 // removed.
3897 }
3898 }
3899 return false;
3900 }
3901
3902 /**
3903 * @return Returns true if event was dispatched, false if it was dropped for any reason
3904 */
3905 private boolean dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
3906 if (DEBUG_INPUT) Log.v(
3907 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
3908
3909 Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
3910 ev, false, false);
3911 if (focusObj == null) {
3912 Log.w(TAG, "No focus window, dropping trackball: " + ev);
3913 if (qev != null) {
3914 mQueue.recycleEvent(qev);
3915 }
3916 ev.recycle();
3917 return false;
3918 }
3919 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3920 if (qev != null) {
3921 mQueue.recycleEvent(qev);
3922 }
3923 ev.recycle();
3924 return true;
3925 }
3926
3927 WindowState focus = (WindowState)focusObj;
3928
3929 if (uid != 0 && uid != focus.mSession.mUid) {
3930 if (mContext.checkPermission(
3931 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3932 != PackageManager.PERMISSION_GRANTED) {
3933 Log.w(TAG, "Permission denied: injecting key event from pid "
3934 + pid + " uid " + uid + " to window " + focus
3935 + " owned by uid " + focus.mSession.mUid);
3936 if (qev != null) {
3937 mQueue.recycleEvent(qev);
3938 }
3939 ev.recycle();
3940 return false;
3941 }
3942 }
3943
3944 final long eventTime = ev.getEventTime();
3945
3946 synchronized(mWindowMap) {
3947 if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
3948 mKeyWaiter.bindTargetWindowLocked(focus,
3949 KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
3950 // We don't deliver movement events to the client, we hold
3951 // them and wait for them to call back.
3952 ev = null;
3953 } else {
3954 mKeyWaiter.bindTargetWindowLocked(focus);
3955 }
3956 }
3957
3958 try {
3959 focus.mClient.dispatchTrackball(ev, eventTime);
3960 return true;
3961 } catch (android.os.RemoteException e) {
3962 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
3963 try {
3964 removeWindow(focus.mSession, focus.mClient);
3965 } catch (java.util.NoSuchElementException ex) {
3966 // This will happen if the window has already been
3967 // removed.
3968 }
3969 }
3970
3971 return false;
3972 }
3973
3974 /**
3975 * @return Returns true if event was dispatched, false if it was dropped for any reason
3976 */
3977 private boolean dispatchKey(KeyEvent event, int pid, int uid) {
3978 if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
3979
3980 Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
3981 null, false, false);
3982 if (focusObj == null) {
3983 Log.w(TAG, "No focus window, dropping: " + event);
3984 return false;
3985 }
3986 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3987 return true;
3988 }
3989
3990 WindowState focus = (WindowState)focusObj;
3991
3992 if (DEBUG_INPUT) Log.v(
3993 TAG, "Dispatching to " + focus + ": " + event);
3994
3995 if (uid != 0 && uid != focus.mSession.mUid) {
3996 if (mContext.checkPermission(
3997 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3998 != PackageManager.PERMISSION_GRANTED) {
3999 Log.w(TAG, "Permission denied: injecting key event from pid "
4000 + pid + " uid " + uid + " to window " + focus
4001 + " owned by uid " + focus.mSession.mUid);
4002 return false;
4003 }
4004 }
4005
4006 synchronized(mWindowMap) {
4007 mKeyWaiter.bindTargetWindowLocked(focus);
4008 }
4009
4010 // NOSHIP extra state logging
4011 mKeyWaiter.recordDispatchState(event, focus);
4012 // END NOSHIP
4013
4014 try {
4015 if (DEBUG_INPUT || DEBUG_FOCUS) {
4016 Log.v(TAG, "Delivering key " + event.getKeyCode()
4017 + " to " + focus);
4018 }
4019 focus.mClient.dispatchKey(event);
4020 return true;
4021 } catch (android.os.RemoteException e) {
4022 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4023 try {
4024 removeWindow(focus.mSession, focus.mClient);
4025 } catch (java.util.NoSuchElementException ex) {
4026 // This will happen if the window has already been
4027 // removed.
4028 }
4029 }
4030
4031 return false;
4032 }
4033
4034 public void pauseKeyDispatching(IBinder _token) {
4035 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4036 "pauseKeyDispatching()")) {
4037 return;
4038 }
4039
4040 synchronized (mWindowMap) {
4041 WindowToken token = mTokenMap.get(_token);
4042 if (token != null) {
4043 mKeyWaiter.pauseDispatchingLocked(token);
4044 }
4045 }
4046 }
4047
4048 public void resumeKeyDispatching(IBinder _token) {
4049 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4050 "resumeKeyDispatching()")) {
4051 return;
4052 }
4053
4054 synchronized (mWindowMap) {
4055 WindowToken token = mTokenMap.get(_token);
4056 if (token != null) {
4057 mKeyWaiter.resumeDispatchingLocked(token);
4058 }
4059 }
4060 }
4061
4062 public void setEventDispatching(boolean enabled) {
4063 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4064 "resumeKeyDispatching()")) {
4065 return;
4066 }
4067
4068 synchronized (mWindowMap) {
4069 mKeyWaiter.setEventDispatchingLocked(enabled);
4070 }
4071 }
4072
4073 /**
4074 * Injects a keystroke event into the UI.
4075 *
4076 * @param ev A motion event describing the keystroke action. (Be sure to use
4077 * {@link SystemClock#uptimeMillis()} as the timebase.)
4078 * @param sync If true, wait for the event to be completed before returning to the caller.
4079 * @return Returns true if event was dispatched, false if it was dropped for any reason
4080 */
4081 public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
4082 long downTime = ev.getDownTime();
4083 long eventTime = ev.getEventTime();
4084
4085 int action = ev.getAction();
4086 int code = ev.getKeyCode();
4087 int repeatCount = ev.getRepeatCount();
4088 int metaState = ev.getMetaState();
4089 int deviceId = ev.getDeviceId();
4090 int scancode = ev.getScanCode();
4091
4092 if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
4093 if (downTime == 0) downTime = eventTime;
4094
4095 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
The Android Open Source Project10592532009-03-18 17:39:46 -07004096 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097
4098 boolean result = dispatchKey(newEvent, Binder.getCallingPid(), Binder.getCallingUid());
4099 if (sync) {
4100 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
4101 }
4102 return result;
4103 }
4104
4105 /**
4106 * Inject a pointer (touch) event into the UI.
4107 *
4108 * @param ev A motion event describing the pointer (touch) action. (As noted in
4109 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
4110 * {@link SystemClock#uptimeMillis()} as the timebase.)
4111 * @param sync If true, wait for the event to be completed before returning to the caller.
4112 * @return Returns true if event was dispatched, false if it was dropped for any reason
4113 */
4114 public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
4115 boolean result = dispatchPointer(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
4116 if (sync) {
4117 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
4118 }
4119 return result;
4120 }
4121
4122 /**
4123 * Inject a trackball (navigation device) event into the UI.
4124 *
4125 * @param ev A motion event describing the trackball action. (As noted in
4126 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
4127 * {@link SystemClock#uptimeMillis()} as the timebase.)
4128 * @param sync If true, wait for the event to be completed before returning to the caller.
4129 * @return Returns true if event was dispatched, false if it was dropped for any reason
4130 */
4131 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
4132 boolean result = dispatchTrackball(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
4133 if (sync) {
4134 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
4135 }
4136 return result;
4137 }
4138
4139 private WindowState getFocusedWindow() {
4140 synchronized (mWindowMap) {
4141 return getFocusedWindowLocked();
4142 }
4143 }
4144
4145 private WindowState getFocusedWindowLocked() {
4146 return mCurrentFocus;
4147 }
4148
4149 /**
4150 * This class holds the state for dispatching key events. This state
4151 * is protected by the KeyWaiter instance, NOT by the window lock. You
4152 * can be holding the main window lock while acquire the KeyWaiter lock,
4153 * but not the other way around.
4154 */
4155 final class KeyWaiter {
4156 // NOSHIP debugging
4157 public class DispatchState {
4158 private KeyEvent event;
4159 private WindowState focus;
4160 private long time;
4161 private WindowState lastWin;
4162 private IBinder lastBinder;
4163 private boolean finished;
4164 private boolean gotFirstWindow;
4165 private boolean eventDispatching;
4166 private long timeToSwitch;
4167 private boolean wasFrozen;
4168 private boolean focusPaused;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004169 private WindowState curFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004170
4171 DispatchState(KeyEvent theEvent, WindowState theFocus) {
4172 focus = theFocus;
4173 event = theEvent;
4174 time = System.currentTimeMillis();
4175 // snapshot KeyWaiter state
4176 lastWin = mLastWin;
4177 lastBinder = mLastBinder;
4178 finished = mFinished;
4179 gotFirstWindow = mGotFirstWindow;
4180 eventDispatching = mEventDispatching;
4181 timeToSwitch = mTimeToSwitch;
4182 wasFrozen = mWasFrozen;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004183 curFocus = mCurrentFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004184 // cache the paused state at ctor time as well
4185 if (theFocus == null || theFocus.mToken == null) {
4186 Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
4187 focusPaused = false;
4188 } else {
4189 focusPaused = theFocus.mToken.paused;
4190 }
4191 }
4192
4193 public String toString() {
4194 return "{{" + event + " to " + focus + " @ " + time
4195 + " lw=" + lastWin + " lb=" + lastBinder
4196 + " fin=" + finished + " gfw=" + gotFirstWindow
4197 + " ed=" + eventDispatching + " tts=" + timeToSwitch
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004198 + " wf=" + wasFrozen + " fp=" + focusPaused
4199 + " mcf=" + mCurrentFocus + "}}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004200 }
4201 };
4202 private DispatchState mDispatchState = null;
4203 public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
4204 mDispatchState = new DispatchState(theEvent, theFocus);
4205 }
4206 // END NOSHIP
4207
4208 public static final int RETURN_NOTHING = 0;
4209 public static final int RETURN_PENDING_POINTER = 1;
4210 public static final int RETURN_PENDING_TRACKBALL = 2;
4211
4212 final Object SKIP_TARGET_TOKEN = new Object();
4213 final Object CONSUMED_EVENT_TOKEN = new Object();
4214
4215 private WindowState mLastWin = null;
4216 private IBinder mLastBinder = null;
4217 private boolean mFinished = true;
4218 private boolean mGotFirstWindow = false;
4219 private boolean mEventDispatching = true;
4220 private long mTimeToSwitch = 0;
4221 /* package */ boolean mWasFrozen = false;
4222
4223 // Target of Motion events
4224 WindowState mMotionTarget;
4225
4226 // Windows above the target who would like to receive an "outside"
4227 // touch event for any down events outside of them.
4228 WindowState mOutsideTouchTargets;
4229
4230 /**
4231 * Wait for the last event dispatch to complete, then find the next
4232 * target that should receive the given event and wait for that one
4233 * to be ready to receive it.
4234 */
4235 Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
4236 MotionEvent nextMotion, boolean isPointerEvent,
4237 boolean failIfTimeout) {
4238 long startTime = SystemClock.uptimeMillis();
4239 long keyDispatchingTimeout = 5 * 1000;
4240 long waitedFor = 0;
4241
4242 while (true) {
4243 // Figure out which window we care about. It is either the
4244 // last window we are waiting to have process the event or,
4245 // if none, then the next window we think the event should go
4246 // to. Note: we retrieve mLastWin outside of the lock, so
4247 // it may change before we lock. Thus we must check it again.
4248 WindowState targetWin = mLastWin;
4249 boolean targetIsNew = targetWin == null;
4250 if (DEBUG_INPUT) Log.v(
4251 TAG, "waitForLastKey: mFinished=" + mFinished +
4252 ", mLastWin=" + mLastWin);
4253 if (targetIsNew) {
4254 Object target = findTargetWindow(nextKey, qev, nextMotion,
4255 isPointerEvent);
4256 if (target == SKIP_TARGET_TOKEN) {
4257 // The user has pressed a special key, and we are
4258 // dropping all pending events before it.
4259 if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey
4260 + " " + nextMotion);
4261 return null;
4262 }
4263 if (target == CONSUMED_EVENT_TOKEN) {
4264 if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
4265 + " " + nextMotion);
4266 return target;
4267 }
4268 targetWin = (WindowState)target;
4269 }
4270
4271 AppWindowToken targetApp = null;
4272
4273 // Now: is it okay to send the next event to this window?
4274 synchronized (this) {
4275 // First: did we come here based on the last window not
4276 // being null, but it changed by the time we got here?
4277 // If so, try again.
4278 if (!targetIsNew && mLastWin == null) {
4279 continue;
4280 }
4281
4282 // We never dispatch events if not finished with the
4283 // last one, or the display is frozen.
4284 if (mFinished && !mDisplayFrozen) {
4285 // If event dispatching is disabled, then we
4286 // just consume the events.
4287 if (!mEventDispatching) {
4288 if (DEBUG_INPUT) Log.v(TAG,
4289 "Skipping event; dispatching disabled: "
4290 + nextKey + " " + nextMotion);
4291 return null;
4292 }
4293 if (targetWin != null) {
4294 // If this is a new target, and that target is not
4295 // paused or unresponsive, then all looks good to
4296 // handle the event.
4297 if (targetIsNew && !targetWin.mToken.paused) {
4298 return targetWin;
4299 }
4300
4301 // If we didn't find a target window, and there is no
4302 // focused app window, then just eat the events.
4303 } else if (mFocusedApp == null) {
4304 if (DEBUG_INPUT) Log.v(TAG,
4305 "Skipping event; no focused app: "
4306 + nextKey + " " + nextMotion);
4307 return null;
4308 }
4309 }
4310
4311 if (DEBUG_INPUT) Log.v(
4312 TAG, "Waiting for last key in " + mLastBinder
4313 + " target=" + targetWin
4314 + " mFinished=" + mFinished
4315 + " mDisplayFrozen=" + mDisplayFrozen
4316 + " targetIsNew=" + targetIsNew
4317 + " paused="
4318 + (targetWin != null ? targetWin.mToken.paused : false)
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004319 + " mFocusedApp=" + mFocusedApp
4320 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004321
4322 targetApp = targetWin != null
4323 ? targetWin.mAppToken : mFocusedApp;
4324
4325 long curTimeout = keyDispatchingTimeout;
4326 if (mTimeToSwitch != 0) {
4327 long now = SystemClock.uptimeMillis();
4328 if (mTimeToSwitch <= now) {
4329 // If an app switch key has been pressed, and we have
4330 // waited too long for the current app to finish
4331 // processing keys, then wait no more!
4332 doFinishedKeyLocked(true);
4333 continue;
4334 }
4335 long switchTimeout = mTimeToSwitch - now;
4336 if (curTimeout > switchTimeout) {
4337 curTimeout = switchTimeout;
4338 }
4339 }
4340
4341 try {
4342 // after that continue
4343 // processing keys, so we don't get stuck.
4344 if (DEBUG_INPUT) Log.v(
4345 TAG, "Waiting for key dispatch: " + curTimeout);
4346 wait(curTimeout);
4347 if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
4348 + SystemClock.uptimeMillis() + " startTime="
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004349 + startTime + " switchTime=" + mTimeToSwitch
4350 + " target=" + targetWin + " mLW=" + mLastWin
4351 + " mLB=" + mLastBinder + " fin=" + mFinished
4352 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004353 } catch (InterruptedException e) {
4354 }
4355 }
4356
4357 // If we were frozen during configuration change, restart the
4358 // timeout checks from now; otherwise look at whether we timed
4359 // out before awakening.
4360 if (mWasFrozen) {
4361 waitedFor = 0;
4362 mWasFrozen = false;
4363 } else {
4364 waitedFor = SystemClock.uptimeMillis() - startTime;
4365 }
4366
4367 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
4368 IApplicationToken at = null;
4369 synchronized (this) {
4370 Log.w(TAG, "Key dispatching timed out sending to " +
4371 (targetWin != null ? targetWin.mAttrs.getTitle()
4372 : "<null>"));
4373 // NOSHIP debugging
4374 Log.w(TAG, "Dispatch state: " + mDispatchState);
4375 Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
4376 // END NOSHIP
4377 //dump();
4378 if (targetWin != null) {
4379 at = targetWin.getAppToken();
4380 } else if (targetApp != null) {
4381 at = targetApp.appToken;
4382 }
4383 }
4384
4385 boolean abort = true;
4386 if (at != null) {
4387 try {
4388 long timeout = at.getKeyDispatchingTimeout();
4389 if (timeout > waitedFor) {
4390 // we did not wait the proper amount of time for this application.
4391 // set the timeout to be the real timeout and wait again.
4392 keyDispatchingTimeout = timeout - waitedFor;
4393 continue;
4394 } else {
4395 abort = at.keyDispatchingTimedOut();
4396 }
4397 } catch (RemoteException ex) {
4398 }
4399 }
4400
4401 synchronized (this) {
4402 if (abort && (mLastWin == targetWin || targetWin == null)) {
4403 mFinished = true;
4404 if (mLastWin != null) {
4405 if (DEBUG_INPUT) Log.v(TAG,
4406 "Window " + mLastWin +
4407 " timed out on key input");
4408 if (mLastWin.mToken.paused) {
4409 Log.w(TAG, "Un-pausing dispatching to this window");
4410 mLastWin.mToken.paused = false;
4411 }
4412 }
4413 if (mMotionTarget == targetWin) {
4414 mMotionTarget = null;
4415 }
4416 mLastWin = null;
4417 mLastBinder = null;
4418 if (failIfTimeout || targetWin == null) {
4419 return null;
4420 }
4421 } else {
4422 Log.w(TAG, "Continuing to wait for key to be dispatched");
4423 startTime = SystemClock.uptimeMillis();
4424 }
4425 }
4426 }
4427 }
4428 }
4429
4430 Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
4431 MotionEvent nextMotion, boolean isPointerEvent) {
4432 mOutsideTouchTargets = null;
4433
4434 if (nextKey != null) {
4435 // Find the target window for a normal key event.
4436 final int keycode = nextKey.getKeyCode();
4437 final int repeatCount = nextKey.getRepeatCount();
4438 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
4439 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
4440 if (!dispatch) {
4441 mPolicy.interceptKeyTi(null, keycode,
4442 nextKey.getMetaState(), down, repeatCount);
4443 Log.w(TAG, "Event timeout during app switch: dropping "
4444 + nextKey);
4445 return SKIP_TARGET_TOKEN;
4446 }
4447
4448 // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
4449
4450 WindowState focus = null;
4451 synchronized(mWindowMap) {
4452 focus = getFocusedWindowLocked();
4453 }
4454
4455 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
4456
4457 if (mPolicy.interceptKeyTi(focus,
4458 keycode, nextKey.getMetaState(), down, repeatCount)) {
4459 return CONSUMED_EVENT_TOKEN;
4460 }
4461
4462 return focus;
4463
4464 } else if (!isPointerEvent) {
4465 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
4466 if (!dispatch) {
4467 Log.w(TAG, "Event timeout during app switch: dropping trackball "
4468 + nextMotion);
4469 return SKIP_TARGET_TOKEN;
4470 }
4471
4472 WindowState focus = null;
4473 synchronized(mWindowMap) {
4474 focus = getFocusedWindowLocked();
4475 }
4476
4477 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
4478 return focus;
4479 }
4480
4481 if (nextMotion == null) {
4482 return SKIP_TARGET_TOKEN;
4483 }
4484
4485 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
4486 KeyEvent.KEYCODE_UNKNOWN);
4487 if (!dispatch) {
4488 Log.w(TAG, "Event timeout during app switch: dropping pointer "
4489 + nextMotion);
4490 return SKIP_TARGET_TOKEN;
4491 }
4492
4493 // Find the target window for a pointer event.
4494 int action = nextMotion.getAction();
4495 final float xf = nextMotion.getX();
4496 final float yf = nextMotion.getY();
4497 final long eventTime = nextMotion.getEventTime();
4498
4499 final boolean screenWasOff = qev != null
4500 && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
4501
4502 WindowState target = null;
4503
4504 synchronized(mWindowMap) {
4505 synchronized (this) {
4506 if (action == MotionEvent.ACTION_DOWN) {
4507 if (mMotionTarget != null) {
4508 // this is weird, we got a pen down, but we thought it was
4509 // already down!
4510 // XXX: We should probably send an ACTION_UP to the current
4511 // target.
4512 Log.w(TAG, "Pointer down received while already down in: "
4513 + mMotionTarget);
4514 mMotionTarget = null;
4515 }
4516
4517 // ACTION_DOWN is special, because we need to lock next events to
4518 // the window we'll land onto.
4519 final int x = (int)xf;
4520 final int y = (int)yf;
4521
4522 final ArrayList windows = mWindows;
4523 final int N = windows.size();
4524 WindowState topErrWindow = null;
4525 final Rect tmpRect = mTempRect;
4526 for (int i=N-1; i>=0; i--) {
4527 WindowState child = (WindowState)windows.get(i);
4528 //Log.i(TAG, "Checking dispatch to: " + child);
4529 final int flags = child.mAttrs.flags;
4530 if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
4531 if (topErrWindow == null) {
4532 topErrWindow = child;
4533 }
4534 }
4535 if (!child.isVisibleLw()) {
4536 //Log.i(TAG, "Not visible!");
4537 continue;
4538 }
4539 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
4540 //Log.i(TAG, "Not touchable!");
4541 if ((flags & WindowManager.LayoutParams
4542 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4543 child.mNextOutsideTouch = mOutsideTouchTargets;
4544 mOutsideTouchTargets = child;
4545 }
4546 continue;
4547 }
4548 tmpRect.set(child.mFrame);
4549 if (child.mTouchableInsets == ViewTreeObserver
4550 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
4551 // The touch is inside of the window if it is
4552 // inside the frame, AND the content part of that
4553 // frame that was given by the application.
4554 tmpRect.left += child.mGivenContentInsets.left;
4555 tmpRect.top += child.mGivenContentInsets.top;
4556 tmpRect.right -= child.mGivenContentInsets.right;
4557 tmpRect.bottom -= child.mGivenContentInsets.bottom;
4558 } else if (child.mTouchableInsets == ViewTreeObserver
4559 .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
4560 // The touch is inside of the window if it is
4561 // inside the frame, AND the visible part of that
4562 // frame that was given by the application.
4563 tmpRect.left += child.mGivenVisibleInsets.left;
4564 tmpRect.top += child.mGivenVisibleInsets.top;
4565 tmpRect.right -= child.mGivenVisibleInsets.right;
4566 tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
4567 }
4568 final int touchFlags = flags &
4569 (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
4570 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
4571 if (tmpRect.contains(x, y) || touchFlags == 0) {
4572 //Log.i(TAG, "Using this target!");
4573 if (!screenWasOff || (flags &
4574 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
4575 mMotionTarget = child;
4576 } else {
4577 //Log.i(TAG, "Waking, skip!");
4578 mMotionTarget = null;
4579 }
4580 break;
4581 }
4582
4583 if ((flags & WindowManager.LayoutParams
4584 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4585 child.mNextOutsideTouch = mOutsideTouchTargets;
4586 mOutsideTouchTargets = child;
4587 //Log.i(TAG, "Adding to outside target list: " + child);
4588 }
4589 }
4590
4591 // if there's an error window but it's not accepting
4592 // focus (typically because it is not yet visible) just
4593 // wait for it -- any other focused window may in fact
4594 // be in ANR state.
4595 if (topErrWindow != null && mMotionTarget != topErrWindow) {
4596 mMotionTarget = null;
4597 }
4598 }
4599
4600 target = mMotionTarget;
4601 }
4602 }
4603
4604 wakeupIfNeeded(target, eventType(nextMotion));
4605
4606 // Pointer events are a little different -- if there isn't a
4607 // target found for any event, then just drop it.
4608 return target != null ? target : SKIP_TARGET_TOKEN;
4609 }
4610
4611 boolean checkShouldDispatchKey(int keycode) {
4612 synchronized (this) {
4613 if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
4614 mTimeToSwitch = 0;
4615 return true;
4616 }
4617 if (mTimeToSwitch != 0
4618 && mTimeToSwitch < SystemClock.uptimeMillis()) {
4619 return false;
4620 }
4621 return true;
4622 }
4623 }
4624
4625 void bindTargetWindowLocked(WindowState win,
4626 int pendingWhat, QueuedEvent pendingMotion) {
4627 synchronized (this) {
4628 bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
4629 }
4630 }
4631
4632 void bindTargetWindowLocked(WindowState win) {
4633 synchronized (this) {
4634 bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
4635 }
4636 }
4637
4638 void bindTargetWindowLockedLocked(WindowState win,
4639 int pendingWhat, QueuedEvent pendingMotion) {
4640 mLastWin = win;
4641 mLastBinder = win.mClient.asBinder();
4642 mFinished = false;
4643 if (pendingMotion != null) {
4644 final Session s = win.mSession;
4645 if (pendingWhat == RETURN_PENDING_POINTER) {
4646 releasePendingPointerLocked(s);
4647 s.mPendingPointerMove = pendingMotion;
4648 s.mPendingPointerWindow = win;
4649 if (DEBUG_INPUT) Log.v(TAG,
4650 "bindTargetToWindow " + s.mPendingPointerMove);
4651 } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
4652 releasePendingTrackballLocked(s);
4653 s.mPendingTrackballMove = pendingMotion;
4654 s.mPendingTrackballWindow = win;
4655 }
4656 }
4657 }
4658
4659 void releasePendingPointerLocked(Session s) {
4660 if (DEBUG_INPUT) Log.v(TAG,
4661 "releasePendingPointer " + s.mPendingPointerMove);
4662 if (s.mPendingPointerMove != null) {
4663 mQueue.recycleEvent(s.mPendingPointerMove);
4664 s.mPendingPointerMove = null;
4665 }
4666 }
4667
4668 void releasePendingTrackballLocked(Session s) {
4669 if (s.mPendingTrackballMove != null) {
4670 mQueue.recycleEvent(s.mPendingTrackballMove);
4671 s.mPendingTrackballMove = null;
4672 }
4673 }
4674
4675 MotionEvent finishedKey(Session session, IWindow client, boolean force,
4676 int returnWhat) {
4677 if (DEBUG_INPUT) Log.v(
4678 TAG, "finishedKey: client=" + client + ", force=" + force);
4679
4680 if (client == null) {
4681 return null;
4682 }
4683
4684 synchronized (this) {
4685 if (DEBUG_INPUT) Log.v(
4686 TAG, "finishedKey: client=" + client.asBinder()
4687 + ", force=" + force + ", last=" + mLastBinder
4688 + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
4689
4690 QueuedEvent qev = null;
4691 WindowState win = null;
4692 if (returnWhat == RETURN_PENDING_POINTER) {
4693 qev = session.mPendingPointerMove;
4694 win = session.mPendingPointerWindow;
4695 session.mPendingPointerMove = null;
4696 session.mPendingPointerWindow = null;
4697 } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
4698 qev = session.mPendingTrackballMove;
4699 win = session.mPendingTrackballWindow;
4700 session.mPendingTrackballMove = null;
4701 session.mPendingTrackballWindow = null;
4702 }
4703
4704 if (mLastBinder == client.asBinder()) {
4705 if (DEBUG_INPUT) Log.v(
4706 TAG, "finishedKey: last paused="
4707 + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
4708 if (mLastWin != null && (!mLastWin.mToken.paused || force
4709 || !mEventDispatching)) {
4710 doFinishedKeyLocked(false);
4711 } else {
4712 // Make sure to wake up anyone currently waiting to
4713 // dispatch a key, so they can re-evaluate their
4714 // current situation.
4715 mFinished = true;
4716 notifyAll();
4717 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004718 }
4719
4720 if (qev != null) {
4721 MotionEvent res = (MotionEvent)qev.event;
4722 if (DEBUG_INPUT) Log.v(TAG,
4723 "Returning pending motion: " + res);
4724 mQueue.recycleEvent(qev);
4725 if (win != null && returnWhat == RETURN_PENDING_POINTER) {
4726 res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
4727 }
4728 return res;
4729 }
4730 return null;
4731 }
4732 }
4733
4734 void tickle() {
4735 synchronized (this) {
4736 notifyAll();
4737 }
4738 }
4739
4740 void handleNewWindowLocked(WindowState newWindow) {
4741 if (!newWindow.canReceiveKeys()) {
4742 return;
4743 }
4744 synchronized (this) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004745 if (DEBUG_INPUT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 TAG, "New key dispatch window: win="
4747 + newWindow.mClient.asBinder()
4748 + ", last=" + mLastBinder
4749 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
4750 + "), finished=" + mFinished + ", paused="
4751 + newWindow.mToken.paused);
4752
4753 // Displaying a window implicitly causes dispatching to
4754 // be unpaused. (This is to protect against bugs if someone
4755 // pauses dispatching but forgets to resume.)
4756 newWindow.mToken.paused = false;
4757
4758 mGotFirstWindow = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004759
4760 if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
4761 if (DEBUG_INPUT) Log.v(TAG,
4762 "New SYSTEM_ERROR window; resetting state");
4763 mLastWin = null;
4764 mLastBinder = null;
4765 mMotionTarget = null;
4766 mFinished = true;
4767 } else if (mLastWin != null) {
4768 // If the new window is above the window we are
4769 // waiting on, then stop waiting and let key dispatching
4770 // start on the new guy.
4771 if (DEBUG_INPUT) Log.v(
4772 TAG, "Last win layer=" + mLastWin.mLayer
4773 + ", new win layer=" + newWindow.mLayer);
4774 if (newWindow.mLayer >= mLastWin.mLayer) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004775 // The new window is above the old; finish pending input to the last
4776 // window and start directing it to the new one.
4777 mLastWin.mToken.paused = false;
4778 doFinishedKeyLocked(true); // does a notifyAll()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004779 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004780 // Either the new window is lower, so there is no need to wake key waiters,
4781 // or we just finished key input to the previous window, which implicitly
4782 // notified the key waiters. In both cases, we don't need to issue the
4783 // notification here.
4784 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004785 }
4786
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004787 // Now that we've put a new window state in place, make the event waiter
4788 // take notice and retarget its attentions.
4789 notifyAll();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004790 }
4791 }
4792
4793 void pauseDispatchingLocked(WindowToken token) {
4794 synchronized (this)
4795 {
4796 if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
4797 token.paused = true;
4798
4799 /*
4800 if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
4801 mPaused = true;
4802 } else {
4803 if (mLastWin == null) {
4804 if (Config.LOGI) Log.i(
4805 TAG, "Key dispatching not paused: no last window.");
4806 } else if (mFinished) {
4807 if (Config.LOGI) Log.i(
4808 TAG, "Key dispatching not paused: finished last key.");
4809 } else {
4810 if (Config.LOGI) Log.i(
4811 TAG, "Key dispatching not paused: window in higher layer.");
4812 }
4813 }
4814 */
4815 }
4816 }
4817
4818 void resumeDispatchingLocked(WindowToken token) {
4819 synchronized (this) {
4820 if (token.paused) {
4821 if (DEBUG_INPUT) Log.v(
4822 TAG, "Resuming WindowToken " + token
4823 + ", last=" + mLastBinder
4824 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
4825 + "), finished=" + mFinished + ", paused="
4826 + token.paused);
4827 token.paused = false;
4828 if (mLastWin != null && mLastWin.mToken == token && mFinished) {
4829 doFinishedKeyLocked(true);
4830 } else {
4831 notifyAll();
4832 }
4833 }
4834 }
4835 }
4836
4837 void setEventDispatchingLocked(boolean enabled) {
4838 synchronized (this) {
4839 mEventDispatching = enabled;
4840 notifyAll();
4841 }
4842 }
4843
4844 void appSwitchComing() {
4845 synchronized (this) {
4846 // Don't wait for more than .5 seconds for app to finish
4847 // processing the pending events.
4848 long now = SystemClock.uptimeMillis() + 500;
4849 if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now);
4850 if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
4851 mTimeToSwitch = now;
4852 }
4853 notifyAll();
4854 }
4855 }
4856
4857 private final void doFinishedKeyLocked(boolean doRecycle) {
4858 if (mLastWin != null) {
4859 releasePendingPointerLocked(mLastWin.mSession);
4860 releasePendingTrackballLocked(mLastWin.mSession);
4861 }
4862
4863 if (mLastWin == null || !mLastWin.mToken.paused
4864 || !mLastWin.isVisibleLw()) {
4865 // If the current window has been paused, we aren't -really-
4866 // finished... so let the waiters still wait.
4867 mLastWin = null;
4868 mLastBinder = null;
4869 }
4870 mFinished = true;
4871 notifyAll();
4872 }
4873 }
4874
4875 private class KeyQ extends KeyInputQueue
4876 implements KeyInputQueue.FilterCallback {
4877 PowerManager.WakeLock mHoldingScreen;
4878
4879 KeyQ() {
4880 super(mContext);
4881 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
4882 mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
4883 "KEEP_SCREEN_ON_FLAG");
4884 mHoldingScreen.setReferenceCounted(false);
4885 }
4886
4887 @Override
4888 boolean preprocessEvent(InputDevice device, RawInputEvent event) {
4889 if (mPolicy.preprocessInputEventTq(event)) {
4890 return true;
4891 }
4892
4893 switch (event.type) {
4894 case RawInputEvent.EV_KEY: {
4895 // XXX begin hack
4896 if (DEBUG) {
4897 if (event.keycode == KeyEvent.KEYCODE_G) {
4898 if (event.value != 0) {
4899 // G down
4900 mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
4901 }
4902 return false;
4903 }
4904 if (event.keycode == KeyEvent.KEYCODE_D) {
4905 if (event.value != 0) {
4906 //dump();
4907 }
4908 return false;
4909 }
4910 }
4911 // XXX end hack
4912
4913 boolean screenIsOff = !mPowerManager.screenIsOn();
4914 boolean screenIsDim = !mPowerManager.screenIsBright();
4915 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
4916
4917 if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
4918 mPowerManager.goToSleep(event.when);
4919 }
4920
4921 if (screenIsOff) {
4922 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
4923 }
4924 if (screenIsDim) {
4925 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
4926 }
4927 if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
4928 mPowerManager.userActivity(event.when, false,
4929 LocalPowerManager.BUTTON_EVENT);
4930 }
4931
4932 if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
4933 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
4934 filterQueue(this);
4935 mKeyWaiter.appSwitchComing();
4936 }
4937 return true;
4938 } else {
4939 return false;
4940 }
4941 }
4942
4943 case RawInputEvent.EV_REL: {
4944 boolean screenIsOff = !mPowerManager.screenIsOn();
4945 boolean screenIsDim = !mPowerManager.screenIsBright();
4946 if (screenIsOff) {
4947 if (!mPolicy.isWakeRelMovementTq(event.deviceId,
4948 device.classes, event)) {
4949 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
4950 return false;
4951 }
4952 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
4953 }
4954 if (screenIsDim) {
4955 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
4956 }
4957 return true;
4958 }
4959
4960 case RawInputEvent.EV_ABS: {
4961 boolean screenIsOff = !mPowerManager.screenIsOn();
4962 boolean screenIsDim = !mPowerManager.screenIsBright();
4963 if (screenIsOff) {
4964 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
4965 device.classes, event)) {
4966 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
4967 return false;
4968 }
4969 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
4970 }
4971 if (screenIsDim) {
4972 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
4973 }
4974 return true;
4975 }
4976
4977 default:
4978 return true;
4979 }
4980 }
4981
4982 public int filterEvent(QueuedEvent ev) {
4983 switch (ev.classType) {
4984 case RawInputEvent.CLASS_KEYBOARD:
4985 KeyEvent ke = (KeyEvent)ev.event;
4986 if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
4987 Log.w(TAG, "Dropping movement key during app switch: "
4988 + ke.getKeyCode() + ", action=" + ke.getAction());
4989 return FILTER_REMOVE;
4990 }
4991 return FILTER_ABORT;
4992 default:
4993 return FILTER_KEEP;
4994 }
4995 }
4996
4997 /**
4998 * Must be called with the main window manager lock held.
4999 */
5000 void setHoldScreenLocked(boolean holding) {
5001 boolean state = mHoldingScreen.isHeld();
5002 if (holding != state) {
5003 if (holding) {
5004 mHoldingScreen.acquire();
5005 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005006 mPolicy.screenOnStoppedLw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005007 mHoldingScreen.release();
5008 }
5009 }
5010 }
5011 };
5012
5013 public boolean detectSafeMode() {
5014 mSafeMode = mPolicy.detectSafeMode();
5015 return mSafeMode;
5016 }
5017
5018 public void systemReady() {
5019 mPolicy.systemReady();
5020 }
5021
5022 private final class InputDispatcherThread extends Thread {
5023 // Time to wait when there is nothing to do: 9999 seconds.
5024 static final int LONG_WAIT=9999*1000;
5025
5026 public InputDispatcherThread() {
5027 super("InputDispatcher");
5028 }
5029
5030 @Override
5031 public void run() {
5032 while (true) {
5033 try {
5034 process();
5035 } catch (Exception e) {
5036 Log.e(TAG, "Exception in input dispatcher", e);
5037 }
5038 }
5039 }
5040
5041 private void process() {
5042 android.os.Process.setThreadPriority(
5043 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
5044
5045 // The last key event we saw
5046 KeyEvent lastKey = null;
5047
5048 // Last keydown time for auto-repeating keys
5049 long lastKeyTime = SystemClock.uptimeMillis();
5050 long nextKeyTime = lastKeyTime+LONG_WAIT;
5051
5052 // How many successive repeats we generated
5053 int keyRepeatCount = 0;
5054
5055 // Need to report that configuration has changed?
5056 boolean configChanged = false;
5057
5058 while (true) {
5059 long curTime = SystemClock.uptimeMillis();
5060
5061 if (DEBUG_INPUT) Log.v(
5062 TAG, "Waiting for next key: now=" + curTime
5063 + ", repeat @ " + nextKeyTime);
5064
5065 // Retrieve next event, waiting only as long as the next
5066 // repeat timeout. If the configuration has changed, then
5067 // don't wait at all -- we'll report the change as soon as
5068 // we have processed all events.
5069 QueuedEvent ev = mQueue.getEvent(
5070 (int)((!configChanged && curTime < nextKeyTime)
5071 ? (nextKeyTime-curTime) : 0));
5072
5073 if (DEBUG_INPUT && ev != null) Log.v(
5074 TAG, "Event: type=" + ev.classType + " data=" + ev.event);
5075
5076 try {
5077 if (ev != null) {
5078 curTime = ev.when;
5079 int eventType;
5080 if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
5081 eventType = eventType((MotionEvent)ev.event);
5082 } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
5083 ev.classType == RawInputEvent.CLASS_TRACKBALL) {
5084 eventType = LocalPowerManager.BUTTON_EVENT;
5085 } else {
5086 eventType = LocalPowerManager.OTHER_EVENT;
5087 }
5088 mPowerManager.userActivity(curTime, false, eventType);
5089 switch (ev.classType) {
5090 case RawInputEvent.CLASS_KEYBOARD:
5091 KeyEvent ke = (KeyEvent)ev.event;
5092 if (ke.isDown()) {
5093 lastKey = ke;
5094 keyRepeatCount = 0;
5095 lastKeyTime = curTime;
5096 nextKeyTime = lastKeyTime
5097 + KEY_REPEAT_FIRST_DELAY;
5098 if (DEBUG_INPUT) Log.v(
5099 TAG, "Received key down: first repeat @ "
5100 + nextKeyTime);
5101 } else {
5102 lastKey = null;
5103 // Arbitrary long timeout.
5104 lastKeyTime = curTime;
5105 nextKeyTime = curTime + LONG_WAIT;
5106 if (DEBUG_INPUT) Log.v(
5107 TAG, "Received key up: ignore repeat @ "
5108 + nextKeyTime);
5109 }
5110 dispatchKey((KeyEvent)ev.event, 0, 0);
5111 mQueue.recycleEvent(ev);
5112 break;
5113 case RawInputEvent.CLASS_TOUCHSCREEN:
5114 //Log.i(TAG, "Read next event " + ev);
5115 dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
5116 break;
5117 case RawInputEvent.CLASS_TRACKBALL:
5118 dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
5119 break;
5120 case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
5121 configChanged = true;
5122 break;
5123 default:
5124 mQueue.recycleEvent(ev);
5125 break;
5126 }
5127
5128 } else if (configChanged) {
5129 configChanged = false;
5130 sendNewConfiguration();
5131
5132 } else if (lastKey != null) {
5133 curTime = SystemClock.uptimeMillis();
5134
5135 // Timeout occurred while key was down. If it is at or
5136 // past the key repeat time, dispatch the repeat.
5137 if (DEBUG_INPUT) Log.v(
5138 TAG, "Key timeout: repeat=" + nextKeyTime
5139 + ", now=" + curTime);
5140 if (curTime < nextKeyTime) {
5141 continue;
5142 }
5143
5144 lastKeyTime = nextKeyTime;
5145 nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
5146 keyRepeatCount++;
5147 if (DEBUG_INPUT) Log.v(
5148 TAG, "Key repeat: count=" + keyRepeatCount
5149 + ", next @ " + nextKeyTime);
The Android Open Source Project10592532009-03-18 17:39:46 -07005150 dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005151
5152 } else {
5153 curTime = SystemClock.uptimeMillis();
5154
5155 lastKeyTime = curTime;
5156 nextKeyTime = curTime + LONG_WAIT;
5157 }
5158
5159 } catch (Exception e) {
5160 Log.e(TAG,
5161 "Input thread received uncaught exception: " + e, e);
5162 }
5163 }
5164 }
5165 }
5166
5167 // -------------------------------------------------------------
5168 // Client Session State
5169 // -------------------------------------------------------------
5170
5171 private final class Session extends IWindowSession.Stub
5172 implements IBinder.DeathRecipient {
5173 final IInputMethodClient mClient;
5174 final IInputContext mInputContext;
5175 final int mUid;
5176 final int mPid;
5177 SurfaceSession mSurfaceSession;
5178 int mNumWindow = 0;
5179 boolean mClientDead = false;
5180
5181 /**
5182 * Current pointer move event being dispatched to client window... must
5183 * hold key lock to access.
5184 */
5185 QueuedEvent mPendingPointerMove;
5186 WindowState mPendingPointerWindow;
5187
5188 /**
5189 * Current trackball move event being dispatched to client window... must
5190 * hold key lock to access.
5191 */
5192 QueuedEvent mPendingTrackballMove;
5193 WindowState mPendingTrackballWindow;
5194
5195 public Session(IInputMethodClient client, IInputContext inputContext) {
5196 mClient = client;
5197 mInputContext = inputContext;
5198 mUid = Binder.getCallingUid();
5199 mPid = Binder.getCallingPid();
5200 synchronized (mWindowMap) {
5201 if (mInputMethodManager == null && mHaveInputMethods) {
5202 IBinder b = ServiceManager.getService(
5203 Context.INPUT_METHOD_SERVICE);
5204 mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
5205 }
5206 }
5207 long ident = Binder.clearCallingIdentity();
5208 try {
5209 // Note: it is safe to call in to the input method manager
5210 // here because we are not holding our lock.
5211 if (mInputMethodManager != null) {
5212 mInputMethodManager.addClient(client, inputContext,
5213 mUid, mPid);
5214 } else {
5215 client.setUsingInputMethod(false);
5216 }
5217 client.asBinder().linkToDeath(this, 0);
5218 } catch (RemoteException e) {
5219 // The caller has died, so we can just forget about this.
5220 try {
5221 if (mInputMethodManager != null) {
5222 mInputMethodManager.removeClient(client);
5223 }
5224 } catch (RemoteException ee) {
5225 }
5226 } finally {
5227 Binder.restoreCallingIdentity(ident);
5228 }
5229 }
5230
5231 @Override
5232 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5233 throws RemoteException {
5234 try {
5235 return super.onTransact(code, data, reply, flags);
5236 } catch (RuntimeException e) {
5237 // Log all 'real' exceptions thrown to the caller
5238 if (!(e instanceof SecurityException)) {
5239 Log.e(TAG, "Window Session Crash", e);
5240 }
5241 throw e;
5242 }
5243 }
5244
5245 public void binderDied() {
5246 // Note: it is safe to call in to the input method manager
5247 // here because we are not holding our lock.
5248 try {
5249 if (mInputMethodManager != null) {
5250 mInputMethodManager.removeClient(mClient);
5251 }
5252 } catch (RemoteException e) {
5253 }
5254 synchronized(mWindowMap) {
5255 mClientDead = true;
5256 killSessionLocked();
5257 }
5258 }
5259
5260 public int add(IWindow window, WindowManager.LayoutParams attrs,
5261 int viewVisibility, Rect outContentInsets) {
5262 return addWindow(this, window, attrs, viewVisibility, outContentInsets);
5263 }
5264
5265 public void remove(IWindow window) {
5266 removeWindow(this, window);
5267 }
5268
5269 public int relayout(IWindow window, WindowManager.LayoutParams attrs,
5270 int requestedWidth, int requestedHeight, int viewFlags,
5271 boolean insetsPending, Rect outFrame, Rect outContentInsets,
5272 Rect outVisibleInsets, Surface outSurface) {
5273 return relayoutWindow(this, window, attrs,
5274 requestedWidth, requestedHeight, viewFlags, insetsPending,
5275 outFrame, outContentInsets, outVisibleInsets, outSurface);
5276 }
5277
5278 public void setTransparentRegion(IWindow window, Region region) {
5279 setTransparentRegionWindow(this, window, region);
5280 }
5281
5282 public void setInsets(IWindow window, int touchableInsets,
5283 Rect contentInsets, Rect visibleInsets) {
5284 setInsetsWindow(this, window, touchableInsets, contentInsets,
5285 visibleInsets);
5286 }
5287
5288 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
5289 getWindowDisplayFrame(this, window, outDisplayFrame);
5290 }
5291
5292 public void finishDrawing(IWindow window) {
5293 if (localLOGV) Log.v(
5294 TAG, "IWindow finishDrawing called for " + window);
5295 finishDrawingWindow(this, window);
5296 }
5297
5298 public void finishKey(IWindow window) {
5299 if (localLOGV) Log.v(
5300 TAG, "IWindow finishKey called for " + window);
5301 mKeyWaiter.finishedKey(this, window, false,
5302 KeyWaiter.RETURN_NOTHING);
5303 }
5304
5305 public MotionEvent getPendingPointerMove(IWindow window) {
5306 if (localLOGV) Log.v(
5307 TAG, "IWindow getPendingMotionEvent called for " + window);
5308 return mKeyWaiter.finishedKey(this, window, false,
5309 KeyWaiter.RETURN_PENDING_POINTER);
5310 }
5311
5312 public MotionEvent getPendingTrackballMove(IWindow window) {
5313 if (localLOGV) Log.v(
5314 TAG, "IWindow getPendingMotionEvent called for " + window);
5315 return mKeyWaiter.finishedKey(this, window, false,
5316 KeyWaiter.RETURN_PENDING_TRACKBALL);
5317 }
5318
5319 public void setInTouchMode(boolean mode) {
5320 synchronized(mWindowMap) {
5321 mInTouchMode = mode;
5322 }
5323 }
5324
5325 public boolean getInTouchMode() {
5326 synchronized(mWindowMap) {
5327 return mInTouchMode;
5328 }
5329 }
5330
5331 public boolean performHapticFeedback(IWindow window, int effectId,
5332 boolean always) {
5333 synchronized(mWindowMap) {
5334 long ident = Binder.clearCallingIdentity();
5335 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005336 return mPolicy.performHapticFeedbackLw(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005337 windowForClientLocked(this, window), effectId, always);
5338 } finally {
5339 Binder.restoreCallingIdentity(ident);
5340 }
5341 }
5342 }
5343
5344 void windowAddedLocked() {
5345 if (mSurfaceSession == null) {
5346 if (localLOGV) Log.v(
5347 TAG, "First window added to " + this + ", creating SurfaceSession");
5348 mSurfaceSession = new SurfaceSession();
5349 mSessions.add(this);
5350 }
5351 mNumWindow++;
5352 }
5353
5354 void windowRemovedLocked() {
5355 mNumWindow--;
5356 killSessionLocked();
5357 }
5358
5359 void killSessionLocked() {
5360 if (mNumWindow <= 0 && mClientDead) {
5361 mSessions.remove(this);
5362 if (mSurfaceSession != null) {
5363 if (localLOGV) Log.v(
5364 TAG, "Last window removed from " + this
5365 + ", destroying " + mSurfaceSession);
5366 try {
5367 mSurfaceSession.kill();
5368 } catch (Exception e) {
5369 Log.w(TAG, "Exception thrown when killing surface session "
5370 + mSurfaceSession + " in session " + this
5371 + ": " + e.toString());
5372 }
5373 mSurfaceSession = null;
5374 }
5375 }
5376 }
5377
5378 void dump(PrintWriter pw, String prefix) {
5379 pw.println(prefix + this);
5380 pw.println(prefix + "mNumWindow=" + mNumWindow
5381 + " mClientDead=" + mClientDead
5382 + " mSurfaceSession=" + mSurfaceSession);
5383 pw.println(prefix + "mPendingPointerWindow=" + mPendingPointerWindow
5384 + " mPendingPointerMove=" + mPendingPointerMove);
5385 pw.println(prefix + "mPendingTrackballWindow=" + mPendingTrackballWindow
5386 + " mPendingTrackballMove=" + mPendingTrackballMove);
5387 }
5388
5389 @Override
5390 public String toString() {
5391 return "Session{"
5392 + Integer.toHexString(System.identityHashCode(this)) + "}";
5393 }
5394 }
5395
5396 // -------------------------------------------------------------
5397 // Client Window State
5398 // -------------------------------------------------------------
5399
5400 private final class WindowState implements WindowManagerPolicy.WindowState {
5401 final Session mSession;
5402 final IWindow mClient;
5403 WindowToken mToken;
The Android Open Source Project10592532009-03-18 17:39:46 -07005404 WindowToken mRootToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005405 AppWindowToken mAppToken;
5406 AppWindowToken mTargetAppToken;
5407 final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
5408 final DeathRecipient mDeathRecipient;
5409 final WindowState mAttachedWindow;
5410 final ArrayList mChildWindows = new ArrayList();
5411 final int mBaseLayer;
5412 final int mSubLayer;
5413 final boolean mLayoutAttached;
5414 final boolean mIsImWindow;
5415 int mViewVisibility;
5416 boolean mPolicyVisibility = true;
5417 boolean mPolicyVisibilityAfterAnim = true;
5418 boolean mAppFreezing;
5419 Surface mSurface;
5420 boolean mAttachedHidden; // is our parent window hidden?
5421 boolean mLastHidden; // was this window last hidden?
5422 int mRequestedWidth;
5423 int mRequestedHeight;
5424 int mLastRequestedWidth;
5425 int mLastRequestedHeight;
5426 int mReqXPos;
5427 int mReqYPos;
5428 int mLayer;
5429 int mAnimLayer;
5430 int mLastLayer;
5431 boolean mHaveFrame;
5432
5433 WindowState mNextOutsideTouch;
5434
5435 // Actual frame shown on-screen (may be modified by animation)
5436 final Rect mShownFrame = new Rect();
5437 final Rect mLastShownFrame = new Rect();
5438
5439 /**
5440 * Insets that determine the actually visible area
5441 */
5442 final Rect mVisibleInsets = new Rect();
5443 final Rect mLastVisibleInsets = new Rect();
5444 boolean mVisibleInsetsChanged;
5445
5446 /**
5447 * Insets that are covered by system windows
5448 */
5449 final Rect mContentInsets = new Rect();
5450 final Rect mLastContentInsets = new Rect();
5451 boolean mContentInsetsChanged;
5452
5453 /**
5454 * Set to true if we are waiting for this window to receive its
5455 * given internal insets before laying out other windows based on it.
5456 */
5457 boolean mGivenInsetsPending;
5458
5459 /**
5460 * These are the content insets that were given during layout for
5461 * this window, to be applied to windows behind it.
5462 */
5463 final Rect mGivenContentInsets = new Rect();
5464
5465 /**
5466 * These are the visible insets that were given during layout for
5467 * this window, to be applied to windows behind it.
5468 */
5469 final Rect mGivenVisibleInsets = new Rect();
5470
5471 /**
5472 * Flag indicating whether the touchable region should be adjusted by
5473 * the visible insets; if false the area outside the visible insets is
5474 * NOT touchable, so we must use those to adjust the frame during hit
5475 * tests.
5476 */
5477 int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
5478
5479 // Current transformation being applied.
5480 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
5481 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
5482 float mHScale=1, mVScale=1;
5483 float mLastHScale=1, mLastVScale=1;
5484 final Matrix mTmpMatrix = new Matrix();
5485
5486 // "Real" frame that the application sees.
5487 final Rect mFrame = new Rect();
5488 final Rect mLastFrame = new Rect();
5489
5490 final Rect mContainingFrame = new Rect();
5491 final Rect mDisplayFrame = new Rect();
5492 final Rect mContentFrame = new Rect();
5493 final Rect mVisibleFrame = new Rect();
5494
5495 float mShownAlpha = 1;
5496 float mAlpha = 1;
5497 float mLastAlpha = 1;
5498
5499 // Set to true if, when the window gets displayed, it should perform
5500 // an enter animation.
5501 boolean mEnterAnimationPending;
5502
5503 // Currently running animation.
5504 boolean mAnimating;
5505 boolean mLocalAnimating;
5506 Animation mAnimation;
5507 boolean mAnimationIsEntrance;
5508 boolean mHasTransformation;
5509 boolean mHasLocalTransformation;
5510 final Transformation mTransformation = new Transformation();
5511
5512 // This is set after IWindowSession.relayout() has been called at
5513 // least once for the window. It allows us to detect the situation
5514 // where we don't yet have a surface, but should have one soon, so
5515 // we can give the window focus before waiting for the relayout.
5516 boolean mRelayoutCalled;
5517
5518 // This is set after the Surface has been created but before the
5519 // window has been drawn. During this time the surface is hidden.
5520 boolean mDrawPending;
5521
5522 // This is set after the window has finished drawing for the first
5523 // time but before its surface is shown. The surface will be
5524 // displayed when the next layout is run.
5525 boolean mCommitDrawPending;
5526
5527 // This is set during the time after the window's drawing has been
5528 // committed, and before its surface is actually shown. It is used
5529 // to delay showing the surface until all windows in a token are ready
5530 // to be shown.
5531 boolean mReadyToShow;
5532
5533 // Set when the window has been shown in the screen the first time.
5534 boolean mHasDrawn;
5535
5536 // Currently running an exit animation?
5537 boolean mExiting;
5538
5539 // Currently on the mDestroySurface list?
5540 boolean mDestroying;
5541
5542 // Completely remove from window manager after exit animation?
5543 boolean mRemoveOnExit;
5544
5545 // Set when the orientation is changing and this window has not yet
5546 // been updated for the new orientation.
5547 boolean mOrientationChanging;
5548
5549 // Is this window now (or just being) removed?
5550 boolean mRemoved;
5551
5552 WindowState(Session s, IWindow c, WindowToken token,
5553 WindowState attachedWindow, WindowManager.LayoutParams a,
5554 int viewVisibility) {
5555 mSession = s;
5556 mClient = c;
5557 mToken = token;
5558 mAttrs.copyFrom(a);
5559 mViewVisibility = viewVisibility;
5560 DeathRecipient deathRecipient = new DeathRecipient();
5561 mAlpha = a.alpha;
5562 if (localLOGV) Log.v(
5563 TAG, "Window " + this + " client=" + c.asBinder()
5564 + " token=" + token + " (" + mAttrs.token + ")");
5565 try {
5566 c.asBinder().linkToDeath(deathRecipient, 0);
5567 } catch (RemoteException e) {
5568 mDeathRecipient = null;
5569 mAttachedWindow = null;
5570 mLayoutAttached = false;
5571 mIsImWindow = false;
5572 mBaseLayer = 0;
5573 mSubLayer = 0;
5574 return;
5575 }
5576 mDeathRecipient = deathRecipient;
5577
5578 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
5579 mAttrs.type <= LAST_SUB_WINDOW)) {
5580 // The multiplier here is to reserve space for multiple
5581 // windows in the same type layer.
5582 mBaseLayer = mPolicy.windowTypeToLayerLw(
5583 attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
5584 + TYPE_LAYER_OFFSET;
5585 mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
5586 mAttachedWindow = attachedWindow;
5587 mAttachedWindow.mChildWindows.add(this);
5588 mLayoutAttached = mAttrs.type !=
5589 WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
5590 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
5591 || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5592 } else {
5593 // The multiplier here is to reserve space for multiple
5594 // windows in the same type layer.
5595 mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
5596 * TYPE_LAYER_MULTIPLIER
5597 + TYPE_LAYER_OFFSET;
5598 mSubLayer = 0;
5599 mAttachedWindow = null;
5600 mLayoutAttached = false;
5601 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
5602 || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5603 }
5604
5605 WindowState appWin = this;
5606 while (appWin.mAttachedWindow != null) {
5607 appWin = mAttachedWindow;
5608 }
5609 WindowToken appToken = appWin.mToken;
5610 while (appToken.appWindowToken == null) {
5611 WindowToken parent = mTokenMap.get(appToken.token);
5612 if (parent == null || appToken == parent) {
5613 break;
5614 }
5615 appToken = parent;
5616 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005617 mRootToken = appToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005618 mAppToken = appToken.appWindowToken;
5619
5620 mSurface = null;
5621 mRequestedWidth = 0;
5622 mRequestedHeight = 0;
5623 mLastRequestedWidth = 0;
5624 mLastRequestedHeight = 0;
5625 mReqXPos = 0;
5626 mReqYPos = 0;
5627 mLayer = 0;
5628 mAnimLayer = 0;
5629 mLastLayer = 0;
5630 }
5631
5632 void attach() {
5633 if (localLOGV) Log.v(
5634 TAG, "Attaching " + this + " token=" + mToken
5635 + ", list=" + mToken.windows);
5636 mSession.windowAddedLocked();
5637 }
5638
5639 public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
5640 mHaveFrame = true;
5641
5642 final int pw = pf.right-pf.left;
5643 final int ph = pf.bottom-pf.top;
5644
5645 int w,h;
5646 if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
5647 w = mAttrs.width < 0 ? pw : mAttrs.width;
5648 h = mAttrs.height< 0 ? ph : mAttrs.height;
5649 } else {
5650 w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
5651 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
5652 }
5653
5654 final Rect container = mContainingFrame;
5655 container.set(pf);
5656
5657 final Rect display = mDisplayFrame;
5658 display.set(df);
5659
5660 final Rect content = mContentFrame;
5661 content.set(cf);
5662
5663 final Rect visible = mVisibleFrame;
5664 visible.set(vf);
5665
5666 final Rect frame = mFrame;
5667
5668 //System.out.println("In: w=" + w + " h=" + h + " container=" +
5669 // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
5670
5671 Gravity.apply(mAttrs.gravity, w, h, container,
5672 (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
5673 (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
5674
5675 //System.out.println("Out: " + mFrame);
5676
5677 // Now make sure the window fits in the overall display.
5678 Gravity.applyDisplay(mAttrs.gravity, df, frame);
5679
5680 // Make sure the content and visible frames are inside of the
5681 // final window frame.
5682 if (content.left < frame.left) content.left = frame.left;
5683 if (content.top < frame.top) content.top = frame.top;
5684 if (content.right > frame.right) content.right = frame.right;
5685 if (content.bottom > frame.bottom) content.bottom = frame.bottom;
5686 if (visible.left < frame.left) visible.left = frame.left;
5687 if (visible.top < frame.top) visible.top = frame.top;
5688 if (visible.right > frame.right) visible.right = frame.right;
5689 if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
5690
5691 final Rect contentInsets = mContentInsets;
5692 contentInsets.left = content.left-frame.left;
5693 contentInsets.top = content.top-frame.top;
5694 contentInsets.right = frame.right-content.right;
5695 contentInsets.bottom = frame.bottom-content.bottom;
5696
5697 final Rect visibleInsets = mVisibleInsets;
5698 visibleInsets.left = visible.left-frame.left;
5699 visibleInsets.top = visible.top-frame.top;
5700 visibleInsets.right = frame.right-visible.right;
5701 visibleInsets.bottom = frame.bottom-visible.bottom;
5702
5703 if (localLOGV) {
5704 //if ("com.google.android.youtube".equals(mAttrs.packageName)
5705 // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
5706 Log.v(TAG, "Resolving (mRequestedWidth="
5707 + mRequestedWidth + ", mRequestedheight="
5708 + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
5709 + "): frame=" + mFrame.toShortString()
5710 + " ci=" + contentInsets.toShortString()
5711 + " vi=" + visibleInsets.toShortString());
5712 //}
5713 }
5714 }
5715
5716 public Rect getFrameLw() {
5717 return mFrame;
5718 }
5719
5720 public Rect getShownFrameLw() {
5721 return mShownFrame;
5722 }
5723
5724 public Rect getDisplayFrameLw() {
5725 return mDisplayFrame;
5726 }
5727
5728 public Rect getContentFrameLw() {
5729 return mContentFrame;
5730 }
5731
5732 public Rect getVisibleFrameLw() {
5733 return mVisibleFrame;
5734 }
5735
5736 public boolean getGivenInsetsPendingLw() {
5737 return mGivenInsetsPending;
5738 }
5739
5740 public Rect getGivenContentInsetsLw() {
5741 return mGivenContentInsets;
5742 }
5743
5744 public Rect getGivenVisibleInsetsLw() {
5745 return mGivenVisibleInsets;
5746 }
5747
5748 public WindowManager.LayoutParams getAttrs() {
5749 return mAttrs;
5750 }
5751
5752 public int getSurfaceLayer() {
5753 return mLayer;
5754 }
5755
5756 public IApplicationToken getAppToken() {
5757 return mAppToken != null ? mAppToken.appToken : null;
5758 }
5759
5760 public boolean hasAppShownWindows() {
5761 return mAppToken != null ? mAppToken.firstWindowDrawn : false;
5762 }
5763
5764 public boolean hasAppStartingIcon() {
5765 return mAppToken != null ? (mAppToken.startingData != null) : false;
5766 }
5767
5768 public WindowManagerPolicy.WindowState getAppStartingWindow() {
5769 return mAppToken != null ? mAppToken.startingWindow : null;
5770 }
5771
5772 public void setAnimation(Animation anim) {
5773 if (localLOGV) Log.v(
5774 TAG, "Setting animation in " + this + ": " + anim);
5775 mAnimating = false;
5776 mLocalAnimating = false;
5777 mAnimation = anim;
5778 mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
5779 mAnimation.scaleCurrentDuration(mWindowAnimationScale);
5780 }
5781
5782 public void clearAnimation() {
5783 if (mAnimation != null) {
5784 mAnimating = true;
5785 mLocalAnimating = false;
5786 mAnimation = null;
5787 }
5788 }
5789
5790 Surface createSurfaceLocked() {
5791 if (mSurface == null) {
5792 mDrawPending = true;
5793 mCommitDrawPending = false;
5794 mReadyToShow = false;
5795 if (mAppToken != null) {
5796 mAppToken.allDrawn = false;
5797 }
5798
5799 int flags = 0;
5800 if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
5801 flags |= Surface.HARDWARE;
5802 } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
5803 flags |= Surface.GPU;
5804 } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
5805 flags |= Surface.PUSH_BUFFERS;
5806 }
5807
5808 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
5809 flags |= Surface.SECURE;
5810 }
5811 if (DEBUG_VISIBILITY) Log.v(
5812 TAG, "Creating surface in session "
5813 + mSession.mSurfaceSession + " window " + this
5814 + " w=" + mFrame.width()
5815 + " h=" + mFrame.height() + " format="
5816 + mAttrs.format + " flags=" + flags);
5817
5818 int w = mFrame.width();
5819 int h = mFrame.height();
5820 if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
5821 // for a scaled surface, we always want the requested
5822 // size.
5823 w = mRequestedWidth;
5824 h = mRequestedHeight;
5825 }
5826
5827 try {
5828 mSurface = new Surface(
5829 mSession.mSurfaceSession, mSession.mPid,
5830 0, w, h, mAttrs.format, flags);
5831 } catch (Surface.OutOfResourcesException e) {
5832 Log.w(TAG, "OutOfResourcesException creating surface");
5833 reclaimSomeSurfaceMemoryLocked(this, "create");
5834 return null;
5835 } catch (Exception e) {
5836 Log.e(TAG, "Exception creating surface", e);
5837 return null;
5838 }
5839
5840 if (localLOGV) Log.v(
5841 TAG, "Got surface: " + mSurface
5842 + ", set left=" + mFrame.left + " top=" + mFrame.top
5843 + ", animLayer=" + mAnimLayer);
5844 if (SHOW_TRANSACTIONS) {
5845 Log.i(TAG, ">>> OPEN TRANSACTION");
5846 Log.i(TAG, " SURFACE " + mSurface + ": CREATE ("
5847 + mAttrs.getTitle() + ") pos=(" +
5848 mFrame.left + "," + mFrame.top + ") (" +
5849 mFrame.width() + "x" + mFrame.height() + "), layer=" +
5850 mAnimLayer + " HIDE");
5851 }
5852 Surface.openTransaction();
5853 try {
5854 try {
5855 mSurface.setPosition(mFrame.left, mFrame.top);
5856 mSurface.setLayer(mAnimLayer);
5857 mSurface.hide();
5858 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
5859 mSurface.setFlags(Surface.SURFACE_DITHER,
5860 Surface.SURFACE_DITHER);
5861 }
5862 } catch (RuntimeException e) {
5863 Log.w(TAG, "Error creating surface in " + w, e);
5864 reclaimSomeSurfaceMemoryLocked(this, "create-init");
5865 }
5866 mLastHidden = true;
5867 } finally {
5868 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
5869 Surface.closeTransaction();
5870 }
5871 if (localLOGV) Log.v(
5872 TAG, "Created surface " + this);
5873 }
5874 return mSurface;
5875 }
5876
5877 void destroySurfaceLocked() {
5878 // Window is no longer on-screen, so can no longer receive
5879 // key events... if we were waiting for it to finish
5880 // handling a key event, the wait is over!
5881 mKeyWaiter.finishedKey(mSession, mClient, true,
5882 KeyWaiter.RETURN_NOTHING);
5883 mKeyWaiter.releasePendingPointerLocked(mSession);
5884 mKeyWaiter.releasePendingTrackballLocked(mSession);
5885
5886 if (mAppToken != null && this == mAppToken.startingWindow) {
5887 mAppToken.startingDisplayed = false;
5888 }
5889
5890 if (localLOGV) Log.v(
5891 TAG, "Window " + this
5892 + " destroying surface " + mSurface + ", session " + mSession);
5893 if (mSurface != null) {
5894 try {
5895 if (SHOW_TRANSACTIONS) {
5896 RuntimeException ex = new RuntimeException();
5897 ex.fillInStackTrace();
5898 Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
5899 + mAttrs.getTitle() + ")", ex);
5900 }
5901 mSurface.clear();
5902 } catch (RuntimeException e) {
5903 Log.w(TAG, "Exception thrown when destroying Window " + this
5904 + " surface " + mSurface + " session " + mSession
5905 + ": " + e.toString());
5906 }
5907 mSurface = null;
5908 mDrawPending = false;
5909 mCommitDrawPending = false;
5910 mReadyToShow = false;
5911
5912 int i = mChildWindows.size();
5913 while (i > 0) {
5914 i--;
5915 WindowState c = (WindowState)mChildWindows.get(i);
5916 c.mAttachedHidden = true;
5917 }
5918 }
5919 }
5920
5921 boolean finishDrawingLocked() {
5922 if (mDrawPending) {
5923 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
5924 TAG, "finishDrawingLocked: " + mSurface);
5925 mCommitDrawPending = true;
5926 mDrawPending = false;
5927 return true;
5928 }
5929 return false;
5930 }
5931
5932 // This must be called while inside a transaction.
5933 void commitFinishDrawingLocked(long currentTime) {
5934 //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
5935 if (!mCommitDrawPending) {
5936 return;
5937 }
5938 mCommitDrawPending = false;
5939 mReadyToShow = true;
5940 final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING;
5941 final AppWindowToken atoken = mAppToken;
5942 if (atoken == null || atoken.allDrawn || starting) {
5943 performShowLocked();
5944 }
5945 }
5946
5947 // This must be called while inside a transaction.
5948 boolean performShowLocked() {
5949 if (DEBUG_VISIBILITY) {
5950 RuntimeException e = new RuntimeException();
5951 e.fillInStackTrace();
5952 Log.v(TAG, "performShow on " + this
5953 + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
5954 + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
5955 }
5956 if (mReadyToShow && isReadyForDisplay()) {
5957 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i(
5958 TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)");
5959 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this
5960 + " during animation: policyVis=" + mPolicyVisibility
5961 + " attHidden=" + mAttachedHidden
5962 + " tok.hiddenRequested="
5963 + (mAppToken != null ? mAppToken.hiddenRequested : false)
5964 + " tok.idden="
5965 + (mAppToken != null ? mAppToken.hidden : false)
5966 + " animating=" + mAnimating
5967 + " tok animating="
5968 + (mAppToken != null ? mAppToken.animating : false));
5969 if (!showSurfaceRobustlyLocked(this)) {
5970 return false;
5971 }
5972 mLastAlpha = -1;
5973 mHasDrawn = true;
5974 mLastHidden = false;
5975 mReadyToShow = false;
5976 enableScreenIfNeededLocked();
5977
5978 applyEnterAnimationLocked(this);
5979
5980 int i = mChildWindows.size();
5981 while (i > 0) {
5982 i--;
5983 WindowState c = (WindowState)mChildWindows.get(i);
5984 if (c.mSurface != null && c.mAttachedHidden) {
5985 c.mAttachedHidden = false;
5986 c.performShowLocked();
5987 }
5988 }
5989
5990 if (mAttrs.type != TYPE_APPLICATION_STARTING
5991 && mAppToken != null) {
5992 mAppToken.firstWindowDrawn = true;
5993 if (mAnimation == null && mAppToken.startingData != null) {
5994 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
5995 + mToken
5996 + ": first real window is shown, no animation");
5997 mFinishedStarting.add(mAppToken);
5998 mH.sendEmptyMessage(H.FINISHED_STARTING);
5999 }
6000 mAppToken.updateReportedVisibilityLocked();
6001 }
6002 }
6003 return true;
6004 }
6005
6006 // This must be called while inside a transaction. Returns true if
6007 // there is more animation to run.
6008 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6009 if (!mDisplayFrozen) {
6010 // We will run animations as long as the display isn't frozen.
6011
6012 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
6013 mHasTransformation = true;
6014 mHasLocalTransformation = true;
6015 if (!mLocalAnimating) {
6016 if (DEBUG_ANIM) Log.v(
6017 TAG, "Starting animation in " + this +
6018 " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
6019 " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
6020 mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
6021 mAnimation.setStartTime(currentTime);
6022 mLocalAnimating = true;
6023 mAnimating = true;
6024 }
6025 mTransformation.clear();
6026 final boolean more = mAnimation.getTransformation(
6027 currentTime, mTransformation);
6028 if (DEBUG_ANIM) Log.v(
6029 TAG, "Stepped animation in " + this +
6030 ": more=" + more + ", xform=" + mTransformation);
6031 if (more) {
6032 // we're not done!
6033 return true;
6034 }
6035 if (DEBUG_ANIM) Log.v(
6036 TAG, "Finished animation in " + this +
6037 " @ " + currentTime);
6038 mAnimation = null;
6039 //WindowManagerService.this.dump();
6040 }
6041 mHasLocalTransformation = false;
6042 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
6043 && mAppToken.hasTransformation) {
6044 // When our app token is animating, we kind-of pretend like
6045 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
6046 // part of this check means that we will only do this if
6047 // our window is not currently exiting, or it is not
6048 // locally animating itself. The idea being that one that
6049 // is exiting and doing a local animation should be removed
6050 // once that animation is done.
6051 mAnimating = true;
6052 mHasTransformation = true;
6053 mTransformation.clear();
6054 return false;
6055 } else if (mHasTransformation) {
6056 // Little trick to get through the path below to act like
6057 // we have finished an animation.
6058 mAnimating = true;
6059 } else if (isAnimating()) {
6060 mAnimating = true;
6061 }
6062 } else if (mAnimation != null) {
6063 // If the display is frozen, and there is a pending animation,
6064 // clear it and make sure we run the cleanup code.
6065 mAnimating = true;
6066 mLocalAnimating = true;
6067 mAnimation = null;
6068 }
6069
6070 if (!mAnimating && !mLocalAnimating) {
6071 return false;
6072 }
6073
6074 if (DEBUG_ANIM) Log.v(
6075 TAG, "Animation done in " + this + ": exiting=" + mExiting
6076 + ", reportedVisible="
6077 + (mAppToken != null ? mAppToken.reportedVisible : false));
6078
6079 mAnimating = false;
6080 mLocalAnimating = false;
6081 mAnimation = null;
6082 mAnimLayer = mLayer;
6083 if (mIsImWindow) {
6084 mAnimLayer += mInputMethodAnimLayerAdjustment;
6085 }
6086 if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
6087 + " anim layer: " + mAnimLayer);
6088 mHasTransformation = false;
6089 mHasLocalTransformation = false;
6090 mPolicyVisibility = mPolicyVisibilityAfterAnim;
6091 mTransformation.clear();
6092 if (mHasDrawn
6093 && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
6094 && mAppToken != null
6095 && mAppToken.firstWindowDrawn
6096 && mAppToken.startingData != null) {
6097 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6098 + mToken + ": first real window done animating");
6099 mFinishedStarting.add(mAppToken);
6100 mH.sendEmptyMessage(H.FINISHED_STARTING);
6101 }
6102
6103 finishExit();
6104
6105 if (mAppToken != null) {
6106 mAppToken.updateReportedVisibilityLocked();
6107 }
6108
6109 return false;
6110 }
6111
6112 void finishExit() {
6113 if (DEBUG_ANIM) Log.v(
6114 TAG, "finishExit in " + this
6115 + ": exiting=" + mExiting
6116 + " remove=" + mRemoveOnExit
6117 + " windowAnimating=" + isWindowAnimating());
6118
6119 final int N = mChildWindows.size();
6120 for (int i=0; i<N; i++) {
6121 ((WindowState)mChildWindows.get(i)).finishExit();
6122 }
6123
6124 if (!mExiting) {
6125 return;
6126 }
6127
6128 if (isWindowAnimating()) {
6129 return;
6130 }
6131
6132 if (localLOGV) Log.v(
6133 TAG, "Exit animation finished in " + this
6134 + ": remove=" + mRemoveOnExit);
6135 if (mSurface != null) {
6136 mDestroySurface.add(this);
6137 mDestroying = true;
6138 if (SHOW_TRANSACTIONS) Log.i(
6139 TAG, " SURFACE " + mSurface + ": HIDE (finishExit)");
6140 try {
6141 mSurface.hide();
6142 } catch (RuntimeException e) {
6143 Log.w(TAG, "Error hiding surface in " + this, e);
6144 }
6145 mLastHidden = true;
6146 mKeyWaiter.releasePendingPointerLocked(mSession);
6147 }
6148 mExiting = false;
6149 if (mRemoveOnExit) {
6150 mPendingRemove.add(this);
6151 mRemoveOnExit = false;
6152 }
6153 }
6154
6155 boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
6156 if (dsdx < .99999f || dsdx > 1.00001f) return false;
6157 if (dtdy < .99999f || dtdy > 1.00001f) return false;
6158 if (dtdx < -.000001f || dtdx > .000001f) return false;
6159 if (dsdy < -.000001f || dsdy > .000001f) return false;
6160 return true;
6161 }
6162
6163 void computeShownFrameLocked() {
6164 final boolean selfTransformation = mHasLocalTransformation;
6165 Transformation attachedTransformation =
6166 (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
6167 ? mAttachedWindow.mTransformation : null;
6168 Transformation appTransformation =
6169 (mAppToken != null && mAppToken.hasTransformation)
6170 ? mAppToken.transformation : null;
6171 if (selfTransformation || attachedTransformation != null
6172 || appTransformation != null) {
6173 // cache often used attributes locally
6174 final Rect frame = mFrame;
6175 final float tmpFloats[] = mTmpFloats;
6176 final Matrix tmpMatrix = mTmpMatrix;
6177
6178 // Compute the desired transformation.
6179 tmpMatrix.setTranslate(frame.left, frame.top);
6180 if (selfTransformation) {
6181 tmpMatrix.preConcat(mTransformation.getMatrix());
6182 }
6183 if (attachedTransformation != null) {
6184 tmpMatrix.preConcat(attachedTransformation.getMatrix());
6185 }
6186 if (appTransformation != null) {
6187 tmpMatrix.preConcat(appTransformation.getMatrix());
6188 }
6189
6190 // "convert" it into SurfaceFlinger's format
6191 // (a 2x2 matrix + an offset)
6192 // Here we must not transform the position of the surface
6193 // since it is already included in the transformation.
6194 //Log.i(TAG, "Transform: " + matrix);
6195
6196 tmpMatrix.getValues(tmpFloats);
6197 mDsDx = tmpFloats[Matrix.MSCALE_X];
6198 mDtDx = tmpFloats[Matrix.MSKEW_X];
6199 mDsDy = tmpFloats[Matrix.MSKEW_Y];
6200 mDtDy = tmpFloats[Matrix.MSCALE_Y];
6201 int x = (int)tmpFloats[Matrix.MTRANS_X];
6202 int y = (int)tmpFloats[Matrix.MTRANS_Y];
6203 int w = frame.width();
6204 int h = frame.height();
6205 mShownFrame.set(x, y, x+w, y+h);
6206
6207 // Now set the alpha... but because our current hardware
6208 // can't do alpha transformation on a non-opaque surface,
6209 // turn it off if we are running an animation that is also
6210 // transforming since it is more important to have that
6211 // animation be smooth.
6212 mShownAlpha = mAlpha;
6213 if (!mLimitedAlphaCompositing
6214 || (!PixelFormat.formatHasAlpha(mAttrs.format)
6215 || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
6216 && x == frame.left && y == frame.top))) {
6217 //Log.i(TAG, "Applying alpha transform");
6218 if (selfTransformation) {
6219 mShownAlpha *= mTransformation.getAlpha();
6220 }
6221 if (attachedTransformation != null) {
6222 mShownAlpha *= attachedTransformation.getAlpha();
6223 }
6224 if (appTransformation != null) {
6225 mShownAlpha *= appTransformation.getAlpha();
6226 }
6227 } else {
6228 //Log.i(TAG, "Not applying alpha transform");
6229 }
6230
6231 if (localLOGV) Log.v(
6232 TAG, "Continuing animation in " + this +
6233 ": " + mShownFrame +
6234 ", alpha=" + mTransformation.getAlpha());
6235 return;
6236 }
6237
6238 mShownFrame.set(mFrame);
6239 mShownAlpha = mAlpha;
6240 mDsDx = 1;
6241 mDtDx = 0;
6242 mDsDy = 0;
6243 mDtDy = 1;
6244 }
6245
6246 /**
6247 * Is this window visible? It is not visible if there is no
6248 * surface, or we are in the process of running an exit animation
6249 * that will remove the surface, or its app token has been hidden.
6250 */
6251 public boolean isVisibleLw() {
6252 final AppWindowToken atoken = mAppToken;
6253 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6254 && (atoken == null || !atoken.hiddenRequested)
6255 && !mExiting && !mDestroying;
6256 }
6257
6258 /**
6259 * Is this window visible, ignoring its app token? It is not visible
6260 * if there is no surface, or we are in the process of running an exit animation
6261 * that will remove the surface.
6262 */
6263 public boolean isWinVisibleLw() {
6264 final AppWindowToken atoken = mAppToken;
6265 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6266 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
6267 && !mExiting && !mDestroying;
6268 }
6269
6270 /**
6271 * The same as isVisible(), but follows the current hidden state of
6272 * the associated app token, not the pending requested hidden state.
6273 */
6274 boolean isVisibleNow() {
6275 return mSurface != null && mPolicyVisibility && !mAttachedHidden
The Android Open Source Project10592532009-03-18 17:39:46 -07006276 && !mRootToken.hidden && !mExiting && !mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006277 }
6278
6279 /**
6280 * Same as isVisible(), but we also count it as visible between the
6281 * call to IWindowSession.add() and the first relayout().
6282 */
6283 boolean isVisibleOrAdding() {
6284 final AppWindowToken atoken = mAppToken;
6285 return (mSurface != null
6286 || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
6287 && mPolicyVisibility && !mAttachedHidden
6288 && (atoken == null || !atoken.hiddenRequested)
6289 && !mExiting && !mDestroying;
6290 }
6291
6292 /**
6293 * Is this window currently on-screen? It is on-screen either if it
6294 * is visible or it is currently running an animation before no longer
6295 * being visible.
6296 */
6297 boolean isOnScreen() {
6298 final AppWindowToken atoken = mAppToken;
6299 if (atoken != null) {
6300 return mSurface != null && mPolicyVisibility && !mDestroying
6301 && ((!mAttachedHidden && !atoken.hiddenRequested)
6302 || mAnimating || atoken.animating);
6303 } else {
6304 return mSurface != null && mPolicyVisibility && !mDestroying
6305 && (!mAttachedHidden || mAnimating);
6306 }
6307 }
6308
6309 /**
6310 * Like isOnScreen(), but we don't return true if the window is part
6311 * of a transition that has not yet been started.
6312 */
6313 boolean isReadyForDisplay() {
6314 final AppWindowToken atoken = mAppToken;
6315 final boolean animating = atoken != null ? atoken.animating : false;
6316 return mSurface != null && mPolicyVisibility && !mDestroying
The Android Open Source Project10592532009-03-18 17:39:46 -07006317 && ((!mAttachedHidden && !mRootToken.hidden)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006318 || mAnimating || animating);
6319 }
6320
6321 /** Is the window or its container currently animating? */
6322 boolean isAnimating() {
6323 final WindowState attached = mAttachedWindow;
6324 final AppWindowToken atoken = mAppToken;
6325 return mAnimation != null
6326 || (attached != null && attached.mAnimation != null)
6327 || (atoken != null &&
6328 (atoken.animation != null
6329 || atoken.inPendingTransaction));
6330 }
6331
6332 /** Is this window currently animating? */
6333 boolean isWindowAnimating() {
6334 return mAnimation != null;
6335 }
6336
6337 /**
6338 * Like isOnScreen, but returns false if the surface hasn't yet
6339 * been drawn.
6340 */
6341 public boolean isDisplayedLw() {
6342 final AppWindowToken atoken = mAppToken;
6343 return mSurface != null && mPolicyVisibility && !mDestroying
6344 && !mDrawPending && !mCommitDrawPending
6345 && ((!mAttachedHidden &&
6346 (atoken == null || !atoken.hiddenRequested))
6347 || mAnimating);
6348 }
6349
6350 public boolean fillsScreenLw(int screenWidth, int screenHeight,
6351 boolean shownFrame, boolean onlyOpaque) {
6352 if (mSurface == null) {
6353 return false;
6354 }
6355 if (mAppToken != null && !mAppToken.appFullscreen) {
6356 return false;
6357 }
6358 if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
6359 return false;
6360 }
6361 final Rect frame = shownFrame ? mShownFrame : mFrame;
6362 if (frame.left <= 0 && frame.top <= 0
6363 && frame.right >= screenWidth
6364 && frame.bottom >= screenHeight) {
6365 return true;
6366 }
6367 return false;
6368 }
6369
6370 boolean isFullscreenOpaque(int screenWidth, int screenHeight) {
6371 if (mAttrs.format != PixelFormat.OPAQUE || mSurface == null
6372 || mAnimation != null || mDrawPending || mCommitDrawPending) {
6373 return false;
6374 }
6375 if (mFrame.left <= 0 && mFrame.top <= 0 &&
6376 mFrame.right >= screenWidth && mFrame.bottom >= screenHeight) {
6377 return true;
6378 }
6379 return false;
6380 }
6381
6382 void removeLocked() {
6383 if (mAttachedWindow != null) {
6384 mAttachedWindow.mChildWindows.remove(this);
6385 }
6386 destroySurfaceLocked();
6387 mSession.windowRemovedLocked();
6388 try {
6389 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
6390 } catch (RuntimeException e) {
6391 // Ignore if it has already been removed (usually because
6392 // we are doing this as part of processing a death note.)
6393 }
6394 }
6395
6396 private class DeathRecipient implements IBinder.DeathRecipient {
6397 public void binderDied() {
6398 try {
6399 synchronized(mWindowMap) {
6400 WindowState win = windowForClientLocked(mSession, mClient);
6401 Log.i(TAG, "WIN DEATH: " + win);
6402 if (win != null) {
6403 removeWindowLocked(mSession, win);
6404 }
6405 }
6406 } catch (IllegalArgumentException ex) {
6407 // This will happen if the window has already been
6408 // removed.
6409 }
6410 }
6411 }
6412
6413 /** Returns true if this window desires key events. */
6414 public final boolean canReceiveKeys() {
6415 return isVisibleOrAdding()
6416 && (mViewVisibility == View.VISIBLE)
6417 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
6418 }
6419
6420 public boolean hasDrawnLw() {
6421 return mHasDrawn;
6422 }
6423
6424 public boolean showLw(boolean doAnimation) {
6425 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
6426 mPolicyVisibility = true;
6427 mPolicyVisibilityAfterAnim = true;
6428 if (doAnimation) {
6429 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
6430 }
6431 requestAnimationLocked(0);
6432 return true;
6433 }
6434 return false;
6435 }
6436
6437 public boolean hideLw(boolean doAnimation) {
6438 boolean current = doAnimation ? mPolicyVisibilityAfterAnim
6439 : mPolicyVisibility;
6440 if (current) {
6441 if (doAnimation) {
6442 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
6443 if (mAnimation == null) {
6444 doAnimation = false;
6445 }
6446 }
6447 if (doAnimation) {
6448 mPolicyVisibilityAfterAnim = false;
6449 } else {
6450 mPolicyVisibilityAfterAnim = false;
6451 mPolicyVisibility = false;
6452 }
6453 requestAnimationLocked(0);
6454 return true;
6455 }
6456 return false;
6457 }
6458
6459 void dump(PrintWriter pw, String prefix) {
6460 pw.println(prefix + this);
6461 pw.println(prefix + "mSession=" + mSession
6462 + " mClient=" + mClient.asBinder());
6463 pw.println(prefix + "mAttrs=" + mAttrs);
6464 pw.println(prefix + "mAttachedWindow=" + mAttachedWindow
6465 + " mLayoutAttached=" + mLayoutAttached
6466 + " mIsImWindow=" + mIsImWindow);
6467 pw.println(prefix + "mBaseLayer=" + mBaseLayer
6468 + " mSubLayer=" + mSubLayer
6469 + " mAnimLayer=" + mLayer + "+"
6470 + (mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
6471 : (mAppToken != null ? mAppToken.animLayerAdjustment : 0))
6472 + "=" + mAnimLayer
6473 + " mLastLayer=" + mLastLayer);
6474 pw.println(prefix + "mSurface=" + mSurface);
6475 pw.println(prefix + "mToken=" + mToken);
The Android Open Source Project10592532009-03-18 17:39:46 -07006476 pw.println(prefix + "mRootToken=" + mRootToken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 pw.println(prefix + "mAppToken=" + mAppToken);
6478 pw.println(prefix + "mTargetAppToken=" + mTargetAppToken);
6479 pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility)
6480 + " mPolicyVisibility=" + mPolicyVisibility
6481 + " (after=" + mPolicyVisibilityAfterAnim
6482 + ") mAttachedHidden=" + mAttachedHidden
6483 + " mLastHidden=" + mLastHidden
6484 + " mHaveFrame=" + mHaveFrame);
6485 pw.println(prefix + "Requested w=" + mRequestedWidth + " h=" + mRequestedHeight
6486 + " x=" + mReqXPos + " y=" + mReqYPos);
6487 pw.println(prefix + "mGivenContentInsets=" + mGivenContentInsets.toShortString()
6488 + " mGivenVisibleInsets=" + mGivenVisibleInsets.toShortString()
6489 + " mTouchableInsets=" + mTouchableInsets
6490 + " pending=" + mGivenInsetsPending);
6491 pw.println(prefix + "mShownFrame=" + mShownFrame.toShortString()
6492 + " last=" + mLastShownFrame.toShortString());
6493 pw.println(prefix + "mFrame=" + mFrame.toShortString()
6494 + " last=" + mLastFrame.toShortString());
6495 pw.println(prefix + "mContainingFrame=" + mContainingFrame.toShortString()
6496 + " mDisplayFrame=" + mDisplayFrame.toShortString());
6497 pw.println(prefix + "mContentFrame=" + mContentFrame.toShortString()
6498 + " mVisibleFrame=" + mVisibleFrame.toShortString());
6499 pw.println(prefix + "mContentInsets=" + mContentInsets.toShortString()
6500 + " last=" + mLastContentInsets.toShortString()
6501 + " mVisibleInsets=" + mVisibleInsets.toShortString()
6502 + " last=" + mLastVisibleInsets.toShortString());
6503 pw.println(prefix + "mShownAlpha=" + mShownAlpha
6504 + " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha);
6505 pw.println(prefix + "mAnimating=" + mAnimating
6506 + " mLocalAnimating=" + mLocalAnimating
6507 + " mAnimationIsEntrance=" + mAnimationIsEntrance
6508 + " mAnimation=" + mAnimation);
6509 pw.println(prefix + "XForm: has=" + mHasTransformation
6510 + " " + mTransformation.toShortString());
6511 pw.println(prefix + "mDrawPending=" + mDrawPending
6512 + " mCommitDrawPending=" + mCommitDrawPending
6513 + " mReadyToShow=" + mReadyToShow
6514 + " mHasDrawn=" + mHasDrawn);
6515 pw.println(prefix + "mExiting=" + mExiting
6516 + " mRemoveOnExit=" + mRemoveOnExit
6517 + " mDestroying=" + mDestroying
6518 + " mRemoved=" + mRemoved);
6519 pw.println(prefix + "mOrientationChanging=" + mOrientationChanging
6520 + " mAppFreezing=" + mAppFreezing);
6521 }
6522
6523 @Override
6524 public String toString() {
6525 return "Window{"
6526 + Integer.toHexString(System.identityHashCode(this))
6527 + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
6528 }
6529 }
6530
6531 // -------------------------------------------------------------
6532 // Window Token State
6533 // -------------------------------------------------------------
6534
6535 class WindowToken {
6536 // The actual token.
6537 final IBinder token;
6538
6539 // The type of window this token is for, as per WindowManager.LayoutParams.
6540 final int windowType;
6541
6542 // Set if this token was explicitly added by a client, so should
6543 // not be removed when all windows are removed.
6544 final boolean explicit;
6545
6546 // If this is an AppWindowToken, this is non-null.
6547 AppWindowToken appWindowToken;
6548
6549 // All of the windows associated with this token.
6550 final ArrayList<WindowState> windows = new ArrayList<WindowState>();
6551
6552 // Is key dispatching paused for this token?
6553 boolean paused = false;
6554
6555 // Should this token's windows be hidden?
6556 boolean hidden;
6557
6558 // Temporary for finding which tokens no longer have visible windows.
6559 boolean hasVisible;
6560
6561 WindowToken(IBinder _token, int type, boolean _explicit) {
6562 token = _token;
6563 windowType = type;
6564 explicit = _explicit;
6565 }
6566
6567 void dump(PrintWriter pw, String prefix) {
6568 pw.println(prefix + this);
6569 pw.println(prefix + "token=" + token);
6570 pw.println(prefix + "windows=" + windows);
6571 pw.println(prefix + "windowType=" + windowType + " hidden=" + hidden
6572 + " hasVisible=" + hasVisible);
6573 }
6574
6575 @Override
6576 public String toString() {
6577 return "WindowToken{"
6578 + Integer.toHexString(System.identityHashCode(this))
6579 + " token=" + token + "}";
6580 }
6581 };
6582
6583 class AppWindowToken extends WindowToken {
6584 // Non-null only for application tokens.
6585 final IApplicationToken appToken;
6586
6587 // All of the windows and child windows that are included in this
6588 // application token. Note this list is NOT sorted!
6589 final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
6590
6591 int groupId = -1;
6592 boolean appFullscreen;
6593 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
6594
6595 // These are used for determining when all windows associated with
6596 // an activity have been drawn, so they can be made visible together
6597 // at the same time.
6598 int lastTransactionSequence = mTransactionSequence-1;
6599 int numInterestingWindows;
6600 int numDrawnWindows;
6601 boolean inPendingTransaction;
6602 boolean allDrawn;
6603
6604 // Is this token going to be hidden in a little while? If so, it
6605 // won't be taken into account for setting the screen orientation.
6606 boolean willBeHidden;
6607
6608 // Is this window's surface needed? This is almost like hidden, except
6609 // it will sometimes be true a little earlier: when the token has
6610 // been shown, but is still waiting for its app transition to execute
6611 // before making its windows shown.
6612 boolean hiddenRequested;
6613
6614 // Have we told the window clients to hide themselves?
6615 boolean clientHidden;
6616
6617 // Last visibility state we reported to the app token.
6618 boolean reportedVisible;
6619
6620 // Set to true when the token has been removed from the window mgr.
6621 boolean removed;
6622
6623 // Have we been asked to have this token keep the screen frozen?
6624 boolean freezingScreen;
6625
6626 boolean animating;
6627 Animation animation;
6628 boolean hasTransformation;
6629 final Transformation transformation = new Transformation();
6630
6631 // Offset to the window of all layers in the token, for use by
6632 // AppWindowToken animations.
6633 int animLayerAdjustment;
6634
6635 // Information about an application starting window if displayed.
6636 StartingData startingData;
6637 WindowState startingWindow;
6638 View startingView;
6639 boolean startingDisplayed;
6640 boolean startingMoved;
6641 boolean firstWindowDrawn;
6642
6643 AppWindowToken(IApplicationToken _token) {
6644 super(_token.asBinder(),
6645 WindowManager.LayoutParams.TYPE_APPLICATION, true);
6646 appWindowToken = this;
6647 appToken = _token;
6648 }
6649
6650 public void setAnimation(Animation anim) {
6651 if (localLOGV) Log.v(
6652 TAG, "Setting animation in " + this + ": " + anim);
6653 animation = anim;
6654 animating = false;
6655 anim.restrictDuration(MAX_ANIMATION_DURATION);
6656 anim.scaleCurrentDuration(mTransitionAnimationScale);
6657 int zorder = anim.getZAdjustment();
6658 int adj = 0;
6659 if (zorder == Animation.ZORDER_TOP) {
6660 adj = TYPE_LAYER_OFFSET;
6661 } else if (zorder == Animation.ZORDER_BOTTOM) {
6662 adj = -TYPE_LAYER_OFFSET;
6663 }
6664
6665 if (animLayerAdjustment != adj) {
6666 animLayerAdjustment = adj;
6667 updateLayers();
6668 }
6669 }
6670
6671 public void setDummyAnimation() {
6672 if (animation == null) {
6673 if (localLOGV) Log.v(
6674 TAG, "Setting dummy animation in " + this);
6675 animation = sDummyAnimation;
6676 }
6677 }
6678
6679 public void clearAnimation() {
6680 if (animation != null) {
6681 animation = null;
6682 animating = true;
6683 }
6684 }
6685
6686 void updateLayers() {
6687 final int N = allAppWindows.size();
6688 final int adj = animLayerAdjustment;
6689 for (int i=0; i<N; i++) {
6690 WindowState w = allAppWindows.get(i);
6691 w.mAnimLayer = w.mLayer + adj;
6692 if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
6693 + w.mAnimLayer);
6694 if (w == mInputMethodTarget) {
6695 setInputMethodAnimLayerAdjustment(adj);
6696 }
6697 }
6698 }
6699
6700 void sendAppVisibilityToClients() {
6701 final int N = allAppWindows.size();
6702 for (int i=0; i<N; i++) {
6703 WindowState win = allAppWindows.get(i);
6704 if (win == startingWindow && clientHidden) {
6705 // Don't hide the starting window.
6706 continue;
6707 }
6708 try {
6709 if (DEBUG_VISIBILITY) Log.v(TAG,
6710 "Setting visibility of " + win + ": " + (!clientHidden));
6711 win.mClient.dispatchAppVisibility(!clientHidden);
6712 } catch (RemoteException e) {
6713 }
6714 }
6715 }
6716
6717 void showAllWindowsLocked() {
6718 final int NW = allAppWindows.size();
6719 for (int i=0; i<NW; i++) {
6720 WindowState w = allAppWindows.get(i);
6721 if (DEBUG_VISIBILITY) Log.v(TAG,
6722 "performing show on: " + w);
6723 w.performShowLocked();
6724 }
6725 }
6726
6727 // This must be called while inside a transaction.
6728 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6729 if (!mDisplayFrozen) {
6730 // We will run animations as long as the display isn't frozen.
6731
6732 if (animation == sDummyAnimation) {
6733 // This guy is going to animate, but not yet. For now count
6734 // it is not animating for purposes of scheduling transactions;
6735 // when it is really time to animate, this will be set to
6736 // a real animation and the next call will execute normally.
6737 return false;
6738 }
6739
6740 if ((allDrawn || animating || startingDisplayed) && animation != null) {
6741 if (!animating) {
6742 if (DEBUG_ANIM) Log.v(
6743 TAG, "Starting animation in " + this +
6744 " @ " + currentTime + ": dw=" + dw + " dh=" + dh
6745 + " scale=" + mTransitionAnimationScale
6746 + " allDrawn=" + allDrawn + " animating=" + animating);
6747 animation.initialize(dw, dh, dw, dh);
6748 animation.setStartTime(currentTime);
6749 animating = true;
6750 }
6751 transformation.clear();
6752 final boolean more = animation.getTransformation(
6753 currentTime, transformation);
6754 if (DEBUG_ANIM) Log.v(
6755 TAG, "Stepped animation in " + this +
6756 ": more=" + more + ", xform=" + transformation);
6757 if (more) {
6758 // we're done!
6759 hasTransformation = true;
6760 return true;
6761 }
6762 if (DEBUG_ANIM) Log.v(
6763 TAG, "Finished animation in " + this +
6764 " @ " + currentTime);
6765 animation = null;
6766 }
6767 } else if (animation != null) {
6768 // If the display is frozen, and there is a pending animation,
6769 // clear it and make sure we run the cleanup code.
6770 animating = true;
6771 animation = null;
6772 }
6773
6774 hasTransformation = false;
6775
6776 if (!animating) {
6777 return false;
6778 }
6779
6780 clearAnimation();
6781 animating = false;
6782 if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
6783 moveInputMethodWindowsIfNeededLocked(true);
6784 }
6785
6786 if (DEBUG_ANIM) Log.v(
6787 TAG, "Animation done in " + this
6788 + ": reportedVisible=" + reportedVisible);
6789
6790 transformation.clear();
6791 if (animLayerAdjustment != 0) {
6792 animLayerAdjustment = 0;
6793 updateLayers();
6794 }
6795
6796 final int N = windows.size();
6797 for (int i=0; i<N; i++) {
6798 ((WindowState)windows.get(i)).finishExit();
6799 }
6800 updateReportedVisibilityLocked();
6801
6802 return false;
6803 }
6804
6805 void updateReportedVisibilityLocked() {
6806 if (appToken == null) {
6807 return;
6808 }
6809
6810 int numInteresting = 0;
6811 int numVisible = 0;
6812 boolean nowGone = true;
6813
6814 if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
6815 final int N = allAppWindows.size();
6816 for (int i=0; i<N; i++) {
6817 WindowState win = allAppWindows.get(i);
6818 if (win == startingWindow || win.mAppFreezing) {
6819 continue;
6820 }
6821 if (DEBUG_VISIBILITY) {
6822 Log.v(TAG, "Win " + win + ": isDisplayed="
6823 + win.isDisplayedLw()
6824 + ", isAnimating=" + win.isAnimating());
6825 if (!win.isDisplayedLw()) {
6826 Log.v(TAG, "Not displayed: s=" + win.mSurface
6827 + " pv=" + win.mPolicyVisibility
6828 + " dp=" + win.mDrawPending
6829 + " cdp=" + win.mCommitDrawPending
6830 + " ah=" + win.mAttachedHidden
6831 + " th="
6832 + (win.mAppToken != null
6833 ? win.mAppToken.hiddenRequested : false)
6834 + " a=" + win.mAnimating);
6835 }
6836 }
6837 numInteresting++;
6838 if (win.isDisplayedLw()) {
6839 if (!win.isAnimating()) {
6840 numVisible++;
6841 }
6842 nowGone = false;
6843 } else if (win.isAnimating()) {
6844 nowGone = false;
6845 }
6846 }
6847
6848 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
6849 if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
6850 + numInteresting + " visible=" + numVisible);
6851 if (nowVisible != reportedVisible) {
6852 if (DEBUG_VISIBILITY) Log.v(
6853 TAG, "Visibility changed in " + this
6854 + ": vis=" + nowVisible);
6855 reportedVisible = nowVisible;
6856 Message m = mH.obtainMessage(
6857 H.REPORT_APPLICATION_TOKEN_WINDOWS,
6858 nowVisible ? 1 : 0,
6859 nowGone ? 1 : 0,
6860 this);
6861 mH.sendMessage(m);
6862 }
6863 }
6864
6865 void dump(PrintWriter pw, String prefix) {
6866 super.dump(pw, prefix);
6867 pw.println(prefix + "app=" + (appToken != null));
6868 pw.println(prefix + "allAppWindows=" + allAppWindows);
6869 pw.println(prefix + "groupId=" + groupId
6870 + " requestedOrientation=" + requestedOrientation);
6871 pw.println(prefix + "hiddenRequested=" + hiddenRequested
6872 + " clientHidden=" + clientHidden
6873 + " willBeHidden=" + willBeHidden
6874 + " reportedVisible=" + reportedVisible);
6875 pw.println(prefix + "paused=" + paused
6876 + " freezingScreen=" + freezingScreen);
6877 pw.println(prefix + "numInterestingWindows=" + numInterestingWindows
6878 + " numDrawnWindows=" + numDrawnWindows
6879 + " inPendingTransaction=" + inPendingTransaction
6880 + " allDrawn=" + allDrawn);
6881 pw.println(prefix + "animating=" + animating
6882 + " animation=" + animation);
6883 pw.println(prefix + "animLayerAdjustment=" + animLayerAdjustment
6884 + " transformation=" + transformation.toShortString());
6885 pw.println(prefix + "startingData=" + startingData
6886 + " removed=" + removed
6887 + " firstWindowDrawn=" + firstWindowDrawn);
6888 pw.println(prefix + "startingWindow=" + startingWindow
6889 + " startingView=" + startingView
6890 + " startingDisplayed=" + startingDisplayed
6891 + " startingMoved" + startingMoved);
6892 }
6893
6894 @Override
6895 public String toString() {
6896 return "AppWindowToken{"
6897 + Integer.toHexString(System.identityHashCode(this))
6898 + " token=" + token + "}";
6899 }
6900 }
6901
6902 public static WindowManager.LayoutParams findAnimations(
6903 ArrayList<AppWindowToken> order,
6904 ArrayList<AppWindowToken> tokenList1,
6905 ArrayList<AppWindowToken> tokenList2) {
6906 // We need to figure out which animation to use...
6907 WindowManager.LayoutParams animParams = null;
6908 int animSrc = 0;
6909
6910 //Log.i(TAG, "Looking for animations...");
6911 for (int i=order.size()-1; i>=0; i--) {
6912 AppWindowToken wtoken = order.get(i);
6913 //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
6914 if (tokenList1.contains(wtoken) || tokenList2.contains(wtoken)) {
6915 int j = wtoken.windows.size();
6916 while (j > 0) {
6917 j--;
6918 WindowState win = wtoken.windows.get(j);
6919 //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
6920 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
6921 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
6922 //Log.i(TAG, "Found base or application window, done!");
6923 if (wtoken.appFullscreen) {
6924 return win.mAttrs;
6925 }
6926 if (animSrc < 2) {
6927 animParams = win.mAttrs;
6928 animSrc = 2;
6929 }
6930 } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
6931 //Log.i(TAG, "Found normal window, we may use this...");
6932 animParams = win.mAttrs;
6933 animSrc = 1;
6934 }
6935 }
6936 }
6937 }
6938
6939 return animParams;
6940 }
6941
6942 // -------------------------------------------------------------
6943 // DummyAnimation
6944 // -------------------------------------------------------------
6945
6946 // This is an animation that does nothing: it just immediately finishes
6947 // itself every time it is called. It is used as a stub animation in cases
6948 // where we want to synchronize multiple things that may be animating.
6949 static final class DummyAnimation extends Animation {
6950 public boolean getTransformation(long currentTime, Transformation outTransformation) {
6951 return false;
6952 }
6953 }
6954 static final Animation sDummyAnimation = new DummyAnimation();
6955
6956 // -------------------------------------------------------------
6957 // Async Handler
6958 // -------------------------------------------------------------
6959
6960 static final class StartingData {
6961 final String pkg;
6962 final int theme;
6963 final CharSequence nonLocalizedLabel;
6964 final int labelRes;
6965 final int icon;
6966
6967 StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
6968 int _labelRes, int _icon) {
6969 pkg = _pkg;
6970 theme = _theme;
6971 nonLocalizedLabel = _nonLocalizedLabel;
6972 labelRes = _labelRes;
6973 icon = _icon;
6974 }
6975 }
6976
6977 private final class H extends Handler {
6978 public static final int REPORT_FOCUS_CHANGE = 2;
6979 public static final int REPORT_LOSING_FOCUS = 3;
6980 public static final int ANIMATE = 4;
6981 public static final int ADD_STARTING = 5;
6982 public static final int REMOVE_STARTING = 6;
6983 public static final int FINISHED_STARTING = 7;
6984 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006985 public static final int WINDOW_FREEZE_TIMEOUT = 11;
6986 public static final int HOLD_SCREEN_CHANGED = 12;
6987 public static final int APP_TRANSITION_TIMEOUT = 13;
6988 public static final int PERSIST_ANIMATION_SCALE = 14;
6989 public static final int FORCE_GC = 15;
6990 public static final int ENABLE_SCREEN = 16;
6991 public static final int APP_FREEZE_TIMEOUT = 17;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07006992 public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006993
6994 private Session mLastReportedHold;
6995
6996 public H() {
6997 }
6998
6999 @Override
7000 public void handleMessage(Message msg) {
7001 switch (msg.what) {
7002 case REPORT_FOCUS_CHANGE: {
7003 WindowState lastFocus;
7004 WindowState newFocus;
7005
7006 synchronized(mWindowMap) {
7007 lastFocus = mLastFocus;
7008 newFocus = mCurrentFocus;
7009 if (lastFocus == newFocus) {
7010 // Focus is not changing, so nothing to do.
7011 return;
7012 }
7013 mLastFocus = newFocus;
7014 //Log.i(TAG, "Focus moving from " + lastFocus
7015 // + " to " + newFocus);
7016 if (newFocus != null && lastFocus != null
7017 && !newFocus.isDisplayedLw()) {
7018 //Log.i(TAG, "Delaying loss of focus...");
7019 mLosingFocus.add(lastFocus);
7020 lastFocus = null;
7021 }
7022 }
7023
7024 if (lastFocus != newFocus) {
7025 //System.out.println("Changing focus from " + lastFocus
7026 // + " to " + newFocus);
7027 if (newFocus != null) {
7028 try {
7029 //Log.i(TAG, "Gaining focus: " + newFocus);
7030 newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7031 } catch (RemoteException e) {
7032 // Ignore if process has died.
7033 }
7034 }
7035
7036 if (lastFocus != null) {
7037 try {
7038 //Log.i(TAG, "Losing focus: " + lastFocus);
7039 lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7040 } catch (RemoteException e) {
7041 // Ignore if process has died.
7042 }
7043 }
7044 }
7045 } break;
7046
7047 case REPORT_LOSING_FOCUS: {
7048 ArrayList<WindowState> losers;
7049
7050 synchronized(mWindowMap) {
7051 losers = mLosingFocus;
7052 mLosingFocus = new ArrayList<WindowState>();
7053 }
7054
7055 final int N = losers.size();
7056 for (int i=0; i<N; i++) {
7057 try {
7058 //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
7059 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7060 } catch (RemoteException e) {
7061 // Ignore if process has died.
7062 }
7063 }
7064 } break;
7065
7066 case ANIMATE: {
7067 synchronized(mWindowMap) {
7068 mAnimationPending = false;
7069 performLayoutAndPlaceSurfacesLocked();
7070 }
7071 } break;
7072
7073 case ADD_STARTING: {
7074 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7075 final StartingData sd = wtoken.startingData;
7076
7077 if (sd == null) {
7078 // Animation has been canceled... do nothing.
7079 return;
7080 }
7081
7082 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
7083 + wtoken + ": pkg=" + sd.pkg);
7084
7085 View view = null;
7086 try {
7087 view = mPolicy.addStartingWindow(
7088 wtoken.token, sd.pkg,
7089 sd.theme, sd.nonLocalizedLabel, sd.labelRes,
7090 sd.icon);
7091 } catch (Exception e) {
7092 Log.w(TAG, "Exception when adding starting window", e);
7093 }
7094
7095 if (view != null) {
7096 boolean abort = false;
7097
7098 synchronized(mWindowMap) {
7099 if (wtoken.removed || wtoken.startingData == null) {
7100 // If the window was successfully added, then
7101 // we need to remove it.
7102 if (wtoken.startingWindow != null) {
7103 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7104 "Aborted starting " + wtoken
7105 + ": removed=" + wtoken.removed
7106 + " startingData=" + wtoken.startingData);
7107 wtoken.startingWindow = null;
7108 wtoken.startingData = null;
7109 abort = true;
7110 }
7111 } else {
7112 wtoken.startingView = view;
7113 }
7114 if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
7115 "Added starting " + wtoken
7116 + ": startingWindow="
7117 + wtoken.startingWindow + " startingView="
7118 + wtoken.startingView);
7119 }
7120
7121 if (abort) {
7122 try {
7123 mPolicy.removeStartingWindow(wtoken.token, view);
7124 } catch (Exception e) {
7125 Log.w(TAG, "Exception when removing starting window", e);
7126 }
7127 }
7128 }
7129 } break;
7130
7131 case REMOVE_STARTING: {
7132 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7133 IBinder token = null;
7134 View view = null;
7135 synchronized (mWindowMap) {
7136 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
7137 + wtoken + ": startingWindow="
7138 + wtoken.startingWindow + " startingView="
7139 + wtoken.startingView);
7140 if (wtoken.startingWindow != null) {
7141 view = wtoken.startingView;
7142 token = wtoken.token;
7143 wtoken.startingData = null;
7144 wtoken.startingView = null;
7145 wtoken.startingWindow = null;
7146 }
7147 }
7148 if (view != null) {
7149 try {
7150 mPolicy.removeStartingWindow(token, view);
7151 } catch (Exception e) {
7152 Log.w(TAG, "Exception when removing starting window", e);
7153 }
7154 }
7155 } break;
7156
7157 case FINISHED_STARTING: {
7158 IBinder token = null;
7159 View view = null;
7160 while (true) {
7161 synchronized (mWindowMap) {
7162 final int N = mFinishedStarting.size();
7163 if (N <= 0) {
7164 break;
7165 }
7166 AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7167
7168 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7169 "Finished starting " + wtoken
7170 + ": startingWindow=" + wtoken.startingWindow
7171 + " startingView=" + wtoken.startingView);
7172
7173 if (wtoken.startingWindow == null) {
7174 continue;
7175 }
7176
7177 view = wtoken.startingView;
7178 token = wtoken.token;
7179 wtoken.startingData = null;
7180 wtoken.startingView = null;
7181 wtoken.startingWindow = null;
7182 }
7183
7184 try {
7185 mPolicy.removeStartingWindow(token, view);
7186 } catch (Exception e) {
7187 Log.w(TAG, "Exception when removing starting window", e);
7188 }
7189 }
7190 } break;
7191
7192 case REPORT_APPLICATION_TOKEN_WINDOWS: {
7193 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7194
7195 boolean nowVisible = msg.arg1 != 0;
7196 boolean nowGone = msg.arg2 != 0;
7197
7198 try {
7199 if (DEBUG_VISIBILITY) Log.v(
7200 TAG, "Reporting visible in " + wtoken
7201 + " visible=" + nowVisible
7202 + " gone=" + nowGone);
7203 if (nowVisible) {
7204 wtoken.appToken.windowsVisible();
7205 } else {
7206 wtoken.appToken.windowsGone();
7207 }
7208 } catch (RemoteException ex) {
7209 }
7210 } break;
7211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007212 case WINDOW_FREEZE_TIMEOUT: {
7213 synchronized (mWindowMap) {
7214 Log.w(TAG, "Window freeze timeout expired.");
7215 int i = mWindows.size();
7216 while (i > 0) {
7217 i--;
7218 WindowState w = (WindowState)mWindows.get(i);
7219 if (w.mOrientationChanging) {
7220 w.mOrientationChanging = false;
7221 Log.w(TAG, "Force clearing orientation change: " + w);
7222 }
7223 }
7224 performLayoutAndPlaceSurfacesLocked();
7225 }
7226 break;
7227 }
7228
7229 case HOLD_SCREEN_CHANGED: {
7230 Session oldHold;
7231 Session newHold;
7232 synchronized (mWindowMap) {
7233 oldHold = mLastReportedHold;
7234 newHold = (Session)msg.obj;
7235 mLastReportedHold = newHold;
7236 }
7237
7238 if (oldHold != newHold) {
7239 try {
7240 if (oldHold != null) {
7241 mBatteryStats.noteStopWakelock(oldHold.mUid,
7242 "window",
7243 BatteryStats.WAKE_TYPE_WINDOW);
7244 }
7245 if (newHold != null) {
7246 mBatteryStats.noteStartWakelock(newHold.mUid,
7247 "window",
7248 BatteryStats.WAKE_TYPE_WINDOW);
7249 }
7250 } catch (RemoteException e) {
7251 }
7252 }
7253 break;
7254 }
7255
7256 case APP_TRANSITION_TIMEOUT: {
7257 synchronized (mWindowMap) {
7258 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
7259 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7260 "*** APP TRANSITION TIMEOUT");
7261 mAppTransitionReady = true;
7262 mAppTransitionTimeout = true;
7263 performLayoutAndPlaceSurfacesLocked();
7264 }
7265 }
7266 break;
7267 }
7268
7269 case PERSIST_ANIMATION_SCALE: {
7270 Settings.System.putFloat(mContext.getContentResolver(),
7271 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7272 Settings.System.putFloat(mContext.getContentResolver(),
7273 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7274 break;
7275 }
7276
7277 case FORCE_GC: {
7278 synchronized(mWindowMap) {
7279 if (mAnimationPending) {
7280 // If we are animating, don't do the gc now but
7281 // delay a bit so we don't interrupt the animation.
7282 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7283 2000);
7284 return;
7285 }
7286 // If we are currently rotating the display, it will
7287 // schedule a new message when done.
7288 if (mDisplayFrozen) {
7289 return;
7290 }
7291 mFreezeGcPending = 0;
7292 }
7293 Runtime.getRuntime().gc();
7294 break;
7295 }
7296
7297 case ENABLE_SCREEN: {
7298 performEnableScreen();
7299 break;
7300 }
7301
7302 case APP_FREEZE_TIMEOUT: {
7303 synchronized (mWindowMap) {
7304 Log.w(TAG, "App freeze timeout expired.");
7305 int i = mAppTokens.size();
7306 while (i > 0) {
7307 i--;
7308 AppWindowToken tok = mAppTokens.get(i);
7309 if (tok.freezingScreen) {
7310 Log.w(TAG, "Force clearing freeze: " + tok);
7311 unsetAppFreezingScreenLocked(tok, true, true);
7312 }
7313 }
7314 }
7315 break;
7316 }
7317
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007318 case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
The Android Open Source Project10592532009-03-18 17:39:46 -07007319 if (updateOrientationFromAppTokens(null, null) != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007320 sendNewConfiguration();
7321 }
7322 break;
7323 }
7324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007325 }
7326 }
7327 }
7328
7329 // -------------------------------------------------------------
7330 // IWindowManager API
7331 // -------------------------------------------------------------
7332
7333 public IWindowSession openSession(IInputMethodClient client,
7334 IInputContext inputContext) {
7335 if (client == null) throw new IllegalArgumentException("null client");
7336 if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7337 return new Session(client, inputContext);
7338 }
7339
7340 public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7341 synchronized (mWindowMap) {
7342 // The focus for the client is the window immediately below
7343 // where we would place the input method window.
7344 int idx = findDesiredInputMethodWindowIndexLocked(false);
7345 WindowState imFocus;
7346 if (idx > 0) {
7347 imFocus = (WindowState)mWindows.get(idx-1);
7348 if (imFocus != null) {
7349 if (imFocus.mSession.mClient != null &&
7350 imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7351 return true;
7352 }
7353 }
7354 }
7355 }
7356 return false;
7357 }
7358
7359 // -------------------------------------------------------------
7360 // Internals
7361 // -------------------------------------------------------------
7362
7363 final WindowState windowForClientLocked(Session session, IWindow client) {
7364 return windowForClientLocked(session, client.asBinder());
7365 }
7366
7367 final WindowState windowForClientLocked(Session session, IBinder client) {
7368 WindowState win = mWindowMap.get(client);
7369 if (localLOGV) Log.v(
7370 TAG, "Looking up client " + client + ": " + win);
7371 if (win == null) {
7372 RuntimeException ex = new RuntimeException();
7373 Log.w(TAG, "Requested window " + client + " does not exist", ex);
7374 return null;
7375 }
7376 if (session != null && win.mSession != session) {
7377 RuntimeException ex = new RuntimeException();
7378 Log.w(TAG, "Requested window " + client + " is in session " +
7379 win.mSession + ", not " + session, ex);
7380 return null;
7381 }
7382
7383 return win;
7384 }
7385
7386 private final void assignLayersLocked() {
7387 int N = mWindows.size();
7388 int curBaseLayer = 0;
7389 int curLayer = 0;
7390 int i;
7391
7392 for (i=0; i<N; i++) {
7393 WindowState w = (WindowState)mWindows.get(i);
7394 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
7395 curLayer += WINDOW_LAYER_MULTIPLIER;
7396 w.mLayer = curLayer;
7397 } else {
7398 curBaseLayer = curLayer = w.mBaseLayer;
7399 w.mLayer = curLayer;
7400 }
7401 if (w.mTargetAppToken != null) {
7402 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
7403 } else if (w.mAppToken != null) {
7404 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
7405 } else {
7406 w.mAnimLayer = w.mLayer;
7407 }
7408 if (w.mIsImWindow) {
7409 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
7410 }
7411 if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
7412 + w.mAnimLayer);
7413 //System.out.println(
7414 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7415 }
7416 }
7417
7418 private boolean mInLayout = false;
7419 private final void performLayoutAndPlaceSurfacesLocked() {
7420 if (mInLayout) {
7421 if (Config.DEBUG) {
7422 throw new RuntimeException("Recursive call!");
7423 }
7424 Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7425 return;
7426 }
7427
7428 boolean recoveringMemory = false;
7429 if (mForceRemoves != null) {
7430 recoveringMemory = true;
7431 // Wait a little it for things to settle down, and off we go.
7432 for (int i=0; i<mForceRemoves.size(); i++) {
7433 WindowState ws = mForceRemoves.get(i);
7434 Log.i(TAG, "Force removing: " + ws);
7435 removeWindowInnerLocked(ws.mSession, ws);
7436 }
7437 mForceRemoves = null;
7438 Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
7439 Object tmp = new Object();
7440 synchronized (tmp) {
7441 try {
7442 tmp.wait(250);
7443 } catch (InterruptedException e) {
7444 }
7445 }
7446 }
7447
7448 mInLayout = true;
7449 try {
7450 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7451
7452 int i = mPendingRemove.size()-1;
7453 if (i >= 0) {
7454 while (i >= 0) {
7455 WindowState w = mPendingRemove.get(i);
7456 removeWindowInnerLocked(w.mSession, w);
7457 i--;
7458 }
7459 mPendingRemove.clear();
7460
7461 mInLayout = false;
7462 assignLayersLocked();
7463 mLayoutNeeded = true;
7464 performLayoutAndPlaceSurfacesLocked();
7465
7466 } else {
7467 mInLayout = false;
7468 if (mLayoutNeeded) {
7469 requestAnimationLocked(0);
7470 }
7471 }
7472 } catch (RuntimeException e) {
7473 mInLayout = false;
7474 Log.e(TAG, "Unhandled exception while layout out windows", e);
7475 }
7476 }
7477
7478 private final void performLayoutLockedInner() {
7479 final int dw = mDisplay.getWidth();
7480 final int dh = mDisplay.getHeight();
7481
7482 final int N = mWindows.size();
7483 int i;
7484
7485 // FIRST LOOP: Perform a layout, if needed.
7486
7487 if (mLayoutNeeded) {
7488 mPolicy.beginLayoutLw(dw, dh);
7489
7490 // First perform layout of any root windows (not attached
7491 // to another window).
7492 int topAttached = -1;
7493 for (i = N-1; i >= 0; i--) {
7494 WindowState win = (WindowState) mWindows.get(i);
7495
7496 boolean gone = win.mViewVisibility == View.GONE
7497 || !win.mRelayoutCalled
The Android Open Source Project10592532009-03-18 17:39:46 -07007498 || win.mRootToken.hidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007499
7500 // If this view is GONE, then skip it -- keep the current
7501 // frame, and let the caller know so they can ignore it
7502 // if they want. (We do the normal layout for INVISIBLE
7503 // windows, since that means "perform layout as normal,
7504 // just don't display").
7505 if (!gone || !win.mHaveFrame) {
7506 if (!win.mLayoutAttached) {
7507 mPolicy.layoutWindowLw(win, win.mAttrs, null);
7508 } else {
7509 if (topAttached < 0) topAttached = i;
7510 }
7511 }
7512 }
7513
7514 // Now perform layout of attached windows, which usually
7515 // depend on the position of the window they are attached to.
7516 // XXX does not deal with windows that are attached to windows
7517 // that are themselves attached.
7518 for (i = topAttached; i >= 0; i--) {
7519 WindowState win = (WindowState) mWindows.get(i);
7520
7521 // If this view is GONE, then skip it -- keep the current
7522 // frame, and let the caller know so they can ignore it
7523 // if they want. (We do the normal layout for INVISIBLE
7524 // windows, since that means "perform layout as normal,
7525 // just don't display").
7526 if (win.mLayoutAttached) {
7527 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7528 || !win.mHaveFrame) {
7529 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7530 }
7531 }
7532 }
7533
7534 mPolicy.finishLayoutLw();
7535 mLayoutNeeded = false;
7536 }
7537 }
7538
7539 private final void performLayoutAndPlaceSurfacesLockedInner(
7540 boolean recoveringMemory) {
7541 final long currentTime = SystemClock.uptimeMillis();
7542 final int dw = mDisplay.getWidth();
7543 final int dh = mDisplay.getHeight();
7544
7545 final int N = mWindows.size();
7546 int i;
7547
7548 // FIRST LOOP: Perform a layout, if needed.
7549
7550 performLayoutLockedInner();
7551
7552 if (mFxSession == null) {
7553 mFxSession = new SurfaceSession();
7554 }
7555
7556 if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
7557
7558 // Initialize state of exiting tokens.
7559 for (i=mExitingTokens.size()-1; i>=0; i--) {
7560 mExitingTokens.get(i).hasVisible = false;
7561 }
7562
7563 // Initialize state of exiting applications.
7564 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7565 mExitingAppTokens.get(i).hasVisible = false;
7566 }
7567
7568 // SECOND LOOP: Execute animations and update visibility of windows.
7569
7570 boolean orientationChangeComplete = true;
7571 Session holdScreen = null;
7572 float screenBrightness = -1;
7573 boolean focusDisplayed = false;
7574 boolean animating = false;
7575
7576 Surface.openTransaction();
7577 try {
7578 boolean restart;
7579
7580 do {
7581 final int transactionSequence = ++mTransactionSequence;
7582
7583 // Update animations of all applications, including those
7584 // associated with exiting/removed apps
7585 boolean tokensAnimating = false;
7586 final int NAT = mAppTokens.size();
7587 for (i=0; i<NAT; i++) {
7588 if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7589 tokensAnimating = true;
7590 }
7591 }
7592 final int NEAT = mExitingAppTokens.size();
7593 for (i=0; i<NEAT; i++) {
7594 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7595 tokensAnimating = true;
7596 }
7597 }
7598
7599 animating = tokensAnimating;
7600 restart = false;
7601
7602 boolean tokenMayBeDrawn = false;
7603
7604 mPolicy.beginAnimationLw(dw, dh);
7605
7606 for (i=N-1; i>=0; i--) {
7607 WindowState w = (WindowState)mWindows.get(i);
7608
7609 final WindowManager.LayoutParams attrs = w.mAttrs;
7610
7611 if (w.mSurface != null) {
7612 // Execute animation.
7613 w.commitFinishDrawingLocked(currentTime);
7614 if (w.stepAnimationLocked(currentTime, dw, dh)) {
7615 animating = true;
7616 //w.dump(" ");
7617 }
7618
7619 mPolicy.animatingWindowLw(w, attrs);
7620 }
7621
7622 final AppWindowToken atoken = w.mAppToken;
7623 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7624 if (atoken.lastTransactionSequence != transactionSequence) {
7625 atoken.lastTransactionSequence = transactionSequence;
7626 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7627 atoken.startingDisplayed = false;
7628 }
7629 if ((w.isOnScreen() || w.mAttrs.type
7630 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7631 && !w.mExiting && !w.mDestroying) {
7632 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7633 Log.v(TAG, "Eval win " + w + ": isDisplayed="
7634 + w.isDisplayedLw()
7635 + ", isAnimating=" + w.isAnimating());
7636 if (!w.isDisplayedLw()) {
7637 Log.v(TAG, "Not displayed: s=" + w.mSurface
7638 + " pv=" + w.mPolicyVisibility
7639 + " dp=" + w.mDrawPending
7640 + " cdp=" + w.mCommitDrawPending
7641 + " ah=" + w.mAttachedHidden
7642 + " th=" + atoken.hiddenRequested
7643 + " a=" + w.mAnimating);
7644 }
7645 }
7646 if (w != atoken.startingWindow) {
7647 if (!atoken.freezingScreen || !w.mAppFreezing) {
7648 atoken.numInterestingWindows++;
7649 if (w.isDisplayedLw()) {
7650 atoken.numDrawnWindows++;
7651 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
7652 "tokenMayBeDrawn: " + atoken
7653 + " freezingScreen=" + atoken.freezingScreen
7654 + " mAppFreezing=" + w.mAppFreezing);
7655 tokenMayBeDrawn = true;
7656 }
7657 }
7658 } else if (w.isDisplayedLw()) {
7659 atoken.startingDisplayed = true;
7660 }
7661 }
7662 } else if (w.mReadyToShow) {
7663 w.performShowLocked();
7664 }
7665 }
7666
7667 if (mPolicy.finishAnimationLw()) {
7668 restart = true;
7669 }
7670
7671 if (tokenMayBeDrawn) {
7672 // See if any windows have been drawn, so they (and others
7673 // associated with them) can now be shown.
7674 final int NT = mTokenList.size();
7675 for (i=0; i<NT; i++) {
7676 AppWindowToken wtoken = mTokenList.get(i).appWindowToken;
7677 if (wtoken == null) {
7678 continue;
7679 }
7680 if (wtoken.freezingScreen) {
7681 int numInteresting = wtoken.numInterestingWindows;
7682 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7683 if (DEBUG_VISIBILITY) Log.v(TAG,
7684 "allDrawn: " + wtoken
7685 + " interesting=" + numInteresting
7686 + " drawn=" + wtoken.numDrawnWindows);
7687 wtoken.showAllWindowsLocked();
7688 unsetAppFreezingScreenLocked(wtoken, false, true);
7689 orientationChangeComplete = true;
7690 }
7691 } else if (!wtoken.allDrawn) {
7692 int numInteresting = wtoken.numInterestingWindows;
7693 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7694 if (DEBUG_VISIBILITY) Log.v(TAG,
7695 "allDrawn: " + wtoken
7696 + " interesting=" + numInteresting
7697 + " drawn=" + wtoken.numDrawnWindows);
7698 wtoken.allDrawn = true;
7699 restart = true;
7700
7701 // We can now show all of the drawn windows!
7702 if (!mOpeningApps.contains(wtoken)) {
7703 wtoken.showAllWindowsLocked();
7704 }
7705 }
7706 }
7707 }
7708 }
7709
7710 // If we are ready to perform an app transition, check through
7711 // all of the app tokens to be shown and see if they are ready
7712 // to go.
7713 if (mAppTransitionReady) {
7714 int NN = mOpeningApps.size();
7715 boolean goodToGo = true;
7716 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7717 "Checking " + NN + " opening apps (frozen="
7718 + mDisplayFrozen + " timeout="
7719 + mAppTransitionTimeout + ")...");
7720 if (!mDisplayFrozen && !mAppTransitionTimeout) {
7721 // If the display isn't frozen, wait to do anything until
7722 // all of the apps are ready. Otherwise just go because
7723 // we'll unfreeze the display when everyone is ready.
7724 for (i=0; i<NN && goodToGo; i++) {
7725 AppWindowToken wtoken = mOpeningApps.get(i);
7726 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7727 "Check opening app" + wtoken + ": allDrawn="
7728 + wtoken.allDrawn + " startingDisplayed="
7729 + wtoken.startingDisplayed);
7730 if (!wtoken.allDrawn && !wtoken.startingDisplayed
7731 && !wtoken.startingMoved) {
7732 goodToGo = false;
7733 }
7734 }
7735 }
7736 if (goodToGo) {
7737 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
7738 int transit = mNextAppTransition;
7739 if (mSkipAppTransitionAnimation) {
7740 transit = WindowManagerPolicy.TRANSIT_NONE;
7741 }
7742 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
7743 mAppTransitionReady = false;
7744 mAppTransitionTimeout = false;
7745 mStartingIconInTransition = false;
7746 mSkipAppTransitionAnimation = false;
7747
7748 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7749
7750 // We need to figure out which animation to use...
7751 WindowManager.LayoutParams lp = findAnimations(mAppTokens,
7752 mOpeningApps, mClosingApps);
7753
7754 NN = mOpeningApps.size();
7755 for (i=0; i<NN; i++) {
7756 AppWindowToken wtoken = mOpeningApps.get(i);
7757 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7758 "Now opening app" + wtoken);
7759 wtoken.reportedVisible = false;
7760 wtoken.inPendingTransaction = false;
7761 setTokenVisibilityLocked(wtoken, lp, true, transit, false);
7762 wtoken.updateReportedVisibilityLocked();
7763 wtoken.showAllWindowsLocked();
7764 }
7765 NN = mClosingApps.size();
7766 for (i=0; i<NN; i++) {
7767 AppWindowToken wtoken = mClosingApps.get(i);
7768 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7769 "Now closing app" + wtoken);
7770 wtoken.inPendingTransaction = false;
7771 setTokenVisibilityLocked(wtoken, lp, false, transit, false);
7772 wtoken.updateReportedVisibilityLocked();
7773 // Force the allDrawn flag, because we want to start
7774 // this guy's animations regardless of whether it's
7775 // gotten drawn.
7776 wtoken.allDrawn = true;
7777 }
7778
7779 mOpeningApps.clear();
7780 mClosingApps.clear();
7781
7782 // This has changed the visibility of windows, so perform
7783 // a new layout to get them all up-to-date.
7784 mLayoutNeeded = true;
7785 moveInputMethodWindowsIfNeededLocked(true);
7786 performLayoutLockedInner();
7787 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
7788
7789 restart = true;
7790 }
7791 }
7792 } while (restart);
7793
7794 // THIRD LOOP: Update the surfaces of all windows.
7795
7796 final boolean someoneLosingFocus = mLosingFocus.size() != 0;
7797
7798 boolean obscured = false;
7799 boolean blurring = false;
7800 boolean dimming = false;
7801 boolean covered = false;
Dianne Hackborn2f847b92009-03-25 15:25:33 -07007802 boolean syswin = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007803
7804 for (i=N-1; i>=0; i--) {
7805 WindowState w = (WindowState)mWindows.get(i);
7806
7807 boolean displayed = false;
7808 final WindowManager.LayoutParams attrs = w.mAttrs;
7809 final int attrFlags = attrs.flags;
7810
7811 if (w.mSurface != null) {
7812 w.computeShownFrameLocked();
7813 if (localLOGV) Log.v(
7814 TAG, "Placing surface #" + i + " " + w.mSurface
7815 + ": new=" + w.mShownFrame + ", old="
7816 + w.mLastShownFrame);
7817
7818 boolean resize;
7819 int width, height;
7820 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
7821 resize = w.mLastRequestedWidth != w.mRequestedWidth ||
7822 w.mLastRequestedHeight != w.mRequestedHeight;
7823 // for a scaled surface, we just want to use
7824 // the requested size.
7825 width = w.mRequestedWidth;
7826 height = w.mRequestedHeight;
7827 w.mLastRequestedWidth = width;
7828 w.mLastRequestedHeight = height;
7829 w.mLastShownFrame.set(w.mShownFrame);
7830 try {
7831 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
7832 } catch (RuntimeException e) {
7833 Log.w(TAG, "Error positioning surface in " + w, e);
7834 if (!recoveringMemory) {
7835 reclaimSomeSurfaceMemoryLocked(w, "position");
7836 }
7837 }
7838 } else {
7839 resize = !w.mLastShownFrame.equals(w.mShownFrame);
7840 width = w.mShownFrame.width();
7841 height = w.mShownFrame.height();
7842 w.mLastShownFrame.set(w.mShownFrame);
7843 if (resize) {
7844 if (SHOW_TRANSACTIONS) Log.i(
7845 TAG, " SURFACE " + w.mSurface + ": ("
7846 + w.mShownFrame.left + ","
7847 + w.mShownFrame.top + ") ("
7848 + w.mShownFrame.width() + "x"
7849 + w.mShownFrame.height() + ")");
7850 }
7851 }
7852
7853 if (resize) {
7854 if (width < 1) width = 1;
7855 if (height < 1) height = 1;
7856 if (w.mSurface != null) {
7857 try {
7858 w.mSurface.setSize(width, height);
7859 w.mSurface.setPosition(w.mShownFrame.left,
7860 w.mShownFrame.top);
7861 } catch (RuntimeException e) {
7862 // If something goes wrong with the surface (such
7863 // as running out of memory), don't take down the
7864 // entire system.
7865 Log.e(TAG, "Failure updating surface of " + w
7866 + "size=(" + width + "x" + height
7867 + "), pos=(" + w.mShownFrame.left
7868 + "," + w.mShownFrame.top + ")", e);
7869 if (!recoveringMemory) {
7870 reclaimSomeSurfaceMemoryLocked(w, "size");
7871 }
7872 }
7873 }
7874 }
7875 if (!w.mAppFreezing) {
7876 w.mContentInsetsChanged =
7877 !w.mLastContentInsets.equals(w.mContentInsets);
7878 w.mVisibleInsetsChanged =
7879 !w.mLastVisibleInsets.equals(w.mVisibleInsets);
7880 if (!w.mLastFrame.equals(w.mFrame)
7881 || w.mContentInsetsChanged
7882 || w.mVisibleInsetsChanged) {
7883 w.mLastFrame.set(w.mFrame);
7884 w.mLastContentInsets.set(w.mContentInsets);
7885 w.mLastVisibleInsets.set(w.mVisibleInsets);
7886 // If the orientation is changing, then we need to
7887 // hold off on unfreezing the display until this
7888 // window has been redrawn; to do that, we need
7889 // to go through the process of getting informed
7890 // by the application when it has finished drawing.
7891 if (w.mOrientationChanging) {
7892 if (DEBUG_ORIENTATION) Log.v(TAG,
7893 "Orientation start waiting for draw in "
7894 + w + ", surface " + w.mSurface);
7895 w.mDrawPending = true;
7896 w.mCommitDrawPending = false;
7897 w.mReadyToShow = false;
7898 if (w.mAppToken != null) {
7899 w.mAppToken.allDrawn = false;
7900 }
7901 }
7902 if (DEBUG_ORIENTATION) Log.v(TAG,
7903 "Resizing window " + w + " to " + w.mFrame);
7904 mResizingWindows.add(w);
7905 } else if (w.mOrientationChanging) {
7906 if (!w.mDrawPending && !w.mCommitDrawPending) {
7907 if (DEBUG_ORIENTATION) Log.v(TAG,
7908 "Orientation not waiting for draw in "
7909 + w + ", surface " + w.mSurface);
7910 w.mOrientationChanging = false;
7911 }
7912 }
7913 }
7914
7915 if (w.mAttachedHidden) {
7916 if (!w.mLastHidden) {
7917 //dump();
7918 w.mLastHidden = true;
7919 if (SHOW_TRANSACTIONS) Log.i(
7920 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)");
7921 if (w.mSurface != null) {
7922 try {
7923 w.mSurface.hide();
7924 } catch (RuntimeException e) {
7925 Log.w(TAG, "Exception hiding surface in " + w);
7926 }
7927 }
7928 mKeyWaiter.releasePendingPointerLocked(w.mSession);
7929 }
7930 // If we are waiting for this window to handle an
7931 // orientation change, well, it is hidden, so
7932 // doesn't really matter. Note that this does
7933 // introduce a potential glitch if the window
7934 // becomes unhidden before it has drawn for the
7935 // new orientation.
7936 if (w.mOrientationChanging) {
7937 w.mOrientationChanging = false;
7938 if (DEBUG_ORIENTATION) Log.v(TAG,
7939 "Orientation change skips hidden " + w);
7940 }
7941 } else if (!w.isReadyForDisplay()) {
7942 if (!w.mLastHidden) {
7943 //dump();
7944 w.mLastHidden = true;
7945 if (SHOW_TRANSACTIONS) Log.i(
7946 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)");
7947 if (w.mSurface != null) {
7948 try {
7949 w.mSurface.hide();
7950 } catch (RuntimeException e) {
7951 Log.w(TAG, "Exception exception hiding surface in " + w);
7952 }
7953 }
7954 mKeyWaiter.releasePendingPointerLocked(w.mSession);
7955 }
7956 // If we are waiting for this window to handle an
7957 // orientation change, well, it is hidden, so
7958 // doesn't really matter. Note that this does
7959 // introduce a potential glitch if the window
7960 // becomes unhidden before it has drawn for the
7961 // new orientation.
7962 if (w.mOrientationChanging) {
7963 w.mOrientationChanging = false;
7964 if (DEBUG_ORIENTATION) Log.v(TAG,
7965 "Orientation change skips hidden " + w);
7966 }
7967 } else if (w.mLastLayer != w.mAnimLayer
7968 || w.mLastAlpha != w.mShownAlpha
7969 || w.mLastDsDx != w.mDsDx
7970 || w.mLastDtDx != w.mDtDx
7971 || w.mLastDsDy != w.mDsDy
7972 || w.mLastDtDy != w.mDtDy
7973 || w.mLastHScale != w.mHScale
7974 || w.mLastVScale != w.mVScale
7975 || w.mLastHidden) {
7976 displayed = true;
7977 w.mLastAlpha = w.mShownAlpha;
7978 w.mLastLayer = w.mAnimLayer;
7979 w.mLastDsDx = w.mDsDx;
7980 w.mLastDtDx = w.mDtDx;
7981 w.mLastDsDy = w.mDsDy;
7982 w.mLastDtDy = w.mDtDy;
7983 w.mLastHScale = w.mHScale;
7984 w.mLastVScale = w.mVScale;
7985 if (SHOW_TRANSACTIONS) Log.i(
7986 TAG, " SURFACE " + w.mSurface + ": alpha="
7987 + w.mShownAlpha + " layer=" + w.mAnimLayer);
7988 if (w.mSurface != null) {
7989 try {
7990 w.mSurface.setAlpha(w.mShownAlpha);
7991 w.mSurface.setLayer(w.mAnimLayer);
7992 w.mSurface.setMatrix(
7993 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
7994 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
7995 } catch (RuntimeException e) {
7996 Log.w(TAG, "Error updating surface in " + w, e);
7997 if (!recoveringMemory) {
7998 reclaimSomeSurfaceMemoryLocked(w, "update");
7999 }
8000 }
8001 }
8002
8003 if (w.mLastHidden && !w.mDrawPending
8004 && !w.mCommitDrawPending
8005 && !w.mReadyToShow) {
8006 if (SHOW_TRANSACTIONS) Log.i(
8007 TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)");
8008 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w
8009 + " during relayout");
8010 if (showSurfaceRobustlyLocked(w)) {
8011 w.mHasDrawn = true;
8012 w.mLastHidden = false;
8013 } else {
8014 w.mOrientationChanging = false;
8015 }
8016 }
8017 if (w.mSurface != null) {
8018 w.mToken.hasVisible = true;
8019 }
8020 } else {
8021 displayed = true;
8022 }
8023
8024 if (displayed) {
8025 if (!covered) {
8026 if (attrs.width == LayoutParams.FILL_PARENT
8027 && attrs.height == LayoutParams.FILL_PARENT) {
8028 covered = true;
8029 }
8030 }
8031 if (w.mOrientationChanging) {
8032 if (w.mDrawPending || w.mCommitDrawPending) {
8033 orientationChangeComplete = false;
8034 if (DEBUG_ORIENTATION) Log.v(TAG,
8035 "Orientation continue waiting for draw in " + w);
8036 } else {
8037 w.mOrientationChanging = false;
8038 if (DEBUG_ORIENTATION) Log.v(TAG,
8039 "Orientation change complete in " + w);
8040 }
8041 }
8042 w.mToken.hasVisible = true;
8043 }
8044 } else if (w.mOrientationChanging) {
8045 if (DEBUG_ORIENTATION) Log.v(TAG,
8046 "Orientation change skips hidden " + w);
8047 w.mOrientationChanging = false;
8048 }
8049
8050 final boolean canBeSeen = w.isDisplayedLw();
8051
8052 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8053 focusDisplayed = true;
8054 }
8055
8056 // Update effect.
8057 if (!obscured) {
8058 if (w.mSurface != null) {
8059 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8060 holdScreen = w.mSession;
8061 }
Dianne Hackborn2f847b92009-03-25 15:25:33 -07008062 if (!syswin && w.mAttrs.screenBrightness >= 0
8063 && screenBrightness < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008064 screenBrightness = w.mAttrs.screenBrightness;
8065 }
Dianne Hackborn2f847b92009-03-25 15:25:33 -07008066 if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8067 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8068 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
8069 syswin = true;
8070 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008071 }
8072 if (w.isFullscreenOpaque(dw, dh)) {
8073 // This window completely covers everything behind it,
8074 // so we want to leave all of them as unblurred (for
8075 // performance reasons).
8076 obscured = true;
8077 } else if (canBeSeen && !obscured &&
8078 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8079 if (localLOGV) Log.v(TAG, "Win " + w
8080 + ": blurring=" + blurring
8081 + " obscured=" + obscured
8082 + " displayed=" + displayed);
8083 if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8084 if (!dimming) {
8085 //Log.i(TAG, "DIM BEHIND: " + w);
8086 dimming = true;
8087 mDimShown = true;
8088 if (mDimSurface == null) {
8089 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8090 + mDimSurface + ": CREATE");
8091 try {
8092 mDimSurface = new Surface(mFxSession, 0,
8093 -1, 16, 16,
8094 PixelFormat.OPAQUE,
8095 Surface.FX_SURFACE_DIM);
8096 } catch (Exception e) {
8097 Log.e(TAG, "Exception creating Dim surface", e);
8098 }
8099 }
8100 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8101 + mDimSurface + ": SHOW pos=(0,0) (" +
8102 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8103 if (mDimSurface != null) {
8104 try {
8105 mDimSurface.setPosition(0, 0);
8106 mDimSurface.setSize(dw, dh);
8107 mDimSurface.show();
8108 } catch (RuntimeException e) {
8109 Log.w(TAG, "Failure showing dim surface", e);
8110 }
8111 }
8112 }
8113 mDimSurface.setLayer(w.mAnimLayer-1);
8114 final float target = w.mExiting ? 0 : attrs.dimAmount;
8115 if (mDimTargetAlpha != target) {
8116 // If the desired dim level has changed, then
8117 // start an animation to it.
8118 mLastDimAnimTime = currentTime;
8119 long duration = (w.mAnimating && w.mAnimation != null)
8120 ? w.mAnimation.computeDurationHint()
8121 : DEFAULT_DIM_DURATION;
8122 if (target > mDimTargetAlpha) {
8123 // This is happening behind the activity UI,
8124 // so we can make it run a little longer to
8125 // give a stronger impression without disrupting
8126 // the user.
8127 duration *= DIM_DURATION_MULTIPLIER;
8128 }
8129 if (duration < 1) {
8130 // Don't divide by zero
8131 duration = 1;
8132 }
8133 mDimTargetAlpha = target;
8134 mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha)
8135 / duration;
8136 }
8137 }
8138 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8139 if (!blurring) {
8140 //Log.i(TAG, "BLUR BEHIND: " + w);
8141 blurring = true;
8142 mBlurShown = true;
8143 if (mBlurSurface == null) {
8144 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8145 + mBlurSurface + ": CREATE");
8146 try {
8147 mBlurSurface = new Surface(mFxSession, 0,
8148 -1, 16, 16,
8149 PixelFormat.OPAQUE,
8150 Surface.FX_SURFACE_BLUR);
8151 } catch (Exception e) {
8152 Log.e(TAG, "Exception creating Blur surface", e);
8153 }
8154 }
8155 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8156 + mBlurSurface + ": SHOW pos=(0,0) (" +
8157 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8158 if (mBlurSurface != null) {
8159 mBlurSurface.setPosition(0, 0);
8160 mBlurSurface.setSize(dw, dh);
8161 try {
8162 mBlurSurface.show();
8163 } catch (RuntimeException e) {
8164 Log.w(TAG, "Failure showing blur surface", e);
8165 }
8166 }
8167 }
8168 mBlurSurface.setLayer(w.mAnimLayer-2);
8169 }
8170 }
8171 }
8172 }
8173
8174 if (!dimming && mDimShown) {
8175 // Time to hide the dim surface... start fading.
8176 if (mDimTargetAlpha != 0) {
8177 mLastDimAnimTime = currentTime;
8178 mDimTargetAlpha = 0;
8179 mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
8180 }
8181 }
8182
8183 if (mDimShown && mLastDimAnimTime != 0) {
8184 mDimCurrentAlpha += mDimDeltaPerMs
8185 * (currentTime-mLastDimAnimTime);
8186 boolean more = true;
8187 if (mDisplayFrozen) {
8188 // If the display is frozen, there is no reason to animate.
8189 more = false;
8190 } else if (mDimDeltaPerMs > 0) {
8191 if (mDimCurrentAlpha > mDimTargetAlpha) {
8192 more = false;
8193 }
8194 } else if (mDimDeltaPerMs < 0) {
8195 if (mDimCurrentAlpha < mDimTargetAlpha) {
8196 more = false;
8197 }
8198 } else {
8199 more = false;
8200 }
8201
8202 // Do we need to continue animating?
8203 if (more) {
8204 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8205 + mDimSurface + ": alpha=" + mDimCurrentAlpha);
8206 mLastDimAnimTime = currentTime;
8207 mDimSurface.setAlpha(mDimCurrentAlpha);
8208 animating = true;
8209 } else {
8210 mDimCurrentAlpha = mDimTargetAlpha;
8211 mLastDimAnimTime = 0;
8212 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8213 + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
8214 mDimSurface.setAlpha(mDimCurrentAlpha);
8215 if (!dimming) {
8216 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
8217 + ": HIDE");
8218 try {
8219 mDimSurface.hide();
8220 } catch (RuntimeException e) {
8221 Log.w(TAG, "Illegal argument exception hiding dim surface");
8222 }
8223 mDimShown = false;
8224 }
8225 }
8226 }
8227
8228 if (!blurring && mBlurShown) {
8229 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
8230 + ": HIDE");
8231 try {
8232 mBlurSurface.hide();
8233 } catch (IllegalArgumentException e) {
8234 Log.w(TAG, "Illegal argument exception hiding blur surface");
8235 }
8236 mBlurShown = false;
8237 }
8238
8239 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
8240 } catch (RuntimeException e) {
8241 Log.e(TAG, "Unhandled exception in Window Manager", e);
8242 }
8243
8244 Surface.closeTransaction();
8245
8246 if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
8247 "With display frozen, orientationChangeComplete="
8248 + orientationChangeComplete);
8249 if (orientationChangeComplete) {
8250 if (mWindowsFreezingScreen) {
8251 mWindowsFreezingScreen = false;
8252 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8253 }
8254 if (mAppsFreezingScreen == 0) {
8255 stopFreezingDisplayLocked();
8256 }
8257 }
8258
8259 i = mResizingWindows.size();
8260 if (i > 0) {
8261 do {
8262 i--;
8263 WindowState win = mResizingWindows.get(i);
8264 try {
8265 win.mClient.resized(win.mFrame.width(),
8266 win.mFrame.height(), win.mLastContentInsets,
8267 win.mLastVisibleInsets, win.mDrawPending);
8268 win.mContentInsetsChanged = false;
8269 win.mVisibleInsetsChanged = false;
8270 } catch (RemoteException e) {
8271 win.mOrientationChanging = false;
8272 }
8273 } while (i > 0);
8274 mResizingWindows.clear();
8275 }
8276
8277 // Destroy the surface of any windows that are no longer visible.
8278 i = mDestroySurface.size();
8279 if (i > 0) {
8280 do {
8281 i--;
8282 WindowState win = mDestroySurface.get(i);
8283 win.mDestroying = false;
8284 if (mInputMethodWindow == win) {
8285 mInputMethodWindow = null;
8286 }
8287 win.destroySurfaceLocked();
8288 } while (i > 0);
8289 mDestroySurface.clear();
8290 }
8291
8292 // Time to remove any exiting tokens?
8293 for (i=mExitingTokens.size()-1; i>=0; i--) {
8294 WindowToken token = mExitingTokens.get(i);
8295 if (!token.hasVisible) {
8296 mExitingTokens.remove(i);
8297 }
8298 }
8299
8300 // Time to remove any exiting applications?
8301 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8302 AppWindowToken token = mExitingAppTokens.get(i);
8303 if (!token.hasVisible && !mClosingApps.contains(token)) {
8304 mAppTokens.remove(token);
8305 mExitingAppTokens.remove(i);
8306 }
8307 }
8308
8309 if (focusDisplayed) {
8310 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8311 }
8312 if (animating) {
8313 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8314 }
8315 mQueue.setHoldScreenLocked(holdScreen != null);
8316 if (screenBrightness < 0 || screenBrightness > 1.0f) {
8317 mPowerManager.setScreenBrightnessOverride(-1);
8318 } else {
8319 mPowerManager.setScreenBrightnessOverride((int)
8320 (screenBrightness * Power.BRIGHTNESS_ON));
8321 }
8322 if (holdScreen != mHoldingScreenOn) {
8323 mHoldingScreenOn = holdScreen;
8324 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8325 mH.sendMessage(m);
8326 }
8327 }
8328
8329 void requestAnimationLocked(long delay) {
8330 if (!mAnimationPending) {
8331 mAnimationPending = true;
8332 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8333 }
8334 }
8335
8336 /**
8337 * Have the surface flinger show a surface, robustly dealing with
8338 * error conditions. In particular, if there is not enough memory
8339 * to show the surface, then we will try to get rid of other surfaces
8340 * in order to succeed.
8341 *
8342 * @return Returns true if the surface was successfully shown.
8343 */
8344 boolean showSurfaceRobustlyLocked(WindowState win) {
8345 try {
8346 if (win.mSurface != null) {
8347 win.mSurface.show();
8348 }
8349 return true;
8350 } catch (RuntimeException e) {
8351 Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
8352 }
8353
8354 reclaimSomeSurfaceMemoryLocked(win, "show");
8355
8356 return false;
8357 }
8358
8359 void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
8360 final Surface surface = win.mSurface;
8361
8362 EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
8363 win.mSession.mPid, operation);
8364
8365 if (mForceRemoves == null) {
8366 mForceRemoves = new ArrayList<WindowState>();
8367 }
8368
8369 long callingIdentity = Binder.clearCallingIdentity();
8370 try {
8371 // There was some problem... first, do a sanity check of the
8372 // window list to make sure we haven't left any dangling surfaces
8373 // around.
8374 int N = mWindows.size();
8375 boolean leakedSurface = false;
8376 Log.i(TAG, "Out of memory for surface! Looking for leaks...");
8377 for (int i=0; i<N; i++) {
8378 WindowState ws = (WindowState)mWindows.get(i);
8379 if (ws.mSurface != null) {
8380 if (!mSessions.contains(ws.mSession)) {
8381 Log.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8382 + ws + " surface=" + ws.mSurface
8383 + " token=" + win.mToken
8384 + " pid=" + ws.mSession.mPid
8385 + " uid=" + ws.mSession.mUid);
8386 ws.mSurface.clear();
8387 ws.mSurface = null;
8388 mForceRemoves.add(ws);
8389 i--;
8390 N--;
8391 leakedSurface = true;
8392 } else if (win.mAppToken != null && win.mAppToken.clientHidden) {
8393 Log.w(TAG, "LEAKED SURFACE (app token hidden): "
8394 + ws + " surface=" + ws.mSurface
8395 + " token=" + win.mAppToken);
8396 ws.mSurface.clear();
8397 ws.mSurface = null;
8398 leakedSurface = true;
8399 }
8400 }
8401 }
8402
8403 boolean killedApps = false;
8404 if (!leakedSurface) {
8405 Log.w(TAG, "No leaked surfaces; killing applicatons!");
8406 SparseIntArray pidCandidates = new SparseIntArray();
8407 for (int i=0; i<N; i++) {
8408 WindowState ws = (WindowState)mWindows.get(i);
8409 if (ws.mSurface != null) {
8410 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8411 }
8412 }
8413 if (pidCandidates.size() > 0) {
8414 int[] pids = new int[pidCandidates.size()];
8415 for (int i=0; i<pids.length; i++) {
8416 pids[i] = pidCandidates.keyAt(i);
8417 }
8418 try {
8419 if (mActivityManager.killPidsForMemory(pids)) {
8420 killedApps = true;
8421 }
8422 } catch (RemoteException e) {
8423 }
8424 }
8425 }
8426
8427 if (leakedSurface || killedApps) {
8428 // We managed to reclaim some memory, so get rid of the trouble
8429 // surface and ask the app to request another one.
8430 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8431 if (surface != null) {
8432 surface.clear();
8433 win.mSurface = null;
8434 }
8435
8436 try {
8437 win.mClient.dispatchGetNewSurface();
8438 } catch (RemoteException e) {
8439 }
8440 }
8441 } finally {
8442 Binder.restoreCallingIdentity(callingIdentity);
8443 }
8444 }
8445
8446 private boolean updateFocusedWindowLocked(int mode) {
8447 WindowState newFocus = computeFocusedWindowLocked();
8448 if (mCurrentFocus != newFocus) {
8449 // This check makes sure that we don't already have the focus
8450 // change message pending.
8451 mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8452 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8453 if (localLOGV) Log.v(
8454 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8455 final WindowState oldFocus = mCurrentFocus;
8456 mCurrentFocus = newFocus;
8457 mLosingFocus.remove(newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008458
8459 final WindowState imWindow = mInputMethodWindow;
8460 if (newFocus != imWindow && oldFocus != imWindow) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008461 if (moveInputMethodWindowsIfNeededLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008462 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008463 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8464 mLayoutNeeded = true;
8465 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008466 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8467 performLayoutLockedInner();
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008468 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8469 // Client will do the layout, but we need to assign layers
8470 // for handleNewWindowLocked() below.
8471 assignLayersLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008472 }
8473 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008474
8475 if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8476 mKeyWaiter.handleNewWindowLocked(newFocus);
8477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008478 return true;
8479 }
8480 return false;
8481 }
8482
8483 private WindowState computeFocusedWindowLocked() {
8484 WindowState result = null;
8485 WindowState win;
8486
8487 int i = mWindows.size() - 1;
8488 int nextAppIndex = mAppTokens.size()-1;
8489 WindowToken nextApp = nextAppIndex >= 0
8490 ? mAppTokens.get(nextAppIndex) : null;
8491
8492 while (i >= 0) {
8493 win = (WindowState)mWindows.get(i);
8494
8495 if (localLOGV || DEBUG_FOCUS) Log.v(
8496 TAG, "Looking for focus: " + i
8497 + " = " + win
8498 + ", flags=" + win.mAttrs.flags
8499 + ", canReceive=" + win.canReceiveKeys());
8500
8501 AppWindowToken thisApp = win.mAppToken;
8502
8503 // If this window's application has been removed, just skip it.
8504 if (thisApp != null && thisApp.removed) {
8505 i--;
8506 continue;
8507 }
8508
8509 // If there is a focused app, don't allow focus to go to any
8510 // windows below it. If this is an application window, step
8511 // through the app tokens until we find its app.
8512 if (thisApp != null && nextApp != null && thisApp != nextApp
8513 && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8514 int origAppIndex = nextAppIndex;
8515 while (nextAppIndex > 0) {
8516 if (nextApp == mFocusedApp) {
8517 // Whoops, we are below the focused app... no focus
8518 // for you!
8519 if (localLOGV || DEBUG_FOCUS) Log.v(
8520 TAG, "Reached focused app: " + mFocusedApp);
8521 return null;
8522 }
8523 nextAppIndex--;
8524 nextApp = mAppTokens.get(nextAppIndex);
8525 if (nextApp == thisApp) {
8526 break;
8527 }
8528 }
8529 if (thisApp != nextApp) {
8530 // Uh oh, the app token doesn't exist! This shouldn't
8531 // happen, but if it does we can get totally hosed...
8532 // so restart at the original app.
8533 nextAppIndex = origAppIndex;
8534 nextApp = mAppTokens.get(nextAppIndex);
8535 }
8536 }
8537
8538 // Dispatch to this window if it is wants key events.
8539 if (win.canReceiveKeys()) {
8540 if (DEBUG_FOCUS) Log.v(
8541 TAG, "Found focus @ " + i + " = " + win);
8542 result = win;
8543 break;
8544 }
8545
8546 i--;
8547 }
8548
8549 return result;
8550 }
8551
8552 private void startFreezingDisplayLocked() {
8553 if (mDisplayFrozen) {
Chris Tate0f8fc102009-03-25 16:22:54 -07008554 // Freezing the display also suspends key event delivery, to
8555 // keep events from going astray while the display is reconfigured.
8556 // If someone has changed orientation again while the screen is
8557 // still frozen, the events will continue to be blocked while the
8558 // successive orientation change is processed. To prevent spurious
8559 // ANRs, we reset the event dispatch timeout in this case.
8560 synchronized (mKeyWaiter) {
8561 mKeyWaiter.mWasFrozen = true;
8562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008563 return;
8564 }
8565
8566 mScreenFrozenLock.acquire();
8567
8568 long now = SystemClock.uptimeMillis();
8569 //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8570 if (mFreezeGcPending != 0) {
8571 if (now > (mFreezeGcPending+1000)) {
8572 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
8573 mH.removeMessages(H.FORCE_GC);
8574 Runtime.getRuntime().gc();
8575 mFreezeGcPending = now;
8576 }
8577 } else {
8578 mFreezeGcPending = now;
8579 }
8580
8581 mDisplayFrozen = true;
8582 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
8583 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8584 mAppTransitionReady = true;
8585 }
8586
8587 if (PROFILE_ORIENTATION) {
8588 File file = new File("/data/system/frozen");
8589 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8590 }
8591 Surface.freezeDisplay(0);
8592 }
8593
8594 private void stopFreezingDisplayLocked() {
8595 if (!mDisplayFrozen) {
8596 return;
8597 }
8598
8599 mDisplayFrozen = false;
8600 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8601 if (PROFILE_ORIENTATION) {
8602 Debug.stopMethodTracing();
8603 }
8604 Surface.unfreezeDisplay(0);
8605
Chris Tate0f8fc102009-03-25 16:22:54 -07008606 // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
8607 // too because regular key delivery processing should resume immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008608 synchronized (mKeyWaiter) {
8609 mKeyWaiter.mWasFrozen = true;
8610 mKeyWaiter.notifyAll();
8611 }
8612
8613 // A little kludge: a lot could have happened while the
8614 // display was frozen, so now that we are coming back we
8615 // do a gc so that any remote references the system
8616 // processes holds on others can be released if they are
8617 // no longer needed.
8618 mH.removeMessages(H.FORCE_GC);
8619 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8620 2000);
8621
8622 mScreenFrozenLock.release();
8623 }
8624
8625 @Override
8626 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8627 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
8628 != PackageManager.PERMISSION_GRANTED) {
8629 pw.println("Permission Denial: can't dump WindowManager from from pid="
8630 + Binder.getCallingPid()
8631 + ", uid=" + Binder.getCallingUid());
8632 return;
8633 }
8634
8635 synchronized(mWindowMap) {
8636 pw.println("Current Window Manager state:");
8637 for (int i=mWindows.size()-1; i>=0; i--) {
8638 WindowState w = (WindowState)mWindows.get(i);
8639 pw.println(" Window #" + i + ":");
8640 w.dump(pw, " ");
8641 }
8642 if (mInputMethodDialogs.size() > 0) {
8643 pw.println(" ");
8644 pw.println(" Input method dialogs:");
8645 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
8646 WindowState w = mInputMethodDialogs.get(i);
8647 pw.println(" IM Dialog #" + i + ": " + w);
8648 }
8649 }
8650 if (mPendingRemove.size() > 0) {
8651 pw.println(" ");
8652 pw.println(" Remove pending for:");
8653 for (int i=mPendingRemove.size()-1; i>=0; i--) {
8654 WindowState w = mPendingRemove.get(i);
8655 pw.println(" Remove #" + i + ":");
8656 w.dump(pw, " ");
8657 }
8658 }
8659 if (mForceRemoves != null && mForceRemoves.size() > 0) {
8660 pw.println(" ");
8661 pw.println(" Windows force removing:");
8662 for (int i=mForceRemoves.size()-1; i>=0; i--) {
8663 WindowState w = mForceRemoves.get(i);
8664 pw.println(" Removing #" + i + ":");
8665 w.dump(pw, " ");
8666 }
8667 }
8668 if (mDestroySurface.size() > 0) {
8669 pw.println(" ");
8670 pw.println(" Windows waiting to destroy their surface:");
8671 for (int i=mDestroySurface.size()-1; i>=0; i--) {
8672 WindowState w = mDestroySurface.get(i);
8673 pw.println(" Destroy #" + i + ":");
8674 w.dump(pw, " ");
8675 }
8676 }
8677 if (mLosingFocus.size() > 0) {
8678 pw.println(" ");
8679 pw.println(" Windows losing focus:");
8680 for (int i=mLosingFocus.size()-1; i>=0; i--) {
8681 WindowState w = mLosingFocus.get(i);
8682 pw.println(" Losing #" + i + ":");
8683 w.dump(pw, " ");
8684 }
8685 }
8686 if (mSessions.size() > 0) {
8687 pw.println(" ");
8688 pw.println(" All active sessions:");
8689 Iterator<Session> it = mSessions.iterator();
8690 while (it.hasNext()) {
8691 Session s = it.next();
8692 pw.println(" Session " + s);
8693 s.dump(pw, " ");
8694 }
8695 }
8696 if (mTokenMap.size() > 0) {
8697 pw.println(" ");
8698 pw.println(" All tokens:");
8699 Iterator<WindowToken> it = mTokenMap.values().iterator();
8700 while (it.hasNext()) {
8701 WindowToken token = it.next();
8702 pw.println(" Token " + token.token);
8703 token.dump(pw, " ");
8704 }
8705 }
8706 if (mTokenList.size() > 0) {
8707 pw.println(" ");
8708 pw.println(" Window token list:");
8709 for (int i=0; i<mTokenList.size(); i++) {
8710 pw.println(" WindowToken #" + i + ": " + mTokenList.get(i));
8711 }
8712 }
8713 if (mAppTokens.size() > 0) {
8714 pw.println(" ");
8715 pw.println(" Application tokens in Z order:");
8716 for (int i=mAppTokens.size()-1; i>=0; i--) {
8717 pw.println(" AppWindowToken #" + i + ": " + mAppTokens.get(i));
8718 }
8719 }
8720 if (mFinishedStarting.size() > 0) {
8721 pw.println(" ");
8722 pw.println(" Finishing start of application tokens:");
8723 for (int i=mFinishedStarting.size()-1; i>=0; i--) {
8724 WindowToken token = mFinishedStarting.get(i);
8725 pw.println(" Finish Starting App Token #" + i + ":");
8726 token.dump(pw, " ");
8727 }
8728 }
8729 if (mExitingTokens.size() > 0) {
8730 pw.println(" ");
8731 pw.println(" Exiting tokens:");
8732 for (int i=mExitingTokens.size()-1; i>=0; i--) {
8733 WindowToken token = mExitingTokens.get(i);
8734 pw.println(" Exiting Token #" + i + ":");
8735 token.dump(pw, " ");
8736 }
8737 }
8738 if (mExitingAppTokens.size() > 0) {
8739 pw.println(" ");
8740 pw.println(" Exiting application tokens:");
8741 for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
8742 WindowToken token = mExitingAppTokens.get(i);
8743 pw.println(" Exiting App Token #" + i + ":");
8744 token.dump(pw, " ");
8745 }
8746 }
8747 pw.println(" ");
8748 pw.println(" mCurrentFocus=" + mCurrentFocus);
8749 pw.println(" mLastFocus=" + mLastFocus);
8750 pw.println(" mFocusedApp=" + mFocusedApp);
8751 pw.println(" mInputMethodTarget=" + mInputMethodTarget);
8752 pw.println(" mInputMethodWindow=" + mInputMethodWindow);
8753 pw.println(" mInTouchMode=" + mInTouchMode);
8754 pw.println(" mSystemBooted=" + mSystemBooted
8755 + " mDisplayEnabled=" + mDisplayEnabled);
8756 pw.println(" mLayoutNeeded=" + mLayoutNeeded
8757 + " mBlurShown=" + mBlurShown);
8758 pw.println(" mDimShown=" + mDimShown
8759 + " current=" + mDimCurrentAlpha
8760 + " target=" + mDimTargetAlpha
8761 + " delta=" + mDimDeltaPerMs
8762 + " lastAnimTime=" + mLastDimAnimTime);
8763 pw.println(" mInputMethodAnimLayerAdjustment="
8764 + mInputMethodAnimLayerAdjustment);
8765 pw.println(" mDisplayFrozen=" + mDisplayFrozen
8766 + " mWindowsFreezingScreen=" + mWindowsFreezingScreen
8767 + " mAppsFreezingScreen=" + mAppsFreezingScreen);
8768 pw.println(" mRotation=" + mRotation
8769 + ", mForcedAppOrientation=" + mForcedAppOrientation
8770 + ", mRequestedRotation=" + mRequestedRotation);
8771 pw.println(" mAnimationPending=" + mAnimationPending
8772 + " mWindowAnimationScale=" + mWindowAnimationScale
8773 + " mTransitionWindowAnimationScale=" + mTransitionAnimationScale);
8774 pw.println(" mNextAppTransition=0x"
8775 + Integer.toHexString(mNextAppTransition)
8776 + ", mAppTransitionReady=" + mAppTransitionReady
8777 + ", mAppTransitionTimeout=" + mAppTransitionTimeout);
8778 pw.println(" mStartingIconInTransition=" + mStartingIconInTransition
8779 + ", mSkipAppTransitionAnimation=" + mSkipAppTransitionAnimation);
8780 pw.println(" mOpeningApps=" + mOpeningApps);
8781 pw.println(" mClosingApps=" + mClosingApps);
8782 pw.println(" DisplayWidth=" + mDisplay.getWidth()
8783 + " DisplayHeight=" + mDisplay.getHeight());
8784 pw.println(" KeyWaiter state:");
8785 pw.println(" mLastWin=" + mKeyWaiter.mLastWin
8786 + " mLastBinder=" + mKeyWaiter.mLastBinder);
8787 pw.println(" mFinished=" + mKeyWaiter.mFinished
8788 + " mGotFirstWindow=" + mKeyWaiter.mGotFirstWindow
8789 + " mEventDispatching=" + mKeyWaiter.mEventDispatching
8790 + " mTimeToSwitch=" + mKeyWaiter.mTimeToSwitch);
8791 }
8792 }
8793
8794 public void monitor() {
8795 synchronized (mWindowMap) { }
8796 synchronized (mKeyguardDisabled) { }
8797 synchronized (mKeyWaiter) { }
8798 }
8799}