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