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