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