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