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