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