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