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