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