blob: ad882a95304ffc0d529013acd1506cf7ebf3bb82 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static android.os.LocalPowerManager.CHEEK_EVENT;
20import static android.os.LocalPowerManager.OTHER_EVENT;
21import static android.os.LocalPowerManager.TOUCH_EVENT;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -070022import static android.os.LocalPowerManager.LONG_TOUCH_EVENT;
23import static android.os.LocalPowerManager.TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
25import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
26import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
27import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
28import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
29import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
30import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
31import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
32import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
33import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
34import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
35import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
36import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
37import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
38import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
39import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
40import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
41
42import com.android.internal.app.IBatteryStats;
43import com.android.internal.policy.PolicyManager;
44import com.android.internal.view.IInputContext;
45import com.android.internal.view.IInputMethodClient;
46import com.android.internal.view.IInputMethodManager;
47import com.android.server.KeyInputQueue.QueuedEvent;
48import com.android.server.am.BatteryStatsService;
49
50import android.Manifest;
51import android.app.ActivityManagerNative;
52import android.app.IActivityManager;
53import android.content.Context;
54import android.content.pm.ActivityInfo;
55import android.content.pm.PackageManager;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -070056import android.content.res.CompatibilityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.content.res.Configuration;
58import android.graphics.Matrix;
59import android.graphics.PixelFormat;
60import android.graphics.Rect;
61import android.graphics.Region;
62import android.os.BatteryStats;
63import android.os.Binder;
64import android.os.Debug;
65import android.os.Handler;
66import android.os.IBinder;
67import android.os.LocalPowerManager;
68import android.os.Looper;
69import android.os.Message;
70import android.os.Parcel;
71import android.os.ParcelFileDescriptor;
72import android.os.Power;
73import android.os.PowerManager;
74import android.os.Process;
75import android.os.RemoteException;
76import android.os.ServiceManager;
77import android.os.SystemClock;
78import android.os.SystemProperties;
79import android.os.TokenWatcher;
80import android.provider.Settings;
Dianne Hackborn723738c2009-06-25 19:48:04 -070081import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.util.EventLog;
83import android.util.Log;
84import android.util.SparseIntArray;
85import android.view.Display;
86import android.view.Gravity;
87import android.view.IApplicationToken;
88import android.view.IOnKeyguardExitResult;
89import android.view.IRotationWatcher;
90import android.view.IWindow;
91import android.view.IWindowManager;
92import android.view.IWindowSession;
93import android.view.KeyEvent;
94import android.view.MotionEvent;
95import android.view.RawInputEvent;
96import android.view.Surface;
97import android.view.SurfaceSession;
98import android.view.View;
99import android.view.ViewTreeObserver;
100import android.view.WindowManager;
101import android.view.WindowManagerImpl;
102import android.view.WindowManagerPolicy;
103import android.view.WindowManager.LayoutParams;
104import android.view.animation.Animation;
105import android.view.animation.AnimationUtils;
106import android.view.animation.Transformation;
107
108import java.io.BufferedWriter;
109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.IOException;
112import java.io.OutputStream;
113import java.io.OutputStreamWriter;
114import java.io.PrintWriter;
115import java.io.StringWriter;
116import java.net.Socket;
117import java.util.ArrayList;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Iterator;
121import java.util.List;
122
123/** {@hide} */
124public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
125 static final String TAG = "WindowManager";
126 static final boolean DEBUG = false;
127 static final boolean DEBUG_FOCUS = false;
128 static final boolean DEBUG_ANIM = false;
129 static final boolean DEBUG_LAYERS = false;
130 static final boolean DEBUG_INPUT = false;
131 static final boolean DEBUG_INPUT_METHOD = false;
132 static final boolean DEBUG_VISIBILITY = false;
133 static final boolean DEBUG_ORIENTATION = false;
134 static final boolean DEBUG_APP_TRANSITIONS = false;
135 static final boolean DEBUG_STARTING_WINDOW = false;
136 static final boolean DEBUG_REORDER = false;
137 static final boolean SHOW_TRANSACTIONS = false;
Romain Guy06882f82009-06-10 13:36:04 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean PROFILE_ORIENTATION = false;
140 static final boolean BLUR = true;
Dave Bortcfe65242009-04-09 14:51:04 -0700141 static final boolean localLOGV = DEBUG;
Romain Guy06882f82009-06-10 13:36:04 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
Romain Guy06882f82009-06-10 13:36:04 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 /** How long to wait for first key repeat, in milliseconds */
146 static final int KEY_REPEAT_FIRST_DELAY = 750;
Romain Guy06882f82009-06-10 13:36:04 -0700147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 /** How long to wait for subsequent key repeats, in milliseconds */
149 static final int KEY_REPEAT_DELAY = 50;
150
151 /** How much to multiply the policy's type layer, to reserve room
152 * for multiple windows of the same type and Z-ordering adjustment
153 * with TYPE_LAYER_OFFSET. */
154 static final int TYPE_LAYER_MULTIPLIER = 10000;
Romain Guy06882f82009-06-10 13:36:04 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
157 * or below others in the same layer. */
158 static final int TYPE_LAYER_OFFSET = 1000;
Romain Guy06882f82009-06-10 13:36:04 -0700159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 /** How much to increment the layer for each window, to reserve room
161 * for effect surfaces between them.
162 */
163 static final int WINDOW_LAYER_MULTIPLIER = 5;
Romain Guy06882f82009-06-10 13:36:04 -0700164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 /** The maximum length we will accept for a loaded animation duration:
166 * this is 10 seconds.
167 */
168 static final int MAX_ANIMATION_DURATION = 10*1000;
169
170 /** Amount of time (in milliseconds) to animate the dim surface from one
171 * value to another, when no window animation is driving it.
172 */
173 static final int DEFAULT_DIM_DURATION = 200;
174
175 /** Adjustment to time to perform a dim, to make it more dramatic.
176 */
177 static final int DIM_DURATION_MULTIPLIER = 6;
Romain Guy06882f82009-06-10 13:36:04 -0700178
Dianne Hackborncfaef692009-06-15 14:24:44 -0700179 static final int INJECT_FAILED = 0;
180 static final int INJECT_SUCCEEDED = 1;
181 static final int INJECT_NO_PERMISSION = -1;
182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 static final int UPDATE_FOCUS_NORMAL = 0;
184 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
185 static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
186 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
Romain Guy06882f82009-06-10 13:36:04 -0700187
Michael Chane96440f2009-05-06 10:27:36 -0700188 /** The minimum time between dispatching touch events. */
189 int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
190
191 // Last touch event time
192 long mLastTouchEventTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700193
Michael Chane96440f2009-05-06 10:27:36 -0700194 // Last touch event type
195 int mLastTouchEventType = OTHER_EVENT;
Romain Guy06882f82009-06-10 13:36:04 -0700196
Michael Chane96440f2009-05-06 10:27:36 -0700197 // Time to wait before calling useractivity again. This saves CPU usage
198 // when we get a flood of touch events.
199 static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
200
201 // Last time we call user activity
202 long mLastUserActivityCallTime = 0;
203
Romain Guy06882f82009-06-10 13:36:04 -0700204 // Last time we updated battery stats
Michael Chane96440f2009-05-06 10:27:36 -0700205 long mLastBatteryStatsCallTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 private static final String SYSTEM_SECURE = "ro.secure";
Romain Guy06882f82009-06-10 13:36:04 -0700208 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209
210 /**
211 * Condition waited on by {@link #reenableKeyguard} to know the call to
212 * the window policy has finished.
213 */
214 private boolean mWaitingUntilKeyguardReenabled = false;
215
216
217 final TokenWatcher mKeyguardDisabled = new TokenWatcher(
218 new Handler(), "WindowManagerService.mKeyguardDisabled") {
219 public void acquired() {
220 mPolicy.enableKeyguard(false);
221 }
222 public void released() {
223 synchronized (mKeyguardDisabled) {
224 mPolicy.enableKeyguard(true);
225 mWaitingUntilKeyguardReenabled = false;
226 mKeyguardDisabled.notifyAll();
227 }
228 }
229 };
230
231 final Context mContext;
232
233 final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 final boolean mLimitedAlphaCompositing;
Romain Guy06882f82009-06-10 13:36:04 -0700236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
238
239 final IActivityManager mActivityManager;
Romain Guy06882f82009-06-10 13:36:04 -0700240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 final IBatteryStats mBatteryStats;
Romain Guy06882f82009-06-10 13:36:04 -0700242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 /**
244 * All currently active sessions with clients.
245 */
246 final HashSet<Session> mSessions = new HashSet<Session>();
Romain Guy06882f82009-06-10 13:36:04 -0700247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 /**
249 * Mapping from an IWindow IBinder to the server's Window object.
250 * This is also used as the lock for all of our state.
251 */
252 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
253
254 /**
255 * Mapping from a token IBinder to a WindowToken object.
256 */
257 final HashMap<IBinder, WindowToken> mTokenMap =
258 new HashMap<IBinder, WindowToken>();
259
260 /**
261 * The same tokens as mTokenMap, stored in a list for efficient iteration
262 * over them.
263 */
264 final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 /**
267 * Window tokens that are in the process of exiting, but still
268 * on screen for animations.
269 */
270 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
271
272 /**
273 * Z-ordered (bottom-most first) list of all application tokens, for
274 * controlling the ordering of windows in different applications. This
275 * contains WindowToken objects.
276 */
277 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
278
279 /**
280 * Application tokens that are in the process of exiting, but still
281 * on screen for animations.
282 */
283 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
284
285 /**
286 * List of window tokens that have finished starting their application,
287 * and now need to have the policy remove their windows.
288 */
289 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
290
291 /**
292 * Z-ordered (bottom-most first) list of all Window objects.
293 */
294 final ArrayList mWindows = new ArrayList();
295
296 /**
297 * Windows that are being resized. Used so we can tell the client about
298 * the resize after closing the transaction in which we resized the
299 * underlying surface.
300 */
301 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
302
303 /**
304 * Windows whose animations have ended and now must be removed.
305 */
306 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
307
308 /**
309 * Windows whose surface should be destroyed.
310 */
311 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
312
313 /**
314 * Windows that have lost input focus and are waiting for the new
315 * focus window to be displayed before they are told about this.
316 */
317 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
318
319 /**
320 * This is set when we have run out of memory, and will either be an empty
321 * list or contain windows that need to be force removed.
322 */
323 ArrayList<WindowState> mForceRemoves;
Romain Guy06882f82009-06-10 13:36:04 -0700324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 IInputMethodManager mInputMethodManager;
Romain Guy06882f82009-06-10 13:36:04 -0700326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 SurfaceSession mFxSession;
328 Surface mDimSurface;
329 boolean mDimShown;
330 float mDimCurrentAlpha;
331 float mDimTargetAlpha;
332 float mDimDeltaPerMs;
333 long mLastDimAnimTime;
334 Surface mBlurSurface;
335 boolean mBlurShown;
Romain Guy06882f82009-06-10 13:36:04 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 int mTransactionSequence = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 final float[] mTmpFloats = new float[9];
340
341 boolean mSafeMode;
342 boolean mDisplayEnabled = false;
343 boolean mSystemBooted = false;
344 int mRotation = 0;
345 int mRequestedRotation = 0;
346 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Dianne Hackborn321ae682009-03-27 16:16:03 -0700347 int mLastRotationFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 ArrayList<IRotationWatcher> mRotationWatchers
349 = new ArrayList<IRotationWatcher>();
Romain Guy06882f82009-06-10 13:36:04 -0700350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 boolean mLayoutNeeded = true;
352 boolean mAnimationPending = false;
353 boolean mDisplayFrozen = false;
354 boolean mWindowsFreezingScreen = false;
355 long mFreezeGcPending = 0;
356 int mAppsFreezingScreen = 0;
357
358 // This is held as long as we have the screen frozen, to give us time to
359 // perform a rotation animation when turning off shows the lock screen which
360 // changes the orientation.
361 PowerManager.WakeLock mScreenFrozenLock;
Romain Guy06882f82009-06-10 13:36:04 -0700362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 // State management of app transitions. When we are preparing for a
364 // transition, mNextAppTransition will be the kind of transition to
365 // perform or TRANSIT_NONE if we are not waiting. If we are waiting,
366 // mOpeningApps and mClosingApps are the lists of tokens that will be
367 // made visible or hidden at the next transition.
368 int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
369 boolean mAppTransitionReady = false;
370 boolean mAppTransitionTimeout = false;
371 boolean mStartingIconInTransition = false;
372 boolean mSkipAppTransitionAnimation = false;
373 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
374 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 //flag to detect fat touch events
377 boolean mFatTouch = false;
378 Display mDisplay;
Romain Guy06882f82009-06-10 13:36:04 -0700379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 H mH = new H();
381
382 WindowState mCurrentFocus = null;
383 WindowState mLastFocus = null;
Romain Guy06882f82009-06-10 13:36:04 -0700384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 // This just indicates the window the input method is on top of, not
386 // necessarily the window its input is going to.
387 WindowState mInputMethodTarget = null;
388 WindowState mUpcomingInputMethodTarget = null;
389 boolean mInputMethodTargetWaitingAnim;
390 int mInputMethodAnimLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -0700391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 WindowState mInputMethodWindow = null;
393 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
394
395 AppWindowToken mFocusedApp = null;
396
397 PowerManagerService mPowerManager;
Romain Guy06882f82009-06-10 13:36:04 -0700398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 float mWindowAnimationScale = 1.0f;
400 float mTransitionAnimationScale = 1.0f;
Romain Guy06882f82009-06-10 13:36:04 -0700401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 final KeyWaiter mKeyWaiter = new KeyWaiter();
403 final KeyQ mQueue;
404 final InputDispatcherThread mInputThread;
405
406 // Who is holding the screen on.
407 Session mHoldingScreenOn;
Romain Guy06882f82009-06-10 13:36:04 -0700408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 /**
410 * Whether the UI is currently running in touch mode (not showing
411 * navigational focus because the user is directly pressing the screen).
412 */
413 boolean mInTouchMode = false;
414
415 private ViewServer mViewServer;
416
417 final Rect mTempRect = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -0700418
Dianne Hackbornc485a602009-03-24 22:39:49 -0700419 final Configuration mTempConfiguration = new Configuration();
Dianne Hackborn723738c2009-06-25 19:48:04 -0700420 int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700421
422 // The frame use to limit the size of the app running in compatibility mode.
423 Rect mCompatibleScreenFrame = new Rect();
424 // The surface used to fill the outer rim of the app running in compatibility mode.
425 Surface mBackgroundFillerSurface = null;
426 boolean mBackgroundFillerShown = false;
427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 public static WindowManagerService main(Context context,
429 PowerManagerService pm, boolean haveInputMethods) {
430 WMThread thr = new WMThread(context, pm, haveInputMethods);
431 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 synchronized (thr) {
434 while (thr.mService == null) {
435 try {
436 thr.wait();
437 } catch (InterruptedException e) {
438 }
439 }
440 }
Romain Guy06882f82009-06-10 13:36:04 -0700441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 return thr.mService;
443 }
Romain Guy06882f82009-06-10 13:36:04 -0700444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 static class WMThread extends Thread {
446 WindowManagerService mService;
Romain Guy06882f82009-06-10 13:36:04 -0700447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 private final Context mContext;
449 private final PowerManagerService mPM;
450 private final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 public WMThread(Context context, PowerManagerService pm,
453 boolean haveInputMethods) {
454 super("WindowManager");
455 mContext = context;
456 mPM = pm;
457 mHaveInputMethods = haveInputMethods;
458 }
Romain Guy06882f82009-06-10 13:36:04 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 public void run() {
461 Looper.prepare();
462 WindowManagerService s = new WindowManagerService(mContext, mPM,
463 mHaveInputMethods);
464 android.os.Process.setThreadPriority(
465 android.os.Process.THREAD_PRIORITY_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 synchronized (this) {
468 mService = s;
469 notifyAll();
470 }
Romain Guy06882f82009-06-10 13:36:04 -0700471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 Looper.loop();
473 }
474 }
475
476 static class PolicyThread extends Thread {
477 private final WindowManagerPolicy mPolicy;
478 private final WindowManagerService mService;
479 private final Context mContext;
480 private final PowerManagerService mPM;
481 boolean mRunning = false;
Romain Guy06882f82009-06-10 13:36:04 -0700482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 public PolicyThread(WindowManagerPolicy policy,
484 WindowManagerService service, Context context,
485 PowerManagerService pm) {
486 super("WindowManagerPolicy");
487 mPolicy = policy;
488 mService = service;
489 mContext = context;
490 mPM = pm;
491 }
Romain Guy06882f82009-06-10 13:36:04 -0700492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 public void run() {
494 Looper.prepare();
495 //Looper.myLooper().setMessageLogging(new LogPrinter(
496 // Log.VERBOSE, "WindowManagerPolicy"));
497 android.os.Process.setThreadPriority(
498 android.os.Process.THREAD_PRIORITY_FOREGROUND);
499 mPolicy.init(mContext, mService, mPM);
Romain Guy06882f82009-06-10 13:36:04 -0700500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 synchronized (this) {
502 mRunning = true;
503 notifyAll();
504 }
Romain Guy06882f82009-06-10 13:36:04 -0700505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 Looper.loop();
507 }
508 }
509
510 private WindowManagerService(Context context, PowerManagerService pm,
511 boolean haveInputMethods) {
512 mContext = context;
513 mHaveInputMethods = haveInputMethods;
514 mLimitedAlphaCompositing = context.getResources().getBoolean(
515 com.android.internal.R.bool.config_sf_limitedAlpha);
Romain Guy06882f82009-06-10 13:36:04 -0700516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 mPowerManager = pm;
518 mPowerManager.setPolicy(mPolicy);
519 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
520 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
521 "SCREEN_FROZEN");
522 mScreenFrozenLock.setReferenceCounted(false);
523
524 mActivityManager = ActivityManagerNative.getDefault();
525 mBatteryStats = BatteryStatsService.getService();
526
527 // Get persisted window scale setting
528 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
529 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
530 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
531 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
Romain Guy06882f82009-06-10 13:36:04 -0700532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 mQueue = new KeyQ();
534
535 mInputThread = new InputDispatcherThread();
Romain Guy06882f82009-06-10 13:36:04 -0700536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
538 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 synchronized (thr) {
541 while (!thr.mRunning) {
542 try {
543 thr.wait();
544 } catch (InterruptedException e) {
545 }
546 }
547 }
Romain Guy06882f82009-06-10 13:36:04 -0700548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 mInputThread.start();
Romain Guy06882f82009-06-10 13:36:04 -0700550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 // Add ourself to the Watchdog monitors.
552 Watchdog.getInstance().addMonitor(this);
553 }
554
555 @Override
556 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
557 throws RemoteException {
558 try {
559 return super.onTransact(code, data, reply, flags);
560 } catch (RuntimeException e) {
561 // The window manager only throws security exceptions, so let's
562 // log all others.
563 if (!(e instanceof SecurityException)) {
564 Log.e(TAG, "Window Manager Crash", e);
565 }
566 throw e;
567 }
568 }
569
570 private void placeWindowAfter(Object pos, WindowState window) {
571 final int i = mWindows.indexOf(pos);
572 if (localLOGV || DEBUG_FOCUS) Log.v(
573 TAG, "Adding window " + window + " at "
574 + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
575 mWindows.add(i+1, window);
576 }
577
578 private void placeWindowBefore(Object pos, WindowState window) {
579 final int i = mWindows.indexOf(pos);
580 if (localLOGV || DEBUG_FOCUS) Log.v(
581 TAG, "Adding window " + window + " at "
582 + i + " of " + mWindows.size() + " (before " + pos + ")");
583 mWindows.add(i, window);
584 }
585
586 //This method finds out the index of a window that has the same app token as
587 //win. used for z ordering the windows in mWindows
588 private int findIdxBasedOnAppTokens(WindowState win) {
589 //use a local variable to cache mWindows
590 ArrayList localmWindows = mWindows;
591 int jmax = localmWindows.size();
592 if(jmax == 0) {
593 return -1;
594 }
595 for(int j = (jmax-1); j >= 0; j--) {
596 WindowState wentry = (WindowState)localmWindows.get(j);
597 if(wentry.mAppToken == win.mAppToken) {
598 return j;
599 }
600 }
601 return -1;
602 }
Romain Guy06882f82009-06-10 13:36:04 -0700603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
605 final IWindow client = win.mClient;
606 final WindowToken token = win.mToken;
607 final ArrayList localmWindows = mWindows;
Romain Guy06882f82009-06-10 13:36:04 -0700608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 final int N = localmWindows.size();
610 final WindowState attached = win.mAttachedWindow;
611 int i;
612 if (attached == null) {
613 int tokenWindowsPos = token.windows.size();
614 if (token.appWindowToken != null) {
615 int index = tokenWindowsPos-1;
616 if (index >= 0) {
617 // If this application has existing windows, we
618 // simply place the new window on top of them... but
619 // keep the starting window on top.
620 if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
621 // Base windows go behind everything else.
622 placeWindowBefore(token.windows.get(0), win);
623 tokenWindowsPos = 0;
624 } else {
625 AppWindowToken atoken = win.mAppToken;
626 if (atoken != null &&
627 token.windows.get(index) == atoken.startingWindow) {
628 placeWindowBefore(token.windows.get(index), win);
629 tokenWindowsPos--;
630 } else {
631 int newIdx = findIdxBasedOnAppTokens(win);
632 if(newIdx != -1) {
Romain Guy06882f82009-06-10 13:36:04 -0700633 //there is a window above this one associated with the same
634 //apptoken note that the window could be a floating window
635 //that was created later or a window at the top of the list of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 //windows associated with this token.
637 localmWindows.add(newIdx+1, win);
Romain Guy06882f82009-06-10 13:36:04 -0700638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 }
640 }
641 } else {
642 if (localLOGV) Log.v(
643 TAG, "Figuring out where to add app window "
644 + client.asBinder() + " (token=" + token + ")");
645 // Figure out where the window should go, based on the
646 // order of applications.
647 final int NA = mAppTokens.size();
648 Object pos = null;
649 for (i=NA-1; i>=0; i--) {
650 AppWindowToken t = mAppTokens.get(i);
651 if (t == token) {
652 i--;
653 break;
654 }
655 if (t.windows.size() > 0) {
656 pos = t.windows.get(0);
657 }
658 }
659 // We now know the index into the apps. If we found
660 // an app window above, that gives us the position; else
661 // we need to look some more.
662 if (pos != null) {
663 // Move behind any windows attached to this one.
Romain Guy06882f82009-06-10 13:36:04 -0700664 WindowToken atoken =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 mTokenMap.get(((WindowState)pos).mClient.asBinder());
666 if (atoken != null) {
667 final int NC = atoken.windows.size();
668 if (NC > 0) {
669 WindowState bottom = atoken.windows.get(0);
670 if (bottom.mSubLayer < 0) {
671 pos = bottom;
672 }
673 }
674 }
675 placeWindowBefore(pos, win);
676 } else {
677 while (i >= 0) {
678 AppWindowToken t = mAppTokens.get(i);
679 final int NW = t.windows.size();
680 if (NW > 0) {
681 pos = t.windows.get(NW-1);
682 break;
683 }
684 i--;
685 }
686 if (pos != null) {
687 // Move in front of any windows attached to this
688 // one.
689 WindowToken atoken =
690 mTokenMap.get(((WindowState)pos).mClient.asBinder());
691 if (atoken != null) {
692 final int NC = atoken.windows.size();
693 if (NC > 0) {
694 WindowState top = atoken.windows.get(NC-1);
695 if (top.mSubLayer >= 0) {
696 pos = top;
697 }
698 }
699 }
700 placeWindowAfter(pos, win);
701 } else {
702 // Just search for the start of this layer.
703 final int myLayer = win.mBaseLayer;
704 for (i=0; i<N; i++) {
705 WindowState w = (WindowState)localmWindows.get(i);
706 if (w.mBaseLayer > myLayer) {
707 break;
708 }
709 }
710 if (localLOGV || DEBUG_FOCUS) Log.v(
711 TAG, "Adding window " + win + " at "
712 + i + " of " + N);
713 localmWindows.add(i, win);
714 }
715 }
716 }
717 } else {
718 // Figure out where window should go, based on layer.
719 final int myLayer = win.mBaseLayer;
720 for (i=N-1; i>=0; i--) {
721 if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
722 i++;
723 break;
724 }
725 }
726 if (i < 0) i = 0;
727 if (localLOGV || DEBUG_FOCUS) Log.v(
728 TAG, "Adding window " + win + " at "
729 + i + " of " + N);
730 localmWindows.add(i, win);
731 }
732 if (addToToken) {
733 token.windows.add(tokenWindowsPos, win);
734 }
735
736 } else {
737 // Figure out this window's ordering relative to the window
738 // it is attached to.
739 final int NA = token.windows.size();
740 final int sublayer = win.mSubLayer;
741 int largestSublayer = Integer.MIN_VALUE;
742 WindowState windowWithLargestSublayer = null;
743 for (i=0; i<NA; i++) {
744 WindowState w = token.windows.get(i);
745 final int wSublayer = w.mSubLayer;
746 if (wSublayer >= largestSublayer) {
747 largestSublayer = wSublayer;
748 windowWithLargestSublayer = w;
749 }
750 if (sublayer < 0) {
751 // For negative sublayers, we go below all windows
752 // in the same sublayer.
753 if (wSublayer >= sublayer) {
754 if (addToToken) {
755 token.windows.add(i, win);
756 }
757 placeWindowBefore(
758 wSublayer >= 0 ? attached : w, win);
759 break;
760 }
761 } else {
762 // For positive sublayers, we go above all windows
763 // in the same sublayer.
764 if (wSublayer > sublayer) {
765 if (addToToken) {
766 token.windows.add(i, win);
767 }
768 placeWindowBefore(w, win);
769 break;
770 }
771 }
772 }
773 if (i >= NA) {
774 if (addToToken) {
775 token.windows.add(win);
776 }
777 if (sublayer < 0) {
778 placeWindowBefore(attached, win);
779 } else {
780 placeWindowAfter(largestSublayer >= 0
781 ? windowWithLargestSublayer
782 : attached,
783 win);
784 }
785 }
786 }
Romain Guy06882f82009-06-10 13:36:04 -0700787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 if (win.mAppToken != null && addToToken) {
789 win.mAppToken.allAppWindows.add(win);
790 }
791 }
Romain Guy06882f82009-06-10 13:36:04 -0700792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 static boolean canBeImeTarget(WindowState w) {
794 final int fl = w.mAttrs.flags
795 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
796 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
797 return w.isVisibleOrAdding();
798 }
799 return false;
800 }
Romain Guy06882f82009-06-10 13:36:04 -0700801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
803 final ArrayList localmWindows = mWindows;
804 final int N = localmWindows.size();
805 WindowState w = null;
806 int i = N;
807 while (i > 0) {
808 i--;
809 w = (WindowState)localmWindows.get(i);
Romain Guy06882f82009-06-10 13:36:04 -0700810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
812 // + Integer.toHexString(w.mAttrs.flags));
813 if (canBeImeTarget(w)) {
814 //Log.i(TAG, "Putting input method here!");
Romain Guy06882f82009-06-10 13:36:04 -0700815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 // Yet more tricksyness! If this window is a "starting"
817 // window, we do actually want to be on top of it, but
818 // it is not -really- where input will go. So if the caller
819 // is not actually looking to move the IME, look down below
820 // for a real window to target...
821 if (!willMove
822 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
823 && i > 0) {
824 WindowState wb = (WindowState)localmWindows.get(i-1);
825 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
826 i--;
827 w = wb;
828 }
829 }
830 break;
831 }
832 }
Romain Guy06882f82009-06-10 13:36:04 -0700833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 mUpcomingInputMethodTarget = w;
Romain Guy06882f82009-06-10 13:36:04 -0700835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
837 + w + " willMove=" + willMove);
Romain Guy06882f82009-06-10 13:36:04 -0700838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 if (willMove && w != null) {
840 final WindowState curTarget = mInputMethodTarget;
841 if (curTarget != null && curTarget.mAppToken != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 // Now some fun for dealing with window animations that
844 // modify the Z order. We need to look at all windows below
845 // the current target that are in this app, finding the highest
846 // visible one in layering.
847 AppWindowToken token = curTarget.mAppToken;
848 WindowState highestTarget = null;
849 int highestPos = 0;
850 if (token.animating || token.animation != null) {
851 int pos = 0;
852 pos = localmWindows.indexOf(curTarget);
853 while (pos >= 0) {
854 WindowState win = (WindowState)localmWindows.get(pos);
855 if (win.mAppToken != token) {
856 break;
857 }
858 if (!win.mRemoved) {
859 if (highestTarget == null || win.mAnimLayer >
860 highestTarget.mAnimLayer) {
861 highestTarget = win;
862 highestPos = pos;
863 }
864 }
865 pos--;
866 }
867 }
Romain Guy06882f82009-06-10 13:36:04 -0700868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 if (highestTarget != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700870 if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 + mNextAppTransition + " " + highestTarget
872 + " animating=" + highestTarget.isAnimating()
873 + " layer=" + highestTarget.mAnimLayer
874 + " new layer=" + w.mAnimLayer);
Romain Guy06882f82009-06-10 13:36:04 -0700875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
877 // If we are currently setting up for an animation,
878 // hold everything until we can find out what will happen.
879 mInputMethodTargetWaitingAnim = true;
880 mInputMethodTarget = highestTarget;
881 return highestPos + 1;
882 } else if (highestTarget.isAnimating() &&
883 highestTarget.mAnimLayer > w.mAnimLayer) {
884 // If the window we are currently targeting is involved
885 // with an animation, and it is on top of the next target
886 // we will be over, then hold off on moving until
887 // that is done.
888 mInputMethodTarget = highestTarget;
889 return highestPos + 1;
890 }
891 }
892 }
893 }
Romain Guy06882f82009-06-10 13:36:04 -0700894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 //Log.i(TAG, "Placing input method @" + (i+1));
896 if (w != null) {
897 if (willMove) {
898 RuntimeException e = new RuntimeException();
899 e.fillInStackTrace();
900 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
901 + mInputMethodTarget + " to " + w, e);
902 mInputMethodTarget = w;
903 if (w.mAppToken != null) {
904 setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
905 } else {
906 setInputMethodAnimLayerAdjustment(0);
907 }
908 }
909 return i+1;
910 }
911 if (willMove) {
912 RuntimeException e = new RuntimeException();
913 e.fillInStackTrace();
914 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
915 + mInputMethodTarget + " to null", e);
916 mInputMethodTarget = null;
917 setInputMethodAnimLayerAdjustment(0);
918 }
919 return -1;
920 }
Romain Guy06882f82009-06-10 13:36:04 -0700921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 void addInputMethodWindowToListLocked(WindowState win) {
923 int pos = findDesiredInputMethodWindowIndexLocked(true);
924 if (pos >= 0) {
925 win.mTargetAppToken = mInputMethodTarget.mAppToken;
926 mWindows.add(pos, win);
927 moveInputMethodDialogsLocked(pos+1);
928 return;
929 }
930 win.mTargetAppToken = null;
931 addWindowToListInOrderLocked(win, true);
932 moveInputMethodDialogsLocked(pos);
933 }
Romain Guy06882f82009-06-10 13:36:04 -0700934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 void setInputMethodAnimLayerAdjustment(int adj) {
936 if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
937 mInputMethodAnimLayerAdjustment = adj;
938 WindowState imw = mInputMethodWindow;
939 if (imw != null) {
940 imw.mAnimLayer = imw.mLayer + adj;
941 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
942 + " anim layer: " + imw.mAnimLayer);
943 int wi = imw.mChildWindows.size();
944 while (wi > 0) {
945 wi--;
946 WindowState cw = (WindowState)imw.mChildWindows.get(wi);
947 cw.mAnimLayer = cw.mLayer + adj;
948 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
949 + " anim layer: " + cw.mAnimLayer);
950 }
951 }
952 int di = mInputMethodDialogs.size();
953 while (di > 0) {
954 di --;
955 imw = mInputMethodDialogs.get(di);
956 imw.mAnimLayer = imw.mLayer + adj;
957 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
958 + " anim layer: " + imw.mAnimLayer);
959 }
960 }
Romain Guy06882f82009-06-10 13:36:04 -0700961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
963 int wpos = mWindows.indexOf(win);
964 if (wpos >= 0) {
965 if (wpos < interestingPos) interestingPos--;
966 mWindows.remove(wpos);
967 int NC = win.mChildWindows.size();
968 while (NC > 0) {
969 NC--;
970 WindowState cw = (WindowState)win.mChildWindows.get(NC);
971 int cpos = mWindows.indexOf(cw);
972 if (cpos >= 0) {
973 if (cpos < interestingPos) interestingPos--;
974 mWindows.remove(cpos);
975 }
976 }
977 }
978 return interestingPos;
979 }
Romain Guy06882f82009-06-10 13:36:04 -0700980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 private void reAddWindowToListInOrderLocked(WindowState win) {
982 addWindowToListInOrderLocked(win, false);
983 // This is a hack to get all of the child windows added as well
984 // at the right position. Child windows should be rare and
985 // this case should be rare, so it shouldn't be that big a deal.
986 int wpos = mWindows.indexOf(win);
987 if (wpos >= 0) {
988 mWindows.remove(wpos);
989 reAddWindowLocked(wpos, win);
990 }
991 }
Romain Guy06882f82009-06-10 13:36:04 -0700992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 void logWindowList(String prefix) {
994 int N = mWindows.size();
995 while (N > 0) {
996 N--;
997 Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
998 }
999 }
Romain Guy06882f82009-06-10 13:36:04 -07001000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 void moveInputMethodDialogsLocked(int pos) {
1002 ArrayList<WindowState> dialogs = mInputMethodDialogs;
Romain Guy06882f82009-06-10 13:36:04 -07001003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 final int N = dialogs.size();
1005 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
1006 for (int i=0; i<N; i++) {
1007 pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
1008 }
1009 if (DEBUG_INPUT_METHOD) {
1010 Log.v(TAG, "Window list w/pos=" + pos);
1011 logWindowList(" ");
1012 }
Romain Guy06882f82009-06-10 13:36:04 -07001013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 if (pos >= 0) {
1015 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
1016 if (pos < mWindows.size()) {
1017 WindowState wp = (WindowState)mWindows.get(pos);
1018 if (wp == mInputMethodWindow) {
1019 pos++;
1020 }
1021 }
1022 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
1023 for (int i=0; i<N; i++) {
1024 WindowState win = dialogs.get(i);
1025 win.mTargetAppToken = targetAppToken;
1026 pos = reAddWindowLocked(pos, win);
1027 }
1028 if (DEBUG_INPUT_METHOD) {
1029 Log.v(TAG, "Final window list:");
1030 logWindowList(" ");
1031 }
1032 return;
1033 }
1034 for (int i=0; i<N; i++) {
1035 WindowState win = dialogs.get(i);
1036 win.mTargetAppToken = null;
1037 reAddWindowToListInOrderLocked(win);
1038 if (DEBUG_INPUT_METHOD) {
1039 Log.v(TAG, "No IM target, final list:");
1040 logWindowList(" ");
1041 }
1042 }
1043 }
Romain Guy06882f82009-06-10 13:36:04 -07001044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
1046 final WindowState imWin = mInputMethodWindow;
1047 final int DN = mInputMethodDialogs.size();
1048 if (imWin == null && DN == 0) {
1049 return false;
1050 }
Romain Guy06882f82009-06-10 13:36:04 -07001051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 int imPos = findDesiredInputMethodWindowIndexLocked(true);
1053 if (imPos >= 0) {
1054 // In this case, the input method windows are to be placed
1055 // immediately above the window they are targeting.
Romain Guy06882f82009-06-10 13:36:04 -07001056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 // First check to see if the input method windows are already
1058 // located here, and contiguous.
1059 final int N = mWindows.size();
1060 WindowState firstImWin = imPos < N
1061 ? (WindowState)mWindows.get(imPos) : null;
Romain Guy06882f82009-06-10 13:36:04 -07001062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 // Figure out the actual input method window that should be
1064 // at the bottom of their stack.
1065 WindowState baseImWin = imWin != null
1066 ? imWin : mInputMethodDialogs.get(0);
1067 if (baseImWin.mChildWindows.size() > 0) {
1068 WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
1069 if (cw.mSubLayer < 0) baseImWin = cw;
1070 }
Romain Guy06882f82009-06-10 13:36:04 -07001071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 if (firstImWin == baseImWin) {
1073 // The windows haven't moved... but are they still contiguous?
1074 // First find the top IM window.
1075 int pos = imPos+1;
1076 while (pos < N) {
1077 if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
1078 break;
1079 }
1080 pos++;
1081 }
1082 pos++;
1083 // Now there should be no more input method windows above.
1084 while (pos < N) {
1085 if (((WindowState)mWindows.get(pos)).mIsImWindow) {
1086 break;
1087 }
1088 pos++;
1089 }
1090 if (pos >= N) {
1091 // All is good!
1092 return false;
1093 }
1094 }
Romain Guy06882f82009-06-10 13:36:04 -07001095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 if (imWin != null) {
1097 if (DEBUG_INPUT_METHOD) {
1098 Log.v(TAG, "Moving IM from " + imPos);
1099 logWindowList(" ");
1100 }
1101 imPos = tmpRemoveWindowLocked(imPos, imWin);
1102 if (DEBUG_INPUT_METHOD) {
1103 Log.v(TAG, "List after moving with new pos " + imPos + ":");
1104 logWindowList(" ");
1105 }
1106 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
1107 reAddWindowLocked(imPos, imWin);
1108 if (DEBUG_INPUT_METHOD) {
1109 Log.v(TAG, "List after moving IM to " + imPos + ":");
1110 logWindowList(" ");
1111 }
1112 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
1113 } else {
1114 moveInputMethodDialogsLocked(imPos);
1115 }
Romain Guy06882f82009-06-10 13:36:04 -07001116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 } else {
1118 // In this case, the input method windows go in a fixed layer,
1119 // because they aren't currently associated with a focus window.
Romain Guy06882f82009-06-10 13:36:04 -07001120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 if (imWin != null) {
1122 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
1123 tmpRemoveWindowLocked(0, imWin);
1124 imWin.mTargetAppToken = null;
1125 reAddWindowToListInOrderLocked(imWin);
1126 if (DEBUG_INPUT_METHOD) {
1127 Log.v(TAG, "List with no IM target:");
1128 logWindowList(" ");
1129 }
1130 if (DN > 0) moveInputMethodDialogsLocked(-1);;
1131 } else {
1132 moveInputMethodDialogsLocked(-1);;
1133 }
Romain Guy06882f82009-06-10 13:36:04 -07001134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 }
Romain Guy06882f82009-06-10 13:36:04 -07001136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 if (needAssignLayers) {
1138 assignLayersLocked();
1139 }
Romain Guy06882f82009-06-10 13:36:04 -07001140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 return true;
1142 }
Romain Guy06882f82009-06-10 13:36:04 -07001143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 void adjustInputMethodDialogsLocked() {
1145 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
1146 }
Romain Guy06882f82009-06-10 13:36:04 -07001147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 public int addWindow(Session session, IWindow client,
1149 WindowManager.LayoutParams attrs, int viewVisibility,
1150 Rect outContentInsets) {
1151 int res = mPolicy.checkAddPermission(attrs);
1152 if (res != WindowManagerImpl.ADD_OKAY) {
1153 return res;
1154 }
Romain Guy06882f82009-06-10 13:36:04 -07001155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 boolean reportNewConfig = false;
1157 WindowState attachedWindow = null;
1158 WindowState win = null;
Romain Guy06882f82009-06-10 13:36:04 -07001159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 synchronized(mWindowMap) {
1161 // Instantiating a Display requires talking with the simulator,
1162 // so don't do it until we know the system is mostly up and
1163 // running.
1164 if (mDisplay == null) {
1165 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1166 mDisplay = wm.getDefaultDisplay();
1167 mQueue.setDisplay(mDisplay);
1168 reportNewConfig = true;
1169 }
Romain Guy06882f82009-06-10 13:36:04 -07001170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 if (mWindowMap.containsKey(client.asBinder())) {
1172 Log.w(TAG, "Window " + client + " is already added");
1173 return WindowManagerImpl.ADD_DUPLICATE_ADD;
1174 }
1175
1176 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
Romain Guy06882f82009-06-10 13:36:04 -07001177 attachedWindow = windowForClientLocked(null, attrs.token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 if (attachedWindow == null) {
1179 Log.w(TAG, "Attempted to add window with token that is not a window: "
1180 + attrs.token + ". Aborting.");
1181 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1182 }
1183 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
1184 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1185 Log.w(TAG, "Attempted to add window with token that is a sub-window: "
1186 + attrs.token + ". Aborting.");
1187 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1188 }
1189 }
1190
1191 boolean addToken = false;
1192 WindowToken token = mTokenMap.get(attrs.token);
1193 if (token == null) {
1194 if (attrs.type >= FIRST_APPLICATION_WINDOW
1195 && attrs.type <= LAST_APPLICATION_WINDOW) {
1196 Log.w(TAG, "Attempted to add application window with unknown token "
1197 + attrs.token + ". Aborting.");
1198 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1199 }
1200 if (attrs.type == TYPE_INPUT_METHOD) {
1201 Log.w(TAG, "Attempted to add input method window with unknown token "
1202 + attrs.token + ". Aborting.");
1203 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1204 }
1205 token = new WindowToken(attrs.token, -1, false);
1206 addToken = true;
1207 } else if (attrs.type >= FIRST_APPLICATION_WINDOW
1208 && attrs.type <= LAST_APPLICATION_WINDOW) {
1209 AppWindowToken atoken = token.appWindowToken;
1210 if (atoken == null) {
1211 Log.w(TAG, "Attempted to add window with non-application token "
1212 + token + ". Aborting.");
1213 return WindowManagerImpl.ADD_NOT_APP_TOKEN;
1214 } else if (atoken.removed) {
1215 Log.w(TAG, "Attempted to add window with exiting application token "
1216 + token + ". Aborting.");
1217 return WindowManagerImpl.ADD_APP_EXITING;
1218 }
1219 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
1220 // No need for this guy!
1221 if (localLOGV) Log.v(
1222 TAG, "**** NO NEED TO START: " + attrs.getTitle());
1223 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
1224 }
1225 } else if (attrs.type == TYPE_INPUT_METHOD) {
1226 if (token.windowType != TYPE_INPUT_METHOD) {
1227 Log.w(TAG, "Attempted to add input method window with bad token "
1228 + attrs.token + ". Aborting.");
1229 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1230 }
1231 }
1232
1233 win = new WindowState(session, client, token,
1234 attachedWindow, attrs, viewVisibility);
1235 if (win.mDeathRecipient == null) {
1236 // Client has apparently died, so there is no reason to
1237 // continue.
1238 Log.w(TAG, "Adding window client " + client.asBinder()
1239 + " that is dead, aborting.");
1240 return WindowManagerImpl.ADD_APP_EXITING;
1241 }
1242
1243 mPolicy.adjustWindowParamsLw(win.mAttrs);
Romain Guy06882f82009-06-10 13:36:04 -07001244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 res = mPolicy.prepareAddWindowLw(win, attrs);
1246 if (res != WindowManagerImpl.ADD_OKAY) {
1247 return res;
1248 }
1249
1250 // From now on, no exceptions or errors allowed!
1251
1252 res = WindowManagerImpl.ADD_OKAY;
Romain Guy06882f82009-06-10 13:36:04 -07001253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 if (addToken) {
1257 mTokenMap.put(attrs.token, token);
1258 mTokenList.add(token);
1259 }
1260 win.attach();
1261 mWindowMap.put(client.asBinder(), win);
1262
1263 if (attrs.type == TYPE_APPLICATION_STARTING &&
1264 token.appWindowToken != null) {
1265 token.appWindowToken.startingWindow = win;
1266 }
1267
1268 boolean imMayMove = true;
Romain Guy06882f82009-06-10 13:36:04 -07001269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 if (attrs.type == TYPE_INPUT_METHOD) {
1271 mInputMethodWindow = win;
1272 addInputMethodWindowToListLocked(win);
1273 imMayMove = false;
1274 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
1275 mInputMethodDialogs.add(win);
1276 addWindowToListInOrderLocked(win, true);
1277 adjustInputMethodDialogsLocked();
1278 imMayMove = false;
1279 } else {
1280 addWindowToListInOrderLocked(win, true);
1281 }
Romain Guy06882f82009-06-10 13:36:04 -07001282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 win.mEnterAnimationPending = true;
Romain Guy06882f82009-06-10 13:36:04 -07001284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
Romain Guy06882f82009-06-10 13:36:04 -07001286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 if (mInTouchMode) {
1288 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
1289 }
1290 if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
1291 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
1292 }
Romain Guy06882f82009-06-10 13:36:04 -07001293
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001294 boolean focusChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 if (win.canReceiveKeys()) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001296 if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
1297 == true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 imMayMove = false;
1299 }
1300 }
Romain Guy06882f82009-06-10 13:36:04 -07001301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 if (imMayMove) {
Romain Guy06882f82009-06-10 13:36:04 -07001303 moveInputMethodWindowsIfNeededLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 }
Romain Guy06882f82009-06-10 13:36:04 -07001305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 assignLayersLocked();
1307 // Don't do layout here, the window must call
1308 // relayout to be displayed, so we'll do it there.
Romain Guy06882f82009-06-10 13:36:04 -07001309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 //dump();
1311
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001312 if (focusChanged) {
1313 if (mCurrentFocus != null) {
1314 mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
1315 }
1316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 if (localLOGV) Log.v(
1318 TAG, "New client " + client.asBinder()
1319 + ": window=" + win);
1320 }
1321
1322 // sendNewConfiguration() checks caller permissions so we must call it with
1323 // privilege. updateOrientationFromAppTokens() clears and resets the caller
1324 // identity anyway, so it's safe to just clear & restore around this whole
1325 // block.
1326 final long origId = Binder.clearCallingIdentity();
1327 if (reportNewConfig) {
1328 sendNewConfiguration();
1329 } else {
1330 // Update Orientation after adding a window, only if the window needs to be
1331 // displayed right away
1332 if (win.isVisibleOrAdding()) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001333 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 sendNewConfiguration();
1335 }
1336 }
1337 }
1338 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 return res;
1341 }
Romain Guy06882f82009-06-10 13:36:04 -07001342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 public void removeWindow(Session session, IWindow client) {
1344 synchronized(mWindowMap) {
1345 WindowState win = windowForClientLocked(session, client);
1346 if (win == null) {
1347 return;
1348 }
1349 removeWindowLocked(session, win);
1350 }
1351 }
Romain Guy06882f82009-06-10 13:36:04 -07001352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 public void removeWindowLocked(Session session, WindowState win) {
1354
1355 if (localLOGV || DEBUG_FOCUS) Log.v(
1356 TAG, "Remove " + win + " client="
1357 + Integer.toHexString(System.identityHashCode(
1358 win.mClient.asBinder()))
1359 + ", surface=" + win.mSurface);
1360
1361 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 if (DEBUG_APP_TRANSITIONS) Log.v(
1364 TAG, "Remove " + win + ": mSurface=" + win.mSurface
1365 + " mExiting=" + win.mExiting
1366 + " isAnimating=" + win.isAnimating()
1367 + " app-animation="
1368 + (win.mAppToken != null ? win.mAppToken.animation : null)
1369 + " inPendingTransaction="
1370 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
1371 + " mDisplayFrozen=" + mDisplayFrozen);
1372 // Visibility of the removed window. Will be used later to update orientation later on.
1373 boolean wasVisible = false;
1374 // First, see if we need to run an animation. If we do, we have
1375 // to hold off on removing the window until the animation is done.
1376 // If the display is frozen, just remove immediately, since the
1377 // animation wouldn't be seen.
1378 if (win.mSurface != null && !mDisplayFrozen) {
1379 // If we are not currently running the exit animation, we
1380 // need to see about starting one.
1381 if (wasVisible=win.isWinVisibleLw()) {
Romain Guy06882f82009-06-10 13:36:04 -07001382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1384 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1385 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1386 }
1387 // Try starting an animation.
1388 if (applyAnimationLocked(win, transit, false)) {
1389 win.mExiting = true;
1390 }
1391 }
1392 if (win.mExiting || win.isAnimating()) {
1393 // The exit animation is running... wait for it!
1394 //Log.i(TAG, "*** Running exit animation...");
1395 win.mExiting = true;
1396 win.mRemoveOnExit = true;
1397 mLayoutNeeded = true;
1398 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
1399 performLayoutAndPlaceSurfacesLocked();
1400 if (win.mAppToken != null) {
1401 win.mAppToken.updateReportedVisibilityLocked();
1402 }
1403 //dump();
1404 Binder.restoreCallingIdentity(origId);
1405 return;
1406 }
1407 }
1408
1409 removeWindowInnerLocked(session, win);
1410 // Removing a visible window will effect the computed orientation
1411 // So just update orientation if needed.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001412 if (wasVisible && computeForcedAppOrientationLocked()
1413 != mForcedAppOrientation) {
1414 mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 }
1416 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1417 Binder.restoreCallingIdentity(origId);
1418 }
Romain Guy06882f82009-06-10 13:36:04 -07001419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 private void removeWindowInnerLocked(Session session, WindowState win) {
1421 mKeyWaiter.releasePendingPointerLocked(win.mSession);
1422 mKeyWaiter.releasePendingTrackballLocked(win.mSession);
Romain Guy06882f82009-06-10 13:36:04 -07001423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 win.mRemoved = true;
Romain Guy06882f82009-06-10 13:36:04 -07001425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 if (mInputMethodTarget == win) {
1427 moveInputMethodWindowsIfNeededLocked(false);
1428 }
Romain Guy06882f82009-06-10 13:36:04 -07001429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 mPolicy.removeWindowLw(win);
1431 win.removeLocked();
1432
1433 mWindowMap.remove(win.mClient.asBinder());
1434 mWindows.remove(win);
1435
1436 if (mInputMethodWindow == win) {
1437 mInputMethodWindow = null;
1438 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
1439 mInputMethodDialogs.remove(win);
1440 }
Romain Guy06882f82009-06-10 13:36:04 -07001441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 final WindowToken token = win.mToken;
1443 final AppWindowToken atoken = win.mAppToken;
1444 token.windows.remove(win);
1445 if (atoken != null) {
1446 atoken.allAppWindows.remove(win);
1447 }
1448 if (localLOGV) Log.v(
1449 TAG, "**** Removing window " + win + ": count="
1450 + token.windows.size());
1451 if (token.windows.size() == 0) {
1452 if (!token.explicit) {
1453 mTokenMap.remove(token.token);
1454 mTokenList.remove(token);
1455 } else if (atoken != null) {
1456 atoken.firstWindowDrawn = false;
1457 }
1458 }
1459
1460 if (atoken != null) {
1461 if (atoken.startingWindow == win) {
1462 atoken.startingWindow = null;
1463 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
1464 // If this is the last window and we had requested a starting
1465 // transition window, well there is no point now.
1466 atoken.startingData = null;
1467 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
1468 // If this is the last window except for a starting transition
1469 // window, we need to get rid of the starting transition.
1470 if (DEBUG_STARTING_WINDOW) {
1471 Log.v(TAG, "Schedule remove starting " + token
1472 + ": no more real windows");
1473 }
1474 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
1475 mH.sendMessage(m);
1476 }
1477 }
Romain Guy06882f82009-06-10 13:36:04 -07001478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 if (!mInLayout) {
1480 assignLayersLocked();
1481 mLayoutNeeded = true;
1482 performLayoutAndPlaceSurfacesLocked();
1483 if (win.mAppToken != null) {
1484 win.mAppToken.updateReportedVisibilityLocked();
1485 }
1486 }
1487 }
1488
1489 private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
1490 long origId = Binder.clearCallingIdentity();
1491 try {
1492 synchronized (mWindowMap) {
1493 WindowState w = windowForClientLocked(session, client);
1494 if ((w != null) && (w.mSurface != null)) {
1495 Surface.openTransaction();
1496 try {
1497 w.mSurface.setTransparentRegionHint(region);
1498 } finally {
1499 Surface.closeTransaction();
1500 }
1501 }
1502 }
1503 } finally {
1504 Binder.restoreCallingIdentity(origId);
1505 }
1506 }
1507
1508 void setInsetsWindow(Session session, IWindow client,
Romain Guy06882f82009-06-10 13:36:04 -07001509 int touchableInsets, Rect contentInsets,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 Rect visibleInsets) {
1511 long origId = Binder.clearCallingIdentity();
1512 try {
1513 synchronized (mWindowMap) {
1514 WindowState w = windowForClientLocked(session, client);
1515 if (w != null) {
1516 w.mGivenInsetsPending = false;
1517 w.mGivenContentInsets.set(contentInsets);
1518 w.mGivenVisibleInsets.set(visibleInsets);
1519 w.mTouchableInsets = touchableInsets;
1520 mLayoutNeeded = true;
1521 performLayoutAndPlaceSurfacesLocked();
1522 }
1523 }
1524 } finally {
1525 Binder.restoreCallingIdentity(origId);
1526 }
1527 }
Romain Guy06882f82009-06-10 13:36:04 -07001528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 public void getWindowDisplayFrame(Session session, IWindow client,
1530 Rect outDisplayFrame) {
1531 synchronized(mWindowMap) {
1532 WindowState win = windowForClientLocked(session, client);
1533 if (win == null) {
1534 outDisplayFrame.setEmpty();
1535 return;
1536 }
1537 outDisplayFrame.set(win.mDisplayFrame);
1538 }
1539 }
1540
1541 public int relayoutWindow(Session session, IWindow client,
1542 WindowManager.LayoutParams attrs, int requestedWidth,
1543 int requestedHeight, int viewVisibility, boolean insetsPending,
1544 Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
1545 Surface outSurface) {
1546 boolean displayed = false;
1547 boolean inTouchMode;
1548 Configuration newConfig = null;
1549 long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 synchronized(mWindowMap) {
1552 WindowState win = windowForClientLocked(session, client);
1553 if (win == null) {
1554 return 0;
1555 }
1556 win.mRequestedWidth = requestedWidth;
1557 win.mRequestedHeight = requestedHeight;
1558
1559 if (attrs != null) {
1560 mPolicy.adjustWindowParamsLw(attrs);
1561 }
Romain Guy06882f82009-06-10 13:36:04 -07001562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 int attrChanges = 0;
1564 int flagChanges = 0;
1565 if (attrs != null) {
1566 flagChanges = win.mAttrs.flags ^= attrs.flags;
1567 attrChanges = win.mAttrs.copyFrom(attrs);
1568 }
1569
1570 if (localLOGV) Log.v(
1571 TAG, "Relayout given client " + client.asBinder()
1572 + " (" + win.mAttrs.getTitle() + ")");
1573
1574
1575 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
1576 win.mAlpha = attrs.alpha;
1577 }
1578
1579 final boolean scaledWindow =
1580 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
1581
1582 if (scaledWindow) {
1583 // requested{Width|Height} Surface's physical size
1584 // attrs.{width|height} Size on screen
1585 win.mHScale = (attrs.width != requestedWidth) ?
1586 (attrs.width / (float)requestedWidth) : 1.0f;
1587 win.mVScale = (attrs.height != requestedHeight) ?
1588 (attrs.height / (float)requestedHeight) : 1.0f;
1589 }
1590
1591 boolean imMayMove = (flagChanges&(
1592 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
1593 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07001594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 boolean focusMayChange = win.mViewVisibility != viewVisibility
1596 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
1597 || (!win.mRelayoutCalled);
Romain Guy06882f82009-06-10 13:36:04 -07001598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 win.mRelayoutCalled = true;
1600 final int oldVisibility = win.mViewVisibility;
1601 win.mViewVisibility = viewVisibility;
1602 if (viewVisibility == View.VISIBLE &&
1603 (win.mAppToken == null || !win.mAppToken.clientHidden)) {
1604 displayed = !win.isVisibleLw();
1605 if (win.mExiting) {
1606 win.mExiting = false;
1607 win.mAnimation = null;
1608 }
1609 if (win.mDestroying) {
1610 win.mDestroying = false;
1611 mDestroySurface.remove(win);
1612 }
1613 if (oldVisibility == View.GONE) {
1614 win.mEnterAnimationPending = true;
1615 }
1616 if (displayed && win.mSurface != null && !win.mDrawPending
1617 && !win.mCommitDrawPending && !mDisplayFrozen) {
1618 applyEnterAnimationLocked(win);
1619 }
1620 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
1621 // To change the format, we need to re-build the surface.
1622 win.destroySurfaceLocked();
1623 displayed = true;
1624 }
1625 try {
1626 Surface surface = win.createSurfaceLocked();
1627 if (surface != null) {
1628 outSurface.copyFrom(surface);
1629 } else {
1630 outSurface.clear();
1631 }
1632 } catch (Exception e) {
1633 Log.w(TAG, "Exception thrown when creating surface for client "
1634 + client + " (" + win.mAttrs.getTitle() + ")",
1635 e);
1636 Binder.restoreCallingIdentity(origId);
1637 return 0;
1638 }
1639 if (displayed) {
1640 focusMayChange = true;
1641 }
1642 if (win.mAttrs.type == TYPE_INPUT_METHOD
1643 && mInputMethodWindow == null) {
1644 mInputMethodWindow = win;
1645 imMayMove = true;
1646 }
1647 } else {
1648 win.mEnterAnimationPending = false;
1649 if (win.mSurface != null) {
1650 // If we are not currently running the exit animation, we
1651 // need to see about starting one.
1652 if (!win.mExiting) {
1653 // Try starting an animation; if there isn't one, we
1654 // can destroy the surface right away.
1655 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1656 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1657 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1658 }
1659 if (win.isWinVisibleLw() &&
1660 applyAnimationLocked(win, transit, false)) {
1661 win.mExiting = true;
1662 mKeyWaiter.finishedKey(session, client, true,
1663 KeyWaiter.RETURN_NOTHING);
1664 } else if (win.isAnimating()) {
1665 // Currently in a hide animation... turn this into
1666 // an exit.
1667 win.mExiting = true;
1668 } else {
1669 if (mInputMethodWindow == win) {
1670 mInputMethodWindow = null;
1671 }
1672 win.destroySurfaceLocked();
1673 }
1674 }
1675 }
1676 outSurface.clear();
1677 }
1678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 if (focusMayChange) {
1680 //System.out.println("Focus may change: " + win.mAttrs.getTitle());
1681 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 imMayMove = false;
1683 }
1684 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
1685 }
Romain Guy06882f82009-06-10 13:36:04 -07001686
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001687 // updateFocusedWindowLocked() already assigned layers so we only need to
1688 // reassign them at this point if the IM window state gets shuffled
1689 boolean assignLayers = false;
Romain Guy06882f82009-06-10 13:36:04 -07001690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 if (imMayMove) {
1692 if (moveInputMethodWindowsIfNeededLocked(false)) {
1693 assignLayers = true;
1694 }
1695 }
Romain Guy06882f82009-06-10 13:36:04 -07001696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 mLayoutNeeded = true;
1698 win.mGivenInsetsPending = insetsPending;
1699 if (assignLayers) {
1700 assignLayersLocked();
1701 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001702 newConfig = updateOrientationFromAppTokensLocked(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 performLayoutAndPlaceSurfacesLocked();
1704 if (win.mAppToken != null) {
1705 win.mAppToken.updateReportedVisibilityLocked();
1706 }
1707 outFrame.set(win.mFrame);
1708 outContentInsets.set(win.mContentInsets);
1709 outVisibleInsets.set(win.mVisibleInsets);
1710 if (localLOGV) Log.v(
1711 TAG, "Relayout given client " + client.asBinder()
Romain Guy06882f82009-06-10 13:36:04 -07001712 + ", requestedWidth=" + requestedWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 + ", requestedHeight=" + requestedHeight
1714 + ", viewVisibility=" + viewVisibility
1715 + "\nRelayout returning frame=" + outFrame
1716 + ", surface=" + outSurface);
1717
1718 if (localLOGV || DEBUG_FOCUS) Log.v(
1719 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
1720
1721 inTouchMode = mInTouchMode;
1722 }
1723
1724 if (newConfig != null) {
1725 sendNewConfiguration();
1726 }
Romain Guy06882f82009-06-10 13:36:04 -07001727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
1731 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
1732 }
1733
1734 public void finishDrawingWindow(Session session, IWindow client) {
1735 final long origId = Binder.clearCallingIdentity();
1736 synchronized(mWindowMap) {
1737 WindowState win = windowForClientLocked(session, client);
1738 if (win != null && win.finishDrawingLocked()) {
1739 mLayoutNeeded = true;
1740 performLayoutAndPlaceSurfacesLocked();
1741 }
1742 }
1743 Binder.restoreCallingIdentity(origId);
1744 }
1745
1746 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
1747 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
1748 + (lp != null ? lp.packageName : null)
1749 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
1750 if (lp != null && lp.windowAnimations != 0) {
1751 // If this is a system resource, don't try to load it from the
1752 // application resources. It is nice to avoid loading application
1753 // resources if we can.
1754 String packageName = lp.packageName != null ? lp.packageName : "android";
1755 int resId = lp.windowAnimations;
1756 if ((resId&0xFF000000) == 0x01000000) {
1757 packageName = "android";
1758 }
1759 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
1760 + packageName);
1761 return AttributeCache.instance().get(packageName, resId,
1762 com.android.internal.R.styleable.WindowAnimation);
1763 }
1764 return null;
1765 }
Romain Guy06882f82009-06-10 13:36:04 -07001766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 private void applyEnterAnimationLocked(WindowState win) {
1768 int transit = WindowManagerPolicy.TRANSIT_SHOW;
1769 if (win.mEnterAnimationPending) {
1770 win.mEnterAnimationPending = false;
1771 transit = WindowManagerPolicy.TRANSIT_ENTER;
1772 }
1773
1774 applyAnimationLocked(win, transit, true);
1775 }
1776
1777 private boolean applyAnimationLocked(WindowState win,
1778 int transit, boolean isEntrance) {
1779 if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
1780 // If we are trying to apply an animation, but already running
1781 // an animation of the same type, then just leave that one alone.
1782 return true;
1783 }
Romain Guy06882f82009-06-10 13:36:04 -07001784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 // Only apply an animation if the display isn't frozen. If it is
1786 // frozen, there is no reason to animate and it can cause strange
1787 // artifacts when we unfreeze the display if some different animation
1788 // is running.
1789 if (!mDisplayFrozen) {
1790 int anim = mPolicy.selectAnimationLw(win, transit);
1791 int attr = -1;
1792 Animation a = null;
1793 if (anim != 0) {
1794 a = AnimationUtils.loadAnimation(mContext, anim);
1795 } else {
1796 switch (transit) {
1797 case WindowManagerPolicy.TRANSIT_ENTER:
1798 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
1799 break;
1800 case WindowManagerPolicy.TRANSIT_EXIT:
1801 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
1802 break;
1803 case WindowManagerPolicy.TRANSIT_SHOW:
1804 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
1805 break;
1806 case WindowManagerPolicy.TRANSIT_HIDE:
1807 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
1808 break;
1809 }
1810 if (attr >= 0) {
1811 a = loadAnimation(win.mAttrs, attr);
1812 }
1813 }
1814 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
1815 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
1816 + " mAnimation=" + win.mAnimation
1817 + " isEntrance=" + isEntrance);
1818 if (a != null) {
1819 if (DEBUG_ANIM) {
1820 RuntimeException e = new RuntimeException();
1821 e.fillInStackTrace();
1822 Log.v(TAG, "Loaded animation " + a + " for " + win, e);
1823 }
1824 win.setAnimation(a);
1825 win.mAnimationIsEntrance = isEntrance;
1826 }
1827 } else {
1828 win.clearAnimation();
1829 }
1830
1831 return win.mAnimation != null;
1832 }
1833
1834 private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
1835 int anim = 0;
1836 Context context = mContext;
1837 if (animAttr >= 0) {
1838 AttributeCache.Entry ent = getCachedAnimations(lp);
1839 if (ent != null) {
1840 context = ent.context;
1841 anim = ent.array.getResourceId(animAttr, 0);
1842 }
1843 }
1844 if (anim != 0) {
1845 return AnimationUtils.loadAnimation(context, anim);
1846 }
1847 return null;
1848 }
Romain Guy06882f82009-06-10 13:36:04 -07001849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 private boolean applyAnimationLocked(AppWindowToken wtoken,
1851 WindowManager.LayoutParams lp, int transit, boolean enter) {
1852 // Only apply an animation if the display isn't frozen. If it is
1853 // frozen, there is no reason to animate and it can cause strange
1854 // artifacts when we unfreeze the display if some different animation
1855 // is running.
1856 if (!mDisplayFrozen) {
1857 int animAttr = 0;
1858 switch (transit) {
1859 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
1860 animAttr = enter
1861 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
1862 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
1863 break;
1864 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
1865 animAttr = enter
1866 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
1867 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
1868 break;
1869 case WindowManagerPolicy.TRANSIT_TASK_OPEN:
1870 animAttr = enter
1871 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
1872 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
1873 break;
1874 case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
1875 animAttr = enter
1876 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
1877 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
1878 break;
1879 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
1880 animAttr = enter
1881 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
1882 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
1883 break;
1884 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
1885 animAttr = enter
1886 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
1887 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
1888 break;
1889 }
1890 Animation a = loadAnimation(lp, animAttr);
1891 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
1892 + " anim=" + a
1893 + " animAttr=0x" + Integer.toHexString(animAttr)
1894 + " transit=" + transit);
1895 if (a != null) {
1896 if (DEBUG_ANIM) {
1897 RuntimeException e = new RuntimeException();
1898 e.fillInStackTrace();
1899 Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
1900 }
1901 wtoken.setAnimation(a);
1902 }
1903 } else {
1904 wtoken.clearAnimation();
1905 }
1906
1907 return wtoken.animation != null;
1908 }
1909
1910 // -------------------------------------------------------------
1911 // Application Window Tokens
1912 // -------------------------------------------------------------
1913
1914 public void validateAppTokens(List tokens) {
1915 int v = tokens.size()-1;
1916 int m = mAppTokens.size()-1;
1917 while (v >= 0 && m >= 0) {
1918 AppWindowToken wtoken = mAppTokens.get(m);
1919 if (wtoken.removed) {
1920 m--;
1921 continue;
1922 }
1923 if (tokens.get(v) != wtoken.token) {
1924 Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
1925 + " @ " + v + ", internal is " + wtoken.token + " @ " + m);
1926 }
1927 v--;
1928 m--;
1929 }
1930 while (v >= 0) {
1931 Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
1932 v--;
1933 }
1934 while (m >= 0) {
1935 AppWindowToken wtoken = mAppTokens.get(m);
1936 if (!wtoken.removed) {
1937 Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
1938 }
1939 m--;
1940 }
1941 }
1942
1943 boolean checkCallingPermission(String permission, String func) {
1944 // Quick check: if the calling permission is me, it's all okay.
1945 if (Binder.getCallingPid() == Process.myPid()) {
1946 return true;
1947 }
Romain Guy06882f82009-06-10 13:36:04 -07001948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 if (mContext.checkCallingPermission(permission)
1950 == PackageManager.PERMISSION_GRANTED) {
1951 return true;
1952 }
1953 String msg = "Permission Denial: " + func + " from pid="
1954 + Binder.getCallingPid()
1955 + ", uid=" + Binder.getCallingUid()
1956 + " requires " + permission;
1957 Log.w(TAG, msg);
1958 return false;
1959 }
Romain Guy06882f82009-06-10 13:36:04 -07001960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 AppWindowToken findAppWindowToken(IBinder token) {
1962 WindowToken wtoken = mTokenMap.get(token);
1963 if (wtoken == null) {
1964 return null;
1965 }
1966 return wtoken.appWindowToken;
1967 }
Romain Guy06882f82009-06-10 13:36:04 -07001968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 public void addWindowToken(IBinder token, int type) {
1970 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1971 "addWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001972 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 }
Romain Guy06882f82009-06-10 13:36:04 -07001974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 synchronized(mWindowMap) {
1976 WindowToken wtoken = mTokenMap.get(token);
1977 if (wtoken != null) {
1978 Log.w(TAG, "Attempted to add existing input method token: " + token);
1979 return;
1980 }
1981 wtoken = new WindowToken(token, type, true);
1982 mTokenMap.put(token, wtoken);
1983 mTokenList.add(wtoken);
1984 }
1985 }
Romain Guy06882f82009-06-10 13:36:04 -07001986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 public void removeWindowToken(IBinder token) {
1988 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1989 "removeWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001990 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 }
1992
1993 final long origId = Binder.clearCallingIdentity();
1994 synchronized(mWindowMap) {
1995 WindowToken wtoken = mTokenMap.remove(token);
1996 mTokenList.remove(wtoken);
1997 if (wtoken != null) {
1998 boolean delayed = false;
1999 if (!wtoken.hidden) {
2000 wtoken.hidden = true;
Romain Guy06882f82009-06-10 13:36:04 -07002001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 final int N = wtoken.windows.size();
2003 boolean changed = false;
Romain Guy06882f82009-06-10 13:36:04 -07002004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 for (int i=0; i<N; i++) {
2006 WindowState win = wtoken.windows.get(i);
2007
2008 if (win.isAnimating()) {
2009 delayed = true;
2010 }
Romain Guy06882f82009-06-10 13:36:04 -07002011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 if (win.isVisibleNow()) {
2013 applyAnimationLocked(win,
2014 WindowManagerPolicy.TRANSIT_EXIT, false);
2015 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2016 KeyWaiter.RETURN_NOTHING);
2017 changed = true;
2018 }
2019 }
2020
2021 if (changed) {
2022 mLayoutNeeded = true;
2023 performLayoutAndPlaceSurfacesLocked();
2024 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2025 }
Romain Guy06882f82009-06-10 13:36:04 -07002026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 if (delayed) {
2028 mExitingTokens.add(wtoken);
2029 }
2030 }
Romain Guy06882f82009-06-10 13:36:04 -07002031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 } else {
2033 Log.w(TAG, "Attempted to remove non-existing token: " + token);
2034 }
2035 }
2036 Binder.restoreCallingIdentity(origId);
2037 }
2038
2039 public void addAppToken(int addPos, IApplicationToken token,
2040 int groupId, int requestedOrientation, boolean fullscreen) {
2041 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2042 "addAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002043 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 }
Romain Guy06882f82009-06-10 13:36:04 -07002045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 synchronized(mWindowMap) {
2047 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2048 if (wtoken != null) {
2049 Log.w(TAG, "Attempted to add existing app token: " + token);
2050 return;
2051 }
2052 wtoken = new AppWindowToken(token);
2053 wtoken.groupId = groupId;
2054 wtoken.appFullscreen = fullscreen;
2055 wtoken.requestedOrientation = requestedOrientation;
2056 mAppTokens.add(addPos, wtoken);
Dave Bortcfe65242009-04-09 14:51:04 -07002057 if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 mTokenMap.put(token.asBinder(), wtoken);
2059 mTokenList.add(wtoken);
Romain Guy06882f82009-06-10 13:36:04 -07002060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 // Application tokens start out hidden.
2062 wtoken.hidden = true;
2063 wtoken.hiddenRequested = true;
Romain Guy06882f82009-06-10 13:36:04 -07002064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 //dump();
2066 }
2067 }
Romain Guy06882f82009-06-10 13:36:04 -07002068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 public void setAppGroupId(IBinder token, int groupId) {
2070 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2071 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002072 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
2074
2075 synchronized(mWindowMap) {
2076 AppWindowToken wtoken = findAppWindowToken(token);
2077 if (wtoken == null) {
2078 Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
2079 return;
2080 }
2081 wtoken.groupId = groupId;
2082 }
2083 }
Romain Guy06882f82009-06-10 13:36:04 -07002084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 public int getOrientationFromWindowsLocked() {
2086 int pos = mWindows.size() - 1;
2087 while (pos >= 0) {
2088 WindowState wtoken = (WindowState) mWindows.get(pos);
2089 pos--;
2090 if (wtoken.mAppToken != null) {
2091 // We hit an application window. so the orientation will be determined by the
2092 // app window. No point in continuing further.
2093 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2094 }
2095 if (!wtoken.isVisibleLw()) {
2096 continue;
2097 }
2098 int req = wtoken.mAttrs.screenOrientation;
2099 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
2100 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
2101 continue;
2102 } else {
2103 return req;
2104 }
2105 }
2106 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2107 }
Romain Guy06882f82009-06-10 13:36:04 -07002108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 public int getOrientationFromAppTokensLocked() {
2110 int pos = mAppTokens.size() - 1;
2111 int curGroup = 0;
2112 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Owen Lin3413b892009-05-01 17:12:32 -07002113 boolean findingBehind = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 boolean haveGroup = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002115 boolean lastFullscreen = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 while (pos >= 0) {
2117 AppWindowToken wtoken = mAppTokens.get(pos);
2118 pos--;
Owen Lin3413b892009-05-01 17:12:32 -07002119 // if we're about to tear down this window and not seek for
2120 // the behind activity, don't use it for orientation
2121 if (!findingBehind
2122 && (!wtoken.hidden && wtoken.hiddenRequested)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002123 continue;
2124 }
2125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002126 if (!haveGroup) {
2127 // We ignore any hidden applications on the top.
2128 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
2129 continue;
2130 }
2131 haveGroup = true;
2132 curGroup = wtoken.groupId;
2133 lastOrientation = wtoken.requestedOrientation;
2134 } else if (curGroup != wtoken.groupId) {
2135 // If we have hit a new application group, and the bottom
2136 // of the previous group didn't explicitly say to use
The Android Open Source Project4df24232009-03-05 14:34:35 -08002137 // the orientation behind it, and the last app was
2138 // full screen, then we'll stick with the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 // user's orientation.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002140 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
2141 && lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 return lastOrientation;
2143 }
2144 }
2145 int or = wtoken.requestedOrientation;
Owen Lin3413b892009-05-01 17:12:32 -07002146 // If this application is fullscreen, and didn't explicitly say
2147 // to use the orientation behind it, then just take whatever
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 // orientation it has and ignores whatever is under it.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002149 lastFullscreen = wtoken.appFullscreen;
Romain Guy06882f82009-06-10 13:36:04 -07002150 if (lastFullscreen
Owen Lin3413b892009-05-01 17:12:32 -07002151 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 return or;
2153 }
2154 // If this application has requested an explicit orientation,
2155 // then use it.
2156 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
2157 or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
2158 or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
2159 or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
2160 or == ActivityInfo.SCREEN_ORIENTATION_USER) {
2161 return or;
2162 }
Owen Lin3413b892009-05-01 17:12:32 -07002163 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
2165 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2166 }
Romain Guy06882f82009-06-10 13:36:04 -07002167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168 public Configuration updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002169 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002170 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2171 "updateOrientationFromAppTokens()")) {
2172 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
2173 }
2174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 Configuration config;
2176 long ident = Binder.clearCallingIdentity();
Dianne Hackborncfaef692009-06-15 14:24:44 -07002177 config = updateOrientationFromAppTokensUnchecked(currentConfig,
2178 freezeThisOneIfNeeded);
2179 Binder.restoreCallingIdentity(ident);
2180 return config;
2181 }
2182
2183 Configuration updateOrientationFromAppTokensUnchecked(
2184 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
2185 Configuration config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 synchronized(mWindowMap) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002187 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 }
2189 if (config != null) {
2190 mLayoutNeeded = true;
2191 performLayoutAndPlaceSurfacesLocked();
2192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 return config;
2194 }
Romain Guy06882f82009-06-10 13:36:04 -07002195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 /*
2197 * The orientation is computed from non-application windows first. If none of
2198 * the non-application windows specify orientation, the orientation is computed from
Romain Guy06882f82009-06-10 13:36:04 -07002199 * application tokens.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 * @see android.view.IWindowManager#updateOrientationFromAppTokens(
2201 * android.os.IBinder)
2202 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002203 Configuration updateOrientationFromAppTokensLocked(
The Android Open Source Project10592532009-03-18 17:39:46 -07002204 Configuration appConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 boolean changed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 long ident = Binder.clearCallingIdentity();
2207 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002208 int req = computeForcedAppOrientationLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 if (req != mForcedAppOrientation) {
2211 changed = true;
2212 mForcedAppOrientation = req;
2213 //send a message to Policy indicating orientation change to take
2214 //action like disabling/enabling sensors etc.,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002215 mPolicy.setCurrentOrientationLw(req);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
Romain Guy06882f82009-06-10 13:36:04 -07002217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 if (changed) {
2219 changed = setRotationUncheckedLocked(
Dianne Hackborn321ae682009-03-27 16:16:03 -07002220 WindowManagerPolicy.USE_LAST_ROTATION,
2221 mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 if (changed) {
2223 if (freezeThisOneIfNeeded != null) {
2224 AppWindowToken wtoken = findAppWindowToken(
2225 freezeThisOneIfNeeded);
2226 if (wtoken != null) {
2227 startAppFreezingScreenLocked(wtoken,
2228 ActivityInfo.CONFIG_ORIENTATION);
2229 }
2230 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07002231 return computeNewConfigurationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 }
2233 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002234
2235 // No obvious action we need to take, but if our current
2236 // state mismatches the activity maanager's, update it
2237 if (appConfig != null) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07002238 mTempConfiguration.setToDefaults();
2239 if (computeNewConfigurationLocked(mTempConfiguration)) {
2240 if (appConfig.diff(mTempConfiguration) != 0) {
2241 Log.i(TAG, "Config changed: " + mTempConfiguration);
2242 return new Configuration(mTempConfiguration);
2243 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002244 }
2245 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 } finally {
2247 Binder.restoreCallingIdentity(ident);
2248 }
Romain Guy06882f82009-06-10 13:36:04 -07002249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 return null;
2251 }
Romain Guy06882f82009-06-10 13:36:04 -07002252
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002253 int computeForcedAppOrientationLocked() {
2254 int req = getOrientationFromWindowsLocked();
2255 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
2256 req = getOrientationFromAppTokensLocked();
2257 }
2258 return req;
2259 }
Romain Guy06882f82009-06-10 13:36:04 -07002260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002261 public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
2262 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2263 "setAppOrientation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002264 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 }
Romain Guy06882f82009-06-10 13:36:04 -07002266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 synchronized(mWindowMap) {
2268 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2269 if (wtoken == null) {
2270 Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
2271 return;
2272 }
Romain Guy06882f82009-06-10 13:36:04 -07002273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 wtoken.requestedOrientation = requestedOrientation;
2275 }
2276 }
Romain Guy06882f82009-06-10 13:36:04 -07002277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 public int getAppOrientation(IApplicationToken token) {
2279 synchronized(mWindowMap) {
2280 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2281 if (wtoken == null) {
2282 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2283 }
Romain Guy06882f82009-06-10 13:36:04 -07002284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 return wtoken.requestedOrientation;
2286 }
2287 }
Romain Guy06882f82009-06-10 13:36:04 -07002288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 public void setFocusedApp(IBinder token, boolean moveFocusNow) {
2290 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2291 "setFocusedApp()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002292 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002293 }
2294
2295 synchronized(mWindowMap) {
2296 boolean changed = false;
2297 if (token == null) {
2298 if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
2299 changed = mFocusedApp != null;
2300 mFocusedApp = null;
2301 mKeyWaiter.tickle();
2302 } else {
2303 AppWindowToken newFocus = findAppWindowToken(token);
2304 if (newFocus == null) {
2305 Log.w(TAG, "Attempted to set focus to non-existing app token: " + token);
2306 return;
2307 }
2308 changed = mFocusedApp != newFocus;
2309 mFocusedApp = newFocus;
2310 if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp);
2311 mKeyWaiter.tickle();
2312 }
2313
2314 if (moveFocusNow && changed) {
2315 final long origId = Binder.clearCallingIdentity();
2316 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2317 Binder.restoreCallingIdentity(origId);
2318 }
2319 }
2320 }
2321
2322 public void prepareAppTransition(int transit) {
2323 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2324 "prepareAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002325 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 }
Romain Guy06882f82009-06-10 13:36:04 -07002327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002328 synchronized(mWindowMap) {
2329 if (DEBUG_APP_TRANSITIONS) Log.v(
2330 TAG, "Prepare app transition: transit=" + transit
2331 + " mNextAppTransition=" + mNextAppTransition);
2332 if (!mDisplayFrozen) {
2333 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
2334 mNextAppTransition = transit;
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002335 } else if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
2336 && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
2337 // Opening a new task always supersedes a close for the anim.
2338 mNextAppTransition = transit;
2339 } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2340 && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
2341 // Opening a new activity always supersedes a close for the anim.
2342 mNextAppTransition = transit;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 }
2344 mAppTransitionReady = false;
2345 mAppTransitionTimeout = false;
2346 mStartingIconInTransition = false;
2347 mSkipAppTransitionAnimation = false;
2348 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2349 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
2350 5000);
2351 }
2352 }
2353 }
2354
2355 public int getPendingAppTransition() {
2356 return mNextAppTransition;
2357 }
Romain Guy06882f82009-06-10 13:36:04 -07002358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002359 public void executeAppTransition() {
2360 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2361 "executeAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002362 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 }
Romain Guy06882f82009-06-10 13:36:04 -07002364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 synchronized(mWindowMap) {
2366 if (DEBUG_APP_TRANSITIONS) Log.v(
2367 TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
2368 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2369 mAppTransitionReady = true;
2370 final long origId = Binder.clearCallingIdentity();
2371 performLayoutAndPlaceSurfacesLocked();
2372 Binder.restoreCallingIdentity(origId);
2373 }
2374 }
2375 }
2376
2377 public void setAppStartingWindow(IBinder token, String pkg,
2378 int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
2379 IBinder transferFrom, boolean createIfNeeded) {
2380 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2381 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002382 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 }
2384
2385 synchronized(mWindowMap) {
2386 if (DEBUG_STARTING_WINDOW) Log.v(
2387 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
2388 + " transferFrom=" + transferFrom);
Romain Guy06882f82009-06-10 13:36:04 -07002389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002390 AppWindowToken wtoken = findAppWindowToken(token);
2391 if (wtoken == null) {
2392 Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
2393 return;
2394 }
2395
2396 // If the display is frozen, we won't do anything until the
2397 // actual window is displayed so there is no reason to put in
2398 // the starting window.
2399 if (mDisplayFrozen) {
2400 return;
2401 }
Romain Guy06882f82009-06-10 13:36:04 -07002402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002403 if (wtoken.startingData != null) {
2404 return;
2405 }
Romain Guy06882f82009-06-10 13:36:04 -07002406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407 if (transferFrom != null) {
2408 AppWindowToken ttoken = findAppWindowToken(transferFrom);
2409 if (ttoken != null) {
2410 WindowState startingWindow = ttoken.startingWindow;
2411 if (startingWindow != null) {
2412 if (mStartingIconInTransition) {
2413 // In this case, the starting icon has already
2414 // been displayed, so start letting windows get
2415 // shown immediately without any more transitions.
2416 mSkipAppTransitionAnimation = true;
2417 }
2418 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2419 "Moving existing starting from " + ttoken
2420 + " to " + wtoken);
2421 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07002422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002423 // Transfer the starting window over to the new
2424 // token.
2425 wtoken.startingData = ttoken.startingData;
2426 wtoken.startingView = ttoken.startingView;
2427 wtoken.startingWindow = startingWindow;
2428 ttoken.startingData = null;
2429 ttoken.startingView = null;
2430 ttoken.startingWindow = null;
2431 ttoken.startingMoved = true;
2432 startingWindow.mToken = wtoken;
Dianne Hackbornef49c572009-03-24 19:27:32 -07002433 startingWindow.mRootToken = wtoken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 startingWindow.mAppToken = wtoken;
2435 mWindows.remove(startingWindow);
2436 ttoken.windows.remove(startingWindow);
2437 ttoken.allAppWindows.remove(startingWindow);
2438 addWindowToListInOrderLocked(startingWindow, true);
2439 wtoken.allAppWindows.add(startingWindow);
Romain Guy06882f82009-06-10 13:36:04 -07002440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002441 // Propagate other interesting state between the
2442 // tokens. If the old token is displayed, we should
2443 // immediately force the new one to be displayed. If
2444 // it is animating, we need to move that animation to
2445 // the new one.
2446 if (ttoken.allDrawn) {
2447 wtoken.allDrawn = true;
2448 }
2449 if (ttoken.firstWindowDrawn) {
2450 wtoken.firstWindowDrawn = true;
2451 }
2452 if (!ttoken.hidden) {
2453 wtoken.hidden = false;
2454 wtoken.hiddenRequested = false;
2455 wtoken.willBeHidden = false;
2456 }
2457 if (wtoken.clientHidden != ttoken.clientHidden) {
2458 wtoken.clientHidden = ttoken.clientHidden;
2459 wtoken.sendAppVisibilityToClients();
2460 }
2461 if (ttoken.animation != null) {
2462 wtoken.animation = ttoken.animation;
2463 wtoken.animating = ttoken.animating;
2464 wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
2465 ttoken.animation = null;
2466 ttoken.animLayerAdjustment = 0;
2467 wtoken.updateLayers();
2468 ttoken.updateLayers();
2469 }
Romain Guy06882f82009-06-10 13:36:04 -07002470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002472 mLayoutNeeded = true;
2473 performLayoutAndPlaceSurfacesLocked();
2474 Binder.restoreCallingIdentity(origId);
2475 return;
2476 } else if (ttoken.startingData != null) {
2477 // The previous app was getting ready to show a
2478 // starting window, but hasn't yet done so. Steal it!
2479 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2480 "Moving pending starting from " + ttoken
2481 + " to " + wtoken);
2482 wtoken.startingData = ttoken.startingData;
2483 ttoken.startingData = null;
2484 ttoken.startingMoved = true;
2485 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2486 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2487 // want to process the message ASAP, before any other queued
2488 // messages.
2489 mH.sendMessageAtFrontOfQueue(m);
2490 return;
2491 }
2492 }
2493 }
2494
2495 // There is no existing starting window, and the caller doesn't
2496 // want us to create one, so that's it!
2497 if (!createIfNeeded) {
2498 return;
2499 }
Romain Guy06882f82009-06-10 13:36:04 -07002500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002501 mStartingIconInTransition = true;
2502 wtoken.startingData = new StartingData(
2503 pkg, theme, nonLocalizedLabel,
2504 labelRes, icon);
2505 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2506 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2507 // want to process the message ASAP, before any other queued
2508 // messages.
2509 mH.sendMessageAtFrontOfQueue(m);
2510 }
2511 }
2512
2513 public void setAppWillBeHidden(IBinder token) {
2514 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2515 "setAppWillBeHidden()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002516 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517 }
2518
2519 AppWindowToken wtoken;
2520
2521 synchronized(mWindowMap) {
2522 wtoken = findAppWindowToken(token);
2523 if (wtoken == null) {
2524 Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
2525 return;
2526 }
2527 wtoken.willBeHidden = true;
2528 }
2529 }
Romain Guy06882f82009-06-10 13:36:04 -07002530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002531 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
2532 boolean visible, int transit, boolean performLayout) {
2533 boolean delayed = false;
2534
2535 if (wtoken.clientHidden == visible) {
2536 wtoken.clientHidden = !visible;
2537 wtoken.sendAppVisibilityToClients();
2538 }
Romain Guy06882f82009-06-10 13:36:04 -07002539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 wtoken.willBeHidden = false;
2541 if (wtoken.hidden == visible) {
2542 final int N = wtoken.allAppWindows.size();
2543 boolean changed = false;
2544 if (DEBUG_APP_TRANSITIONS) Log.v(
2545 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
2546 + " performLayout=" + performLayout);
Romain Guy06882f82009-06-10 13:36:04 -07002547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 boolean runningAppAnimation = false;
Romain Guy06882f82009-06-10 13:36:04 -07002549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 if (transit != WindowManagerPolicy.TRANSIT_NONE) {
2551 if (wtoken.animation == sDummyAnimation) {
2552 wtoken.animation = null;
2553 }
2554 applyAnimationLocked(wtoken, lp, transit, visible);
2555 changed = true;
2556 if (wtoken.animation != null) {
2557 delayed = runningAppAnimation = true;
2558 }
2559 }
Romain Guy06882f82009-06-10 13:36:04 -07002560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 for (int i=0; i<N; i++) {
2562 WindowState win = wtoken.allAppWindows.get(i);
2563 if (win == wtoken.startingWindow) {
2564 continue;
2565 }
2566
2567 if (win.isAnimating()) {
2568 delayed = true;
2569 }
Romain Guy06882f82009-06-10 13:36:04 -07002570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
2572 //win.dump(" ");
2573 if (visible) {
2574 if (!win.isVisibleNow()) {
2575 if (!runningAppAnimation) {
2576 applyAnimationLocked(win,
2577 WindowManagerPolicy.TRANSIT_ENTER, true);
2578 }
2579 changed = true;
2580 }
2581 } else if (win.isVisibleNow()) {
2582 if (!runningAppAnimation) {
2583 applyAnimationLocked(win,
2584 WindowManagerPolicy.TRANSIT_EXIT, false);
2585 }
2586 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2587 KeyWaiter.RETURN_NOTHING);
2588 changed = true;
2589 }
2590 }
2591
2592 wtoken.hidden = wtoken.hiddenRequested = !visible;
2593 if (!visible) {
2594 unsetAppFreezingScreenLocked(wtoken, true, true);
2595 } else {
2596 // If we are being set visible, and the starting window is
2597 // not yet displayed, then make sure it doesn't get displayed.
2598 WindowState swin = wtoken.startingWindow;
2599 if (swin != null && (swin.mDrawPending
2600 || swin.mCommitDrawPending)) {
2601 swin.mPolicyVisibility = false;
2602 swin.mPolicyVisibilityAfterAnim = false;
2603 }
2604 }
Romain Guy06882f82009-06-10 13:36:04 -07002605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002606 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
2607 + ": hidden=" + wtoken.hidden + " hiddenRequested="
2608 + wtoken.hiddenRequested);
Romain Guy06882f82009-06-10 13:36:04 -07002609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 if (changed && performLayout) {
2611 mLayoutNeeded = true;
2612 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 performLayoutAndPlaceSurfacesLocked();
2614 }
2615 }
2616
2617 if (wtoken.animation != null) {
2618 delayed = true;
2619 }
Romain Guy06882f82009-06-10 13:36:04 -07002620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002621 return delayed;
2622 }
2623
2624 public void setAppVisibility(IBinder token, boolean visible) {
2625 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2626 "setAppVisibility()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002627 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 }
2629
2630 AppWindowToken wtoken;
2631
2632 synchronized(mWindowMap) {
2633 wtoken = findAppWindowToken(token);
2634 if (wtoken == null) {
2635 Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
2636 return;
2637 }
2638
2639 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
2640 RuntimeException e = new RuntimeException();
2641 e.fillInStackTrace();
2642 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
2643 + "): mNextAppTransition=" + mNextAppTransition
2644 + " hidden=" + wtoken.hidden
2645 + " hiddenRequested=" + wtoken.hiddenRequested, e);
2646 }
Romain Guy06882f82009-06-10 13:36:04 -07002647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002648 // If we are preparing an app transition, then delay changing
2649 // the visibility of this token until we execute that transition.
2650 if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2651 // Already in requested state, don't do anything more.
2652 if (wtoken.hiddenRequested != visible) {
2653 return;
2654 }
2655 wtoken.hiddenRequested = !visible;
Romain Guy06882f82009-06-10 13:36:04 -07002656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 if (DEBUG_APP_TRANSITIONS) Log.v(
2658 TAG, "Setting dummy animation on: " + wtoken);
2659 wtoken.setDummyAnimation();
2660 mOpeningApps.remove(wtoken);
2661 mClosingApps.remove(wtoken);
2662 wtoken.inPendingTransaction = true;
2663 if (visible) {
2664 mOpeningApps.add(wtoken);
2665 wtoken.allDrawn = false;
2666 wtoken.startingDisplayed = false;
2667 wtoken.startingMoved = false;
Romain Guy06882f82009-06-10 13:36:04 -07002668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002669 if (wtoken.clientHidden) {
2670 // In the case where we are making an app visible
2671 // but holding off for a transition, we still need
2672 // to tell the client to make its windows visible so
2673 // they get drawn. Otherwise, we will wait on
2674 // performing the transition until all windows have
2675 // been drawn, they never will be, and we are sad.
2676 wtoken.clientHidden = false;
2677 wtoken.sendAppVisibilityToClients();
2678 }
2679 } else {
2680 mClosingApps.add(wtoken);
2681 }
2682 return;
2683 }
Romain Guy06882f82009-06-10 13:36:04 -07002684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 final long origId = Binder.clearCallingIdentity();
2686 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
2687 wtoken.updateReportedVisibilityLocked();
2688 Binder.restoreCallingIdentity(origId);
2689 }
2690 }
2691
2692 void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
2693 boolean unfreezeSurfaceNow, boolean force) {
2694 if (wtoken.freezingScreen) {
2695 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
2696 + " force=" + force);
2697 final int N = wtoken.allAppWindows.size();
2698 boolean unfrozeWindows = false;
2699 for (int i=0; i<N; i++) {
2700 WindowState w = wtoken.allAppWindows.get(i);
2701 if (w.mAppFreezing) {
2702 w.mAppFreezing = false;
2703 if (w.mSurface != null && !w.mOrientationChanging) {
2704 w.mOrientationChanging = true;
2705 }
2706 unfrozeWindows = true;
2707 }
2708 }
2709 if (force || unfrozeWindows) {
2710 if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
2711 wtoken.freezingScreen = false;
2712 mAppsFreezingScreen--;
2713 }
2714 if (unfreezeSurfaceNow) {
2715 if (unfrozeWindows) {
2716 mLayoutNeeded = true;
2717 performLayoutAndPlaceSurfacesLocked();
2718 }
2719 if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
2720 stopFreezingDisplayLocked();
2721 }
2722 }
2723 }
2724 }
Romain Guy06882f82009-06-10 13:36:04 -07002725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 public void startAppFreezingScreenLocked(AppWindowToken wtoken,
2727 int configChanges) {
2728 if (DEBUG_ORIENTATION) {
2729 RuntimeException e = new RuntimeException();
2730 e.fillInStackTrace();
2731 Log.i(TAG, "Set freezing of " + wtoken.appToken
2732 + ": hidden=" + wtoken.hidden + " freezing="
2733 + wtoken.freezingScreen, e);
2734 }
2735 if (!wtoken.hiddenRequested) {
2736 if (!wtoken.freezingScreen) {
2737 wtoken.freezingScreen = true;
2738 mAppsFreezingScreen++;
2739 if (mAppsFreezingScreen == 1) {
2740 startFreezingDisplayLocked();
2741 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
2742 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
2743 5000);
2744 }
2745 }
2746 final int N = wtoken.allAppWindows.size();
2747 for (int i=0; i<N; i++) {
2748 WindowState w = wtoken.allAppWindows.get(i);
2749 w.mAppFreezing = true;
2750 }
2751 }
2752 }
Romain Guy06882f82009-06-10 13:36:04 -07002753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 public void startAppFreezingScreen(IBinder token, int configChanges) {
2755 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2756 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002757 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002758 }
2759
2760 synchronized(mWindowMap) {
2761 if (configChanges == 0 && !mDisplayFrozen) {
2762 if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
2763 return;
2764 }
Romain Guy06882f82009-06-10 13:36:04 -07002765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 AppWindowToken wtoken = findAppWindowToken(token);
2767 if (wtoken == null || wtoken.appToken == null) {
2768 Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
2769 return;
2770 }
2771 final long origId = Binder.clearCallingIdentity();
2772 startAppFreezingScreenLocked(wtoken, configChanges);
2773 Binder.restoreCallingIdentity(origId);
2774 }
2775 }
Romain Guy06882f82009-06-10 13:36:04 -07002776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002777 public void stopAppFreezingScreen(IBinder token, boolean force) {
2778 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2779 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002780 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 }
2782
2783 synchronized(mWindowMap) {
2784 AppWindowToken wtoken = findAppWindowToken(token);
2785 if (wtoken == null || wtoken.appToken == null) {
2786 return;
2787 }
2788 final long origId = Binder.clearCallingIdentity();
2789 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
2790 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
2791 unsetAppFreezingScreenLocked(wtoken, true, force);
2792 Binder.restoreCallingIdentity(origId);
2793 }
2794 }
Romain Guy06882f82009-06-10 13:36:04 -07002795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 public void removeAppToken(IBinder token) {
2797 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2798 "removeAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002799 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002800 }
2801
2802 AppWindowToken wtoken = null;
2803 AppWindowToken startingToken = null;
2804 boolean delayed = false;
2805
2806 final long origId = Binder.clearCallingIdentity();
2807 synchronized(mWindowMap) {
2808 WindowToken basewtoken = mTokenMap.remove(token);
2809 mTokenList.remove(basewtoken);
2810 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
2811 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
2812 delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
2813 wtoken.inPendingTransaction = false;
2814 mOpeningApps.remove(wtoken);
2815 if (mClosingApps.contains(wtoken)) {
2816 delayed = true;
2817 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2818 mClosingApps.add(wtoken);
2819 delayed = true;
2820 }
2821 if (DEBUG_APP_TRANSITIONS) Log.v(
2822 TAG, "Removing app " + wtoken + " delayed=" + delayed
2823 + " animation=" + wtoken.animation
2824 + " animating=" + wtoken.animating);
2825 if (delayed) {
2826 // set the token aside because it has an active animation to be finished
2827 mExitingAppTokens.add(wtoken);
2828 }
2829 mAppTokens.remove(wtoken);
2830 wtoken.removed = true;
2831 if (wtoken.startingData != null) {
2832 startingToken = wtoken;
2833 }
2834 unsetAppFreezingScreenLocked(wtoken, true, true);
2835 if (mFocusedApp == wtoken) {
2836 if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
2837 mFocusedApp = null;
2838 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2839 mKeyWaiter.tickle();
2840 }
2841 } else {
2842 Log.w(TAG, "Attempted to remove non-existing app token: " + token);
2843 }
Romain Guy06882f82009-06-10 13:36:04 -07002844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 if (!delayed && wtoken != null) {
2846 wtoken.updateReportedVisibilityLocked();
2847 }
2848 }
2849 Binder.restoreCallingIdentity(origId);
2850
2851 if (startingToken != null) {
2852 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
2853 + startingToken + ": app token removed");
2854 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
2855 mH.sendMessage(m);
2856 }
2857 }
2858
2859 private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
2860 final int NW = token.windows.size();
2861 for (int i=0; i<NW; i++) {
2862 WindowState win = token.windows.get(i);
2863 mWindows.remove(win);
2864 int j = win.mChildWindows.size();
2865 while (j > 0) {
2866 j--;
2867 mWindows.remove(win.mChildWindows.get(j));
2868 }
2869 }
2870 return NW > 0;
2871 }
2872
2873 void dumpAppTokensLocked() {
2874 for (int i=mAppTokens.size()-1; i>=0; i--) {
2875 Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
2876 }
2877 }
Romain Guy06882f82009-06-10 13:36:04 -07002878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 void dumpWindowsLocked() {
2880 for (int i=mWindows.size()-1; i>=0; i--) {
2881 Log.v(TAG, " #" + i + ": " + mWindows.get(i));
2882 }
2883 }
Romain Guy06882f82009-06-10 13:36:04 -07002884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 private int findWindowOffsetLocked(int tokenPos) {
2886 final int NW = mWindows.size();
2887
2888 if (tokenPos >= mAppTokens.size()) {
2889 int i = NW;
2890 while (i > 0) {
2891 i--;
2892 WindowState win = (WindowState)mWindows.get(i);
2893 if (win.getAppToken() != null) {
2894 return i+1;
2895 }
2896 }
2897 }
2898
2899 while (tokenPos > 0) {
2900 // Find the first app token below the new position that has
2901 // a window displayed.
2902 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
2903 if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
2904 + tokenPos + " -- " + wtoken.token);
2905 int i = wtoken.windows.size();
2906 while (i > 0) {
2907 i--;
2908 WindowState win = wtoken.windows.get(i);
2909 int j = win.mChildWindows.size();
2910 while (j > 0) {
2911 j--;
2912 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2913 if (cwin.mSubLayer >= 0 ) {
2914 for (int pos=NW-1; pos>=0; pos--) {
2915 if (mWindows.get(pos) == cwin) {
2916 if (DEBUG_REORDER) Log.v(TAG,
2917 "Found child win @" + (pos+1));
2918 return pos+1;
2919 }
2920 }
2921 }
2922 }
2923 for (int pos=NW-1; pos>=0; pos--) {
2924 if (mWindows.get(pos) == win) {
2925 if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
2926 return pos+1;
2927 }
2928 }
2929 }
2930 tokenPos--;
2931 }
2932
2933 return 0;
2934 }
2935
2936 private final int reAddWindowLocked(int index, WindowState win) {
2937 final int NCW = win.mChildWindows.size();
2938 boolean added = false;
2939 for (int j=0; j<NCW; j++) {
2940 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2941 if (!added && cwin.mSubLayer >= 0) {
2942 mWindows.add(index, win);
2943 index++;
2944 added = true;
2945 }
2946 mWindows.add(index, cwin);
2947 index++;
2948 }
2949 if (!added) {
2950 mWindows.add(index, win);
2951 index++;
2952 }
2953 return index;
2954 }
Romain Guy06882f82009-06-10 13:36:04 -07002955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956 private final int reAddAppWindowsLocked(int index, WindowToken token) {
2957 final int NW = token.windows.size();
2958 for (int i=0; i<NW; i++) {
2959 index = reAddWindowLocked(index, token.windows.get(i));
2960 }
2961 return index;
2962 }
2963
2964 public void moveAppToken(int index, IBinder token) {
2965 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2966 "moveAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002967 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 }
2969
2970 synchronized(mWindowMap) {
2971 if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
2972 if (DEBUG_REORDER) dumpAppTokensLocked();
2973 final AppWindowToken wtoken = findAppWindowToken(token);
2974 if (wtoken == null || !mAppTokens.remove(wtoken)) {
2975 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
2976 + token + " (" + wtoken + ")");
2977 return;
2978 }
2979 mAppTokens.add(index, wtoken);
2980 if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
2981 if (DEBUG_REORDER) dumpAppTokensLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 final long origId = Binder.clearCallingIdentity();
2984 if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
2985 if (DEBUG_REORDER) dumpWindowsLocked();
2986 if (tmpRemoveAppWindowsLocked(wtoken)) {
2987 if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:");
2988 if (DEBUG_REORDER) dumpWindowsLocked();
2989 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
2990 if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
2991 if (DEBUG_REORDER) dumpWindowsLocked();
2992 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993 mLayoutNeeded = true;
2994 performLayoutAndPlaceSurfacesLocked();
2995 }
2996 Binder.restoreCallingIdentity(origId);
2997 }
2998 }
2999
3000 private void removeAppTokensLocked(List<IBinder> tokens) {
3001 // XXX This should be done more efficiently!
3002 // (take advantage of the fact that both lists should be
3003 // ordered in the same way.)
3004 int N = tokens.size();
3005 for (int i=0; i<N; i++) {
3006 IBinder token = tokens.get(i);
3007 final AppWindowToken wtoken = findAppWindowToken(token);
3008 if (!mAppTokens.remove(wtoken)) {
3009 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
3010 + token + " (" + wtoken + ")");
3011 i--;
3012 N--;
3013 }
3014 }
3015 }
3016
3017 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
3018 // First remove all of the windows from the list.
3019 final int N = tokens.size();
3020 int i;
3021 for (i=0; i<N; i++) {
3022 WindowToken token = mTokenMap.get(tokens.get(i));
3023 if (token != null) {
3024 tmpRemoveAppWindowsLocked(token);
3025 }
3026 }
3027
3028 // Where to start adding?
3029 int pos = findWindowOffsetLocked(tokenPos);
3030
3031 // And now add them back at the correct place.
3032 for (i=0; i<N; i++) {
3033 WindowToken token = mTokenMap.get(tokens.get(i));
3034 if (token != null) {
3035 pos = reAddAppWindowsLocked(pos, token);
3036 }
3037 }
3038
3039 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003040 mLayoutNeeded = true;
3041 performLayoutAndPlaceSurfacesLocked();
3042
3043 //dump();
3044 }
3045
3046 public void moveAppTokensToTop(List<IBinder> tokens) {
3047 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3048 "moveAppTokensToTop()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003049 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003050 }
3051
3052 final long origId = Binder.clearCallingIdentity();
3053 synchronized(mWindowMap) {
3054 removeAppTokensLocked(tokens);
3055 final int N = tokens.size();
3056 for (int i=0; i<N; i++) {
3057 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3058 if (wt != null) {
3059 mAppTokens.add(wt);
3060 }
3061 }
3062 moveAppWindowsLocked(tokens, mAppTokens.size());
3063 }
3064 Binder.restoreCallingIdentity(origId);
3065 }
3066
3067 public void moveAppTokensToBottom(List<IBinder> tokens) {
3068 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3069 "moveAppTokensToBottom()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003070 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071 }
3072
3073 final long origId = Binder.clearCallingIdentity();
3074 synchronized(mWindowMap) {
3075 removeAppTokensLocked(tokens);
3076 final int N = tokens.size();
3077 int pos = 0;
3078 for (int i=0; i<N; i++) {
3079 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3080 if (wt != null) {
3081 mAppTokens.add(pos, wt);
3082 pos++;
3083 }
3084 }
3085 moveAppWindowsLocked(tokens, 0);
3086 }
3087 Binder.restoreCallingIdentity(origId);
3088 }
3089
3090 // -------------------------------------------------------------
3091 // Misc IWindowSession methods
3092 // -------------------------------------------------------------
Romain Guy06882f82009-06-10 13:36:04 -07003093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003094 public void disableKeyguard(IBinder token, String tag) {
3095 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3096 != PackageManager.PERMISSION_GRANTED) {
3097 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3098 }
3099 mKeyguardDisabled.acquire(token, tag);
3100 }
3101
3102 public void reenableKeyguard(IBinder token) {
3103 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3104 != PackageManager.PERMISSION_GRANTED) {
3105 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3106 }
3107 synchronized (mKeyguardDisabled) {
3108 mKeyguardDisabled.release(token);
3109
3110 if (!mKeyguardDisabled.isAcquired()) {
3111 // if we are the last one to reenable the keyguard wait until
3112 // we have actaully finished reenabling until returning
3113 mWaitingUntilKeyguardReenabled = true;
3114 while (mWaitingUntilKeyguardReenabled) {
3115 try {
3116 mKeyguardDisabled.wait();
3117 } catch (InterruptedException e) {
3118 Thread.currentThread().interrupt();
3119 }
3120 }
3121 }
3122 }
3123 }
3124
3125 /**
3126 * @see android.app.KeyguardManager#exitKeyguardSecurely
3127 */
3128 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
3129 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3130 != PackageManager.PERMISSION_GRANTED) {
3131 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3132 }
3133 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
3134 public void onKeyguardExitResult(boolean success) {
3135 try {
3136 callback.onKeyguardExitResult(success);
3137 } catch (RemoteException e) {
3138 // Client has died, we don't care.
3139 }
3140 }
3141 });
3142 }
3143
3144 public boolean inKeyguardRestrictedInputMode() {
3145 return mPolicy.inKeyguardRestrictedKeyInputMode();
3146 }
Romain Guy06882f82009-06-10 13:36:04 -07003147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 static float fixScale(float scale) {
3149 if (scale < 0) scale = 0;
3150 else if (scale > 20) scale = 20;
3151 return Math.abs(scale);
3152 }
Romain Guy06882f82009-06-10 13:36:04 -07003153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 public void setAnimationScale(int which, float scale) {
3155 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3156 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003157 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 }
3159
3160 if (scale < 0) scale = 0;
3161 else if (scale > 20) scale = 20;
3162 scale = Math.abs(scale);
3163 switch (which) {
3164 case 0: mWindowAnimationScale = fixScale(scale); break;
3165 case 1: mTransitionAnimationScale = fixScale(scale); break;
3166 }
Romain Guy06882f82009-06-10 13:36:04 -07003167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 // Persist setting
3169 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3170 }
Romain Guy06882f82009-06-10 13:36:04 -07003171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 public void setAnimationScales(float[] scales) {
3173 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3174 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003175 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 }
3177
3178 if (scales != null) {
3179 if (scales.length >= 1) {
3180 mWindowAnimationScale = fixScale(scales[0]);
3181 }
3182 if (scales.length >= 2) {
3183 mTransitionAnimationScale = fixScale(scales[1]);
3184 }
3185 }
Romain Guy06882f82009-06-10 13:36:04 -07003186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 // Persist setting
3188 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3189 }
Romain Guy06882f82009-06-10 13:36:04 -07003190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003191 public float getAnimationScale(int which) {
3192 switch (which) {
3193 case 0: return mWindowAnimationScale;
3194 case 1: return mTransitionAnimationScale;
3195 }
3196 return 0;
3197 }
Romain Guy06882f82009-06-10 13:36:04 -07003198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003199 public float[] getAnimationScales() {
3200 return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
3201 }
Romain Guy06882f82009-06-10 13:36:04 -07003202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 public int getSwitchState(int sw) {
3204 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3205 "getSwitchState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003206 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 }
3208 return KeyInputQueue.getSwitchState(sw);
3209 }
Romain Guy06882f82009-06-10 13:36:04 -07003210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 public int getSwitchStateForDevice(int devid, int sw) {
3212 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3213 "getSwitchStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003214 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003215 }
3216 return KeyInputQueue.getSwitchState(devid, sw);
3217 }
Romain Guy06882f82009-06-10 13:36:04 -07003218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 public int getScancodeState(int sw) {
3220 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3221 "getScancodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003222 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 }
3224 return KeyInputQueue.getScancodeState(sw);
3225 }
Romain Guy06882f82009-06-10 13:36:04 -07003226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 public int getScancodeStateForDevice(int devid, int sw) {
3228 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3229 "getScancodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003230 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 }
3232 return KeyInputQueue.getScancodeState(devid, sw);
3233 }
Romain Guy06882f82009-06-10 13:36:04 -07003234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003235 public int getKeycodeState(int sw) {
3236 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3237 "getKeycodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003238 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 }
3240 return KeyInputQueue.getKeycodeState(sw);
3241 }
Romain Guy06882f82009-06-10 13:36:04 -07003242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 public int getKeycodeStateForDevice(int devid, int sw) {
3244 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3245 "getKeycodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003246 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 }
3248 return KeyInputQueue.getKeycodeState(devid, sw);
3249 }
Romain Guy06882f82009-06-10 13:36:04 -07003250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
3252 return KeyInputQueue.hasKeys(keycodes, keyExists);
3253 }
Romain Guy06882f82009-06-10 13:36:04 -07003254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 public void enableScreenAfterBoot() {
3256 synchronized(mWindowMap) {
3257 if (mSystemBooted) {
3258 return;
3259 }
3260 mSystemBooted = true;
3261 }
Romain Guy06882f82009-06-10 13:36:04 -07003262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003263 performEnableScreen();
3264 }
Romain Guy06882f82009-06-10 13:36:04 -07003265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 public void enableScreenIfNeededLocked() {
3267 if (mDisplayEnabled) {
3268 return;
3269 }
3270 if (!mSystemBooted) {
3271 return;
3272 }
3273 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
3274 }
Romain Guy06882f82009-06-10 13:36:04 -07003275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003276 public void performEnableScreen() {
3277 synchronized(mWindowMap) {
3278 if (mDisplayEnabled) {
3279 return;
3280 }
3281 if (!mSystemBooted) {
3282 return;
3283 }
Romain Guy06882f82009-06-10 13:36:04 -07003284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 // Don't enable the screen until all existing windows
3286 // have been drawn.
3287 final int N = mWindows.size();
3288 for (int i=0; i<N; i++) {
3289 WindowState w = (WindowState)mWindows.get(i);
3290 if (w.isVisibleLw() && !w.isDisplayedLw()) {
3291 return;
3292 }
3293 }
Romain Guy06882f82009-06-10 13:36:04 -07003294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 mDisplayEnabled = true;
3296 if (false) {
3297 Log.i(TAG, "ENABLING SCREEN!");
3298 StringWriter sw = new StringWriter();
3299 PrintWriter pw = new PrintWriter(sw);
3300 this.dump(null, pw, null);
3301 Log.i(TAG, sw.toString());
3302 }
3303 try {
3304 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
3305 if (surfaceFlinger != null) {
3306 //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
3307 Parcel data = Parcel.obtain();
3308 data.writeInterfaceToken("android.ui.ISurfaceComposer");
3309 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
3310 data, null, 0);
3311 data.recycle();
3312 }
3313 } catch (RemoteException ex) {
3314 Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
3315 }
3316 }
Romain Guy06882f82009-06-10 13:36:04 -07003317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318 mPolicy.enableScreenAfterBoot();
Romain Guy06882f82009-06-10 13:36:04 -07003319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 // Make sure the last requested orientation has been applied.
Dianne Hackborn321ae682009-03-27 16:16:03 -07003321 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
3322 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003323 }
Romain Guy06882f82009-06-10 13:36:04 -07003324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 public void setInTouchMode(boolean mode) {
3326 synchronized(mWindowMap) {
3327 mInTouchMode = mode;
3328 }
3329 }
3330
Romain Guy06882f82009-06-10 13:36:04 -07003331 public void setRotation(int rotation,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003332 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003334 "setRotation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003335 throw new SecurityException("Requires SET_ORIENTATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 }
3337
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003338 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003339 }
Romain Guy06882f82009-06-10 13:36:04 -07003340
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003341 public void setRotationUnchecked(int rotation,
3342 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 if(DEBUG_ORIENTATION) Log.v(TAG,
3344 "alwaysSendConfiguration set to "+alwaysSendConfiguration);
Romain Guy06882f82009-06-10 13:36:04 -07003345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 long origId = Binder.clearCallingIdentity();
3347 boolean changed;
3348 synchronized(mWindowMap) {
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003349 changed = setRotationUncheckedLocked(rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
Romain Guy06882f82009-06-10 13:36:04 -07003351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 if (changed) {
3353 sendNewConfiguration();
3354 synchronized(mWindowMap) {
3355 mLayoutNeeded = true;
3356 performLayoutAndPlaceSurfacesLocked();
3357 }
3358 } else if (alwaysSendConfiguration) {
3359 //update configuration ignoring orientation change
3360 sendNewConfiguration();
3361 }
Romain Guy06882f82009-06-10 13:36:04 -07003362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 Binder.restoreCallingIdentity(origId);
3364 }
Romain Guy06882f82009-06-10 13:36:04 -07003365
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003366 public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 boolean changed;
3368 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
3369 rotation = mRequestedRotation;
3370 } else {
3371 mRequestedRotation = rotation;
Dianne Hackborn321ae682009-03-27 16:16:03 -07003372 mLastRotationFlags = animFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003373 }
3374 if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07003375 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 mRotation, mDisplayEnabled);
3377 if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
3378 changed = mDisplayEnabled && mRotation != rotation;
Romain Guy06882f82009-06-10 13:36:04 -07003379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 if (changed) {
Romain Guy06882f82009-06-10 13:36:04 -07003381 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 "Rotation changed to " + rotation
3383 + " from " + mRotation
3384 + " (forceApp=" + mForcedAppOrientation
3385 + ", req=" + mRequestedRotation + ")");
3386 mRotation = rotation;
3387 mWindowsFreezingScreen = true;
3388 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
3389 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
3390 2000);
3391 startFreezingDisplayLocked();
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003392 Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 mQueue.setOrientation(rotation);
3394 if (mDisplayEnabled) {
Dianne Hackborn321ae682009-03-27 16:16:03 -07003395 Surface.setOrientation(0, rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 }
3397 for (int i=mWindows.size()-1; i>=0; i--) {
3398 WindowState w = (WindowState)mWindows.get(i);
3399 if (w.mSurface != null) {
3400 w.mOrientationChanging = true;
3401 }
3402 }
3403 for (int i=mRotationWatchers.size()-1; i>=0; i--) {
3404 try {
3405 mRotationWatchers.get(i).onRotationChanged(rotation);
3406 } catch (RemoteException e) {
3407 }
3408 }
3409 } //end if changed
Romain Guy06882f82009-06-10 13:36:04 -07003410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 return changed;
3412 }
Romain Guy06882f82009-06-10 13:36:04 -07003413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 public int getRotation() {
3415 return mRotation;
3416 }
3417
3418 public int watchRotation(IRotationWatcher watcher) {
3419 final IBinder watcherBinder = watcher.asBinder();
3420 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
3421 public void binderDied() {
3422 synchronized (mWindowMap) {
3423 for (int i=0; i<mRotationWatchers.size(); i++) {
3424 if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07003425 IRotationWatcher removed = mRotationWatchers.remove(i);
3426 if (removed != null) {
3427 removed.asBinder().unlinkToDeath(this, 0);
3428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 i--;
3430 }
3431 }
3432 }
3433 }
3434 };
Romain Guy06882f82009-06-10 13:36:04 -07003435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 synchronized (mWindowMap) {
3437 try {
3438 watcher.asBinder().linkToDeath(dr, 0);
3439 mRotationWatchers.add(watcher);
3440 } catch (RemoteException e) {
3441 // Client died, no cleanup needed.
3442 }
Romain Guy06882f82009-06-10 13:36:04 -07003443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444 return mRotation;
3445 }
3446 }
3447
3448 /**
3449 * Starts the view server on the specified port.
3450 *
3451 * @param port The port to listener to.
3452 *
3453 * @return True if the server was successfully started, false otherwise.
3454 *
3455 * @see com.android.server.ViewServer
3456 * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
3457 */
3458 public boolean startViewServer(int port) {
Romain Guy06882f82009-06-10 13:36:04 -07003459 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 return false;
3461 }
3462
3463 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
3464 return false;
3465 }
3466
3467 if (port < 1024) {
3468 return false;
3469 }
3470
3471 if (mViewServer != null) {
3472 if (!mViewServer.isRunning()) {
3473 try {
3474 return mViewServer.start();
3475 } catch (IOException e) {
Romain Guy06882f82009-06-10 13:36:04 -07003476 Log.w(TAG, "View server did not start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 }
3478 }
3479 return false;
3480 }
3481
3482 try {
3483 mViewServer = new ViewServer(this, port);
3484 return mViewServer.start();
3485 } catch (IOException e) {
3486 Log.w(TAG, "View server did not start");
3487 }
3488 return false;
3489 }
3490
Romain Guy06882f82009-06-10 13:36:04 -07003491 private boolean isSystemSecure() {
3492 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
3493 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
3494 }
3495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 /**
3497 * Stops the view server if it exists.
3498 *
3499 * @return True if the server stopped, false if it wasn't started or
3500 * couldn't be stopped.
3501 *
3502 * @see com.android.server.ViewServer
3503 */
3504 public boolean stopViewServer() {
Romain Guy06882f82009-06-10 13:36:04 -07003505 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 return false;
3507 }
3508
3509 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
3510 return false;
3511 }
3512
3513 if (mViewServer != null) {
3514 return mViewServer.stop();
3515 }
3516 return false;
3517 }
3518
3519 /**
3520 * Indicates whether the view server is running.
3521 *
3522 * @return True if the server is running, false otherwise.
3523 *
3524 * @see com.android.server.ViewServer
3525 */
3526 public boolean isViewServerRunning() {
Romain Guy06882f82009-06-10 13:36:04 -07003527 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 return false;
3529 }
3530
3531 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
3532 return false;
3533 }
3534
3535 return mViewServer != null && mViewServer.isRunning();
3536 }
3537
3538 /**
3539 * Lists all availble windows in the system. The listing is written in the
3540 * specified Socket's output stream with the following syntax:
3541 * windowHashCodeInHexadecimal windowName
3542 * Each line of the ouput represents a different window.
3543 *
3544 * @param client The remote client to send the listing to.
3545 * @return False if an error occured, true otherwise.
3546 */
3547 boolean viewServerListWindows(Socket client) {
Romain Guy06882f82009-06-10 13:36:04 -07003548 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 return false;
3550 }
3551
3552 boolean result = true;
3553
3554 Object[] windows;
3555 synchronized (mWindowMap) {
3556 windows = new Object[mWindows.size()];
3557 //noinspection unchecked
3558 windows = mWindows.toArray(windows);
3559 }
3560
3561 BufferedWriter out = null;
3562
3563 // Any uncaught exception will crash the system process
3564 try {
3565 OutputStream clientStream = client.getOutputStream();
3566 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
3567
3568 final int count = windows.length;
3569 for (int i = 0; i < count; i++) {
3570 final WindowState w = (WindowState) windows[i];
3571 out.write(Integer.toHexString(System.identityHashCode(w)));
3572 out.write(' ');
3573 out.append(w.mAttrs.getTitle());
3574 out.write('\n');
3575 }
3576
3577 out.write("DONE.\n");
3578 out.flush();
3579 } catch (Exception e) {
3580 result = false;
3581 } finally {
3582 if (out != null) {
3583 try {
3584 out.close();
3585 } catch (IOException e) {
3586 result = false;
3587 }
3588 }
3589 }
3590
3591 return result;
3592 }
3593
3594 /**
3595 * Sends a command to a target window. The result of the command, if any, will be
3596 * written in the output stream of the specified socket.
3597 *
3598 * The parameters must follow this syntax:
3599 * windowHashcode extra
3600 *
3601 * Where XX is the length in characeters of the windowTitle.
3602 *
3603 * The first parameter is the target window. The window with the specified hashcode
3604 * will be the target. If no target can be found, nothing happens. The extra parameters
3605 * will be delivered to the target window and as parameters to the command itself.
3606 *
3607 * @param client The remote client to sent the result, if any, to.
3608 * @param command The command to execute.
3609 * @param parameters The command parameters.
3610 *
3611 * @return True if the command was successfully delivered, false otherwise. This does
3612 * not indicate whether the command itself was successful.
3613 */
3614 boolean viewServerWindowCommand(Socket client, String command, String parameters) {
Romain Guy06882f82009-06-10 13:36:04 -07003615 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003616 return false;
3617 }
3618
3619 boolean success = true;
3620 Parcel data = null;
3621 Parcel reply = null;
3622
3623 // Any uncaught exception will crash the system process
3624 try {
3625 // Find the hashcode of the window
3626 int index = parameters.indexOf(' ');
3627 if (index == -1) {
3628 index = parameters.length();
3629 }
3630 final String code = parameters.substring(0, index);
3631 int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
3632
3633 // Extract the command's parameter after the window description
3634 if (index < parameters.length()) {
3635 parameters = parameters.substring(index + 1);
3636 } else {
3637 parameters = "";
3638 }
3639
3640 final WindowManagerService.WindowState window = findWindow(hashCode);
3641 if (window == null) {
3642 return false;
3643 }
3644
3645 data = Parcel.obtain();
3646 data.writeInterfaceToken("android.view.IWindow");
3647 data.writeString(command);
3648 data.writeString(parameters);
3649 data.writeInt(1);
3650 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
3651
3652 reply = Parcel.obtain();
3653
3654 final IBinder binder = window.mClient.asBinder();
3655 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
3656 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
3657
3658 reply.readException();
3659
3660 } catch (Exception e) {
3661 Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
3662 success = false;
3663 } finally {
3664 if (data != null) {
3665 data.recycle();
3666 }
3667 if (reply != null) {
3668 reply.recycle();
3669 }
3670 }
3671
3672 return success;
3673 }
3674
3675 private WindowState findWindow(int hashCode) {
3676 if (hashCode == -1) {
3677 return getFocusedWindow();
3678 }
3679
3680 synchronized (mWindowMap) {
3681 final ArrayList windows = mWindows;
3682 final int count = windows.size();
3683
3684 for (int i = 0; i < count; i++) {
3685 WindowState w = (WindowState) windows.get(i);
3686 if (System.identityHashCode(w) == hashCode) {
3687 return w;
3688 }
3689 }
3690 }
3691
3692 return null;
3693 }
3694
3695 /*
3696 * Instruct the Activity Manager to fetch the current configuration and broadcast
3697 * that to config-changed listeners if appropriate.
3698 */
3699 void sendNewConfiguration() {
3700 try {
3701 mActivityManager.updateConfiguration(null);
3702 } catch (RemoteException e) {
3703 }
3704 }
Romain Guy06882f82009-06-10 13:36:04 -07003705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 public Configuration computeNewConfiguration() {
3707 synchronized (mWindowMap) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07003708 return computeNewConfigurationLocked();
3709 }
3710 }
Romain Guy06882f82009-06-10 13:36:04 -07003711
Dianne Hackbornc485a602009-03-24 22:39:49 -07003712 Configuration computeNewConfigurationLocked() {
3713 Configuration config = new Configuration();
3714 if (!computeNewConfigurationLocked(config)) {
3715 return null;
3716 }
3717 Log.i(TAG, "Config changed: " + config);
3718 long now = SystemClock.uptimeMillis();
3719 //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
3720 if (mFreezeGcPending != 0) {
3721 if (now > (mFreezeGcPending+1000)) {
3722 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
3723 mH.removeMessages(H.FORCE_GC);
3724 Runtime.getRuntime().gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 mFreezeGcPending = now;
3726 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003727 } else {
3728 mFreezeGcPending = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003729 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003730 return config;
3731 }
Romain Guy06882f82009-06-10 13:36:04 -07003732
Dianne Hackbornc485a602009-03-24 22:39:49 -07003733 boolean computeNewConfigurationLocked(Configuration config) {
3734 if (mDisplay == null) {
3735 return false;
3736 }
3737 mQueue.getInputConfiguration(config);
3738 final int dw = mDisplay.getWidth();
3739 final int dh = mDisplay.getHeight();
3740 int orientation = Configuration.ORIENTATION_SQUARE;
3741 if (dw < dh) {
3742 orientation = Configuration.ORIENTATION_PORTRAIT;
3743 } else if (dw > dh) {
3744 orientation = Configuration.ORIENTATION_LANDSCAPE;
3745 }
3746 config.orientation = orientation;
Dianne Hackborn723738c2009-06-25 19:48:04 -07003747
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07003748 DisplayMetrics dm = new DisplayMetrics();
3749 mDisplay.getMetrics(dm);
3750 CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
3751
Dianne Hackborn723738c2009-06-25 19:48:04 -07003752 if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
3753 // Note we only do this once because at this point we don't
3754 // expect the screen to change in this way at runtime, and want
3755 // to avoid all of this computation for every config change.
Dianne Hackborn723738c2009-06-25 19:48:04 -07003756 int longSize = dw;
3757 int shortSize = dh;
3758 if (longSize < shortSize) {
3759 int tmp = longSize;
3760 longSize = shortSize;
3761 shortSize = tmp;
3762 }
3763 longSize = (int)(longSize/dm.density);
3764 shortSize = (int)(shortSize/dm.density);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07003765
Dianne Hackborn723738c2009-06-25 19:48:04 -07003766 // These semi-magic numbers define our compatibility modes for
3767 // applications with different screens. Don't change unless you
3768 // make sure to test lots and lots of apps!
3769 if (longSize < 470) {
3770 // This is shorter than an HVGA normal density screen (which
3771 // is 480 pixels on its long side).
3772 screenLayout = Configuration.SCREENLAYOUT_SMALL;
3773 } else if (longSize > 490 && shortSize > 330) {
3774 // This is larger than an HVGA normal density screen (which
3775 // is 480x320 pixels).
3776 screenLayout = Configuration.SCREENLAYOUT_LARGE;
3777 } else {
3778 screenLayout = Configuration.SCREENLAYOUT_NORMAL;
3779 }
3780 }
3781 config.screenLayout = screenLayout;
3782
Dianne Hackbornc485a602009-03-24 22:39:49 -07003783 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
3784 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
3785 mPolicy.adjustConfigurationLw(config);
3786 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003787 }
Romain Guy06882f82009-06-10 13:36:04 -07003788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789 // -------------------------------------------------------------
3790 // Input Events and Focus Management
3791 // -------------------------------------------------------------
3792
3793 private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
Michael Chane96440f2009-05-06 10:27:36 -07003794 long curTime = SystemClock.uptimeMillis();
3795
3796 if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
3797 if (mLastTouchEventType == eventType &&
3798 (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
3799 return;
3800 }
3801 mLastUserActivityCallTime = curTime;
3802 mLastTouchEventType = eventType;
3803 }
3804
3805 if (targetWin == null
3806 || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
3807 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003808 }
3809 }
3810
3811 // tells if it's a cheek event or not -- this function is stateful
3812 private static final int EVENT_NONE = 0;
3813 private static final int EVENT_UNKNOWN = 0;
3814 private static final int EVENT_CHEEK = 0;
3815 private static final int EVENT_IGNORE_DURATION = 300; // ms
3816 private static final float CHEEK_THRESHOLD = 0.6f;
3817 private int mEventState = EVENT_NONE;
3818 private float mEventSize;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 private int eventType(MotionEvent ev) {
3821 float size = ev.getSize();
3822 switch (ev.getAction()) {
3823 case MotionEvent.ACTION_DOWN:
3824 mEventSize = size;
3825 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
3826 case MotionEvent.ACTION_UP:
3827 if (size > mEventSize) mEventSize = size;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003828 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 case MotionEvent.ACTION_MOVE:
3830 final int N = ev.getHistorySize();
3831 if (size > mEventSize) mEventSize = size;
3832 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3833 for (int i=0; i<N; i++) {
3834 size = ev.getHistoricalSize(i);
3835 if (size > mEventSize) mEventSize = size;
3836 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3837 }
3838 if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
3839 return TOUCH_EVENT;
3840 } else {
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003841 return LONG_TOUCH_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003842 }
3843 default:
3844 // not good
3845 return OTHER_EVENT;
3846 }
3847 }
3848
3849 /**
3850 * @return Returns true if event was dispatched, false if it was dropped for any reason
3851 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07003852 private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003853 if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
3854 "dispatchPointer " + ev);
3855
3856 Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07003857 ev, true, false, pid, uid);
Romain Guy06882f82009-06-10 13:36:04 -07003858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 int action = ev.getAction();
Romain Guy06882f82009-06-10 13:36:04 -07003860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003861 if (action == MotionEvent.ACTION_UP) {
3862 // let go of our target
3863 mKeyWaiter.mMotionTarget = null;
3864 mPowerManager.logPointerUpEvent();
3865 } else if (action == MotionEvent.ACTION_DOWN) {
3866 mPowerManager.logPointerDownEvent();
3867 }
3868
3869 if (targetObj == null) {
3870 // In this case we are either dropping the event, or have received
3871 // a move or up without a down. It is common to receive move
3872 // events in such a way, since this means the user is moving the
3873 // pointer without actually pressing down. All other cases should
3874 // be atypical, so let's log them.
Michael Chane96440f2009-05-06 10:27:36 -07003875 if (action != MotionEvent.ACTION_MOVE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
3877 }
3878 if (qev != null) {
3879 mQueue.recycleEvent(qev);
3880 }
3881 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003882 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003883 }
3884 if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3885 if (qev != null) {
3886 mQueue.recycleEvent(qev);
3887 }
3888 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003889 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 }
Romain Guy06882f82009-06-10 13:36:04 -07003891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003892 WindowState target = (WindowState)targetObj;
Romain Guy06882f82009-06-10 13:36:04 -07003893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003894 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07003895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003896 //Log.i(TAG, "Sending " + ev + " to " + target);
3897
3898 if (uid != 0 && uid != target.mSession.mUid) {
3899 if (mContext.checkPermission(
3900 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3901 != PackageManager.PERMISSION_GRANTED) {
3902 Log.w(TAG, "Permission denied: injecting pointer event from pid "
3903 + pid + " uid " + uid + " to window " + target
3904 + " owned by uid " + target.mSession.mUid);
3905 if (qev != null) {
3906 mQueue.recycleEvent(qev);
3907 }
3908 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003909 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003910 }
3911 }
Romain Guy06882f82009-06-10 13:36:04 -07003912
3913 if ((target.mAttrs.flags &
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003914 WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
3915 //target wants to ignore fat touch events
3916 boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
3917 //explicit flag to return without processing event further
3918 boolean returnFlag = false;
3919 if((action == MotionEvent.ACTION_DOWN)) {
3920 mFatTouch = false;
3921 if(cheekPress) {
3922 mFatTouch = true;
3923 returnFlag = true;
3924 }
3925 } else {
3926 if(action == MotionEvent.ACTION_UP) {
3927 if(mFatTouch) {
3928 //earlier even was invalid doesnt matter if current up is cheekpress or not
3929 mFatTouch = false;
3930 returnFlag = true;
3931 } else if(cheekPress) {
3932 //cancel the earlier event
3933 ev.setAction(MotionEvent.ACTION_CANCEL);
3934 action = MotionEvent.ACTION_CANCEL;
3935 }
3936 } else if(action == MotionEvent.ACTION_MOVE) {
3937 if(mFatTouch) {
3938 //two cases here
3939 //an invalid down followed by 0 or moves(valid or invalid)
Romain Guy06882f82009-06-10 13:36:04 -07003940 //a valid down, invalid move, more moves. want to ignore till up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003941 returnFlag = true;
3942 } else if(cheekPress) {
3943 //valid down followed by invalid moves
3944 //an invalid move have to cancel earlier action
3945 ev.setAction(MotionEvent.ACTION_CANCEL);
3946 action = MotionEvent.ACTION_CANCEL;
3947 if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE");
3948 //note that the subsequent invalid moves will not get here
3949 mFatTouch = true;
3950 }
3951 }
3952 } //else if action
3953 if(returnFlag) {
3954 //recycle que, ev
3955 if (qev != null) {
3956 mQueue.recycleEvent(qev);
3957 }
3958 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003959 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960 }
3961 } //end if target
Michael Chane96440f2009-05-06 10:27:36 -07003962
3963 // TODO remove once we settle on a value or make it app specific
3964 if (action == MotionEvent.ACTION_DOWN) {
3965 int max_events_per_sec = 35;
3966 try {
3967 max_events_per_sec = Integer.parseInt(SystemProperties
3968 .get("windowsmgr.max_events_per_sec"));
3969 if (max_events_per_sec < 1) {
3970 max_events_per_sec = 35;
3971 }
3972 } catch (NumberFormatException e) {
3973 }
3974 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
3975 }
3976
3977 /*
3978 * Throttle events to minimize CPU usage when there's a flood of events
3979 * e.g. constant contact with the screen
3980 */
3981 if (action == MotionEvent.ACTION_MOVE) {
3982 long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
3983 long now = SystemClock.uptimeMillis();
3984 if (now < nextEventTime) {
3985 try {
3986 Thread.sleep(nextEventTime - now);
3987 } catch (InterruptedException e) {
3988 }
3989 mLastTouchEventTime = nextEventTime;
3990 } else {
3991 mLastTouchEventTime = now;
3992 }
3993 }
3994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003995 synchronized(mWindowMap) {
3996 if (qev != null && action == MotionEvent.ACTION_MOVE) {
3997 mKeyWaiter.bindTargetWindowLocked(target,
3998 KeyWaiter.RETURN_PENDING_POINTER, qev);
3999 ev = null;
4000 } else {
4001 if (action == MotionEvent.ACTION_DOWN) {
4002 WindowState out = mKeyWaiter.mOutsideTouchTargets;
4003 if (out != null) {
4004 MotionEvent oev = MotionEvent.obtain(ev);
4005 oev.setAction(MotionEvent.ACTION_OUTSIDE);
4006 do {
4007 final Rect frame = out.mFrame;
4008 oev.offsetLocation(-(float)frame.left, -(float)frame.top);
4009 try {
4010 out.mClient.dispatchPointer(oev, eventTime);
4011 } catch (android.os.RemoteException e) {
4012 Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
4013 }
4014 oev.offsetLocation((float)frame.left, (float)frame.top);
4015 out = out.mNextOutsideTouch;
4016 } while (out != null);
4017 mKeyWaiter.mOutsideTouchTargets = null;
4018 }
4019 }
4020 final Rect frame = target.mFrame;
4021 ev.offsetLocation(-(float)frame.left, -(float)frame.top);
4022 mKeyWaiter.bindTargetWindowLocked(target);
4023 }
4024 }
Romain Guy06882f82009-06-10 13:36:04 -07004025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026 // finally offset the event to the target's coordinate system and
4027 // dispatch the event.
4028 try {
4029 if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
4030 Log.v(TAG, "Delivering pointer " + qev + " to " + target);
4031 }
4032 target.mClient.dispatchPointer(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004033 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004034 } catch (android.os.RemoteException e) {
4035 Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
4036 mKeyWaiter.mMotionTarget = null;
4037 try {
4038 removeWindow(target.mSession, target.mClient);
4039 } catch (java.util.NoSuchElementException ex) {
4040 // This will happen if the window has already been
4041 // removed.
4042 }
4043 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004044 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004045 }
Romain Guy06882f82009-06-10 13:36:04 -07004046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004047 /**
4048 * @return Returns true if event was dispatched, false if it was dropped for any reason
4049 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004050 private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004051 if (DEBUG_INPUT) Log.v(
4052 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
Romain Guy06882f82009-06-10 13:36:04 -07004053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004055 ev, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004056 if (focusObj == null) {
4057 Log.w(TAG, "No focus window, dropping trackball: " + ev);
4058 if (qev != null) {
4059 mQueue.recycleEvent(qev);
4060 }
4061 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004062 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063 }
4064 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
4065 if (qev != null) {
4066 mQueue.recycleEvent(qev);
4067 }
4068 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004069 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004070 }
Romain Guy06882f82009-06-10 13:36:04 -07004071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004072 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004074 if (uid != 0 && uid != focus.mSession.mUid) {
4075 if (mContext.checkPermission(
4076 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4077 != PackageManager.PERMISSION_GRANTED) {
4078 Log.w(TAG, "Permission denied: injecting key event from pid "
4079 + pid + " uid " + uid + " to window " + focus
4080 + " owned by uid " + focus.mSession.mUid);
4081 if (qev != null) {
4082 mQueue.recycleEvent(qev);
4083 }
4084 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004085 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004086 }
4087 }
Romain Guy06882f82009-06-10 13:36:04 -07004088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004089 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 synchronized(mWindowMap) {
4092 if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
4093 mKeyWaiter.bindTargetWindowLocked(focus,
4094 KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
4095 // We don't deliver movement events to the client, we hold
4096 // them and wait for them to call back.
4097 ev = null;
4098 } else {
4099 mKeyWaiter.bindTargetWindowLocked(focus);
4100 }
4101 }
Romain Guy06882f82009-06-10 13:36:04 -07004102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 try {
4104 focus.mClient.dispatchTrackball(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004105 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004106 } catch (android.os.RemoteException e) {
4107 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4108 try {
4109 removeWindow(focus.mSession, focus.mClient);
4110 } catch (java.util.NoSuchElementException ex) {
4111 // This will happen if the window has already been
4112 // removed.
4113 }
4114 }
Romain Guy06882f82009-06-10 13:36:04 -07004115
Dianne Hackborncfaef692009-06-15 14:24:44 -07004116 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004117 }
Romain Guy06882f82009-06-10 13:36:04 -07004118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004119 /**
4120 * @return Returns true if event was dispatched, false if it was dropped for any reason
4121 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004122 private int dispatchKey(KeyEvent event, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004123 if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
4124
4125 Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004126 null, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 if (focusObj == null) {
4128 Log.w(TAG, "No focus window, dropping: " + event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004129 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004130 }
4131 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004132 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133 }
Romain Guy06882f82009-06-10 13:36:04 -07004134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004135 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004137 if (DEBUG_INPUT) Log.v(
4138 TAG, "Dispatching to " + focus + ": " + event);
4139
4140 if (uid != 0 && uid != focus.mSession.mUid) {
4141 if (mContext.checkPermission(
4142 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4143 != PackageManager.PERMISSION_GRANTED) {
4144 Log.w(TAG, "Permission denied: injecting key event from pid "
4145 + pid + " uid " + uid + " to window " + focus
4146 + " owned by uid " + focus.mSession.mUid);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004147 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004148 }
4149 }
Romain Guy06882f82009-06-10 13:36:04 -07004150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004151 synchronized(mWindowMap) {
4152 mKeyWaiter.bindTargetWindowLocked(focus);
4153 }
4154
4155 // NOSHIP extra state logging
4156 mKeyWaiter.recordDispatchState(event, focus);
4157 // END NOSHIP
Romain Guy06882f82009-06-10 13:36:04 -07004158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 try {
4160 if (DEBUG_INPUT || DEBUG_FOCUS) {
4161 Log.v(TAG, "Delivering key " + event.getKeyCode()
4162 + " to " + focus);
4163 }
4164 focus.mClient.dispatchKey(event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004165 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004166 } catch (android.os.RemoteException e) {
4167 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4168 try {
4169 removeWindow(focus.mSession, focus.mClient);
4170 } catch (java.util.NoSuchElementException ex) {
4171 // This will happen if the window has already been
4172 // removed.
4173 }
4174 }
Romain Guy06882f82009-06-10 13:36:04 -07004175
Dianne Hackborncfaef692009-06-15 14:24:44 -07004176 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004177 }
Romain Guy06882f82009-06-10 13:36:04 -07004178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 public void pauseKeyDispatching(IBinder _token) {
4180 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4181 "pauseKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004182 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004183 }
4184
4185 synchronized (mWindowMap) {
4186 WindowToken token = mTokenMap.get(_token);
4187 if (token != null) {
4188 mKeyWaiter.pauseDispatchingLocked(token);
4189 }
4190 }
4191 }
4192
4193 public void resumeKeyDispatching(IBinder _token) {
4194 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4195 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004196 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197 }
4198
4199 synchronized (mWindowMap) {
4200 WindowToken token = mTokenMap.get(_token);
4201 if (token != null) {
4202 mKeyWaiter.resumeDispatchingLocked(token);
4203 }
4204 }
4205 }
4206
4207 public void setEventDispatching(boolean enabled) {
4208 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4209 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004210 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004211 }
4212
4213 synchronized (mWindowMap) {
4214 mKeyWaiter.setEventDispatchingLocked(enabled);
4215 }
4216 }
Romain Guy06882f82009-06-10 13:36:04 -07004217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004218 /**
4219 * Injects a keystroke event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004220 *
4221 * @param ev A motion event describing the keystroke action. (Be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004222 * {@link SystemClock#uptimeMillis()} as the timebase.)
4223 * @param sync If true, wait for the event to be completed before returning to the caller.
4224 * @return Returns true if event was dispatched, false if it was dropped for any reason
4225 */
4226 public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
4227 long downTime = ev.getDownTime();
4228 long eventTime = ev.getEventTime();
4229
4230 int action = ev.getAction();
4231 int code = ev.getKeyCode();
4232 int repeatCount = ev.getRepeatCount();
4233 int metaState = ev.getMetaState();
4234 int deviceId = ev.getDeviceId();
4235 int scancode = ev.getScanCode();
4236
4237 if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
4238 if (downTime == 0) downTime = eventTime;
4239
4240 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
The Android Open Source Project10592532009-03-18 17:39:46 -07004241 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004242
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004243 final int pid = Binder.getCallingPid();
4244 final int uid = Binder.getCallingUid();
4245 final long ident = Binder.clearCallingIdentity();
4246 final int result = dispatchKey(newEvent, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004247 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004248 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004249 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004250 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004251 switch (result) {
4252 case INJECT_NO_PERMISSION:
4253 throw new SecurityException(
4254 "Injecting to another application requires INJECT_EVENT permission");
4255 case INJECT_SUCCEEDED:
4256 return true;
4257 }
4258 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004259 }
4260
4261 /**
4262 * Inject a pointer (touch) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004263 *
4264 * @param ev A motion event describing the pointer (touch) action. (As noted in
4265 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266 * {@link SystemClock#uptimeMillis()} as the timebase.)
4267 * @param sync If true, wait for the event to be completed before returning to the caller.
4268 * @return Returns true if event was dispatched, false if it was dropped for any reason
4269 */
4270 public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004271 final int pid = Binder.getCallingPid();
4272 final int uid = Binder.getCallingUid();
4273 final long ident = Binder.clearCallingIdentity();
4274 final int result = dispatchPointer(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004275 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004276 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004277 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004278 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004279 switch (result) {
4280 case INJECT_NO_PERMISSION:
4281 throw new SecurityException(
4282 "Injecting to another application requires INJECT_EVENT permission");
4283 case INJECT_SUCCEEDED:
4284 return true;
4285 }
4286 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004287 }
Romain Guy06882f82009-06-10 13:36:04 -07004288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004289 /**
4290 * Inject a trackball (navigation device) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004291 *
4292 * @param ev A motion event describing the trackball action. (As noted in
4293 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004294 * {@link SystemClock#uptimeMillis()} as the timebase.)
4295 * @param sync If true, wait for the event to be completed before returning to the caller.
4296 * @return Returns true if event was dispatched, false if it was dropped for any reason
4297 */
4298 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004299 final int pid = Binder.getCallingPid();
4300 final int uid = Binder.getCallingUid();
4301 final long ident = Binder.clearCallingIdentity();
4302 final int result = dispatchTrackball(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004303 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004304 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004305 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004306 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004307 switch (result) {
4308 case INJECT_NO_PERMISSION:
4309 throw new SecurityException(
4310 "Injecting to another application requires INJECT_EVENT permission");
4311 case INJECT_SUCCEEDED:
4312 return true;
4313 }
4314 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004315 }
Romain Guy06882f82009-06-10 13:36:04 -07004316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004317 private WindowState getFocusedWindow() {
4318 synchronized (mWindowMap) {
4319 return getFocusedWindowLocked();
4320 }
4321 }
4322
4323 private WindowState getFocusedWindowLocked() {
4324 return mCurrentFocus;
4325 }
Romain Guy06882f82009-06-10 13:36:04 -07004326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004327 /**
4328 * This class holds the state for dispatching key events. This state
4329 * is protected by the KeyWaiter instance, NOT by the window lock. You
4330 * can be holding the main window lock while acquire the KeyWaiter lock,
4331 * but not the other way around.
4332 */
4333 final class KeyWaiter {
4334 // NOSHIP debugging
4335 public class DispatchState {
4336 private KeyEvent event;
4337 private WindowState focus;
4338 private long time;
4339 private WindowState lastWin;
4340 private IBinder lastBinder;
4341 private boolean finished;
4342 private boolean gotFirstWindow;
4343 private boolean eventDispatching;
4344 private long timeToSwitch;
4345 private boolean wasFrozen;
4346 private boolean focusPaused;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004347 private WindowState curFocus;
Romain Guy06882f82009-06-10 13:36:04 -07004348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004349 DispatchState(KeyEvent theEvent, WindowState theFocus) {
4350 focus = theFocus;
4351 event = theEvent;
4352 time = System.currentTimeMillis();
4353 // snapshot KeyWaiter state
4354 lastWin = mLastWin;
4355 lastBinder = mLastBinder;
4356 finished = mFinished;
4357 gotFirstWindow = mGotFirstWindow;
4358 eventDispatching = mEventDispatching;
4359 timeToSwitch = mTimeToSwitch;
4360 wasFrozen = mWasFrozen;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004361 curFocus = mCurrentFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 // cache the paused state at ctor time as well
4363 if (theFocus == null || theFocus.mToken == null) {
4364 Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
4365 focusPaused = false;
4366 } else {
4367 focusPaused = theFocus.mToken.paused;
4368 }
4369 }
Romain Guy06882f82009-06-10 13:36:04 -07004370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004371 public String toString() {
4372 return "{{" + event + " to " + focus + " @ " + time
4373 + " lw=" + lastWin + " lb=" + lastBinder
4374 + " fin=" + finished + " gfw=" + gotFirstWindow
4375 + " ed=" + eventDispatching + " tts=" + timeToSwitch
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004376 + " wf=" + wasFrozen + " fp=" + focusPaused
4377 + " mcf=" + mCurrentFocus + "}}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004378 }
4379 };
4380 private DispatchState mDispatchState = null;
4381 public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
4382 mDispatchState = new DispatchState(theEvent, theFocus);
4383 }
4384 // END NOSHIP
4385
4386 public static final int RETURN_NOTHING = 0;
4387 public static final int RETURN_PENDING_POINTER = 1;
4388 public static final int RETURN_PENDING_TRACKBALL = 2;
Romain Guy06882f82009-06-10 13:36:04 -07004389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004390 final Object SKIP_TARGET_TOKEN = new Object();
4391 final Object CONSUMED_EVENT_TOKEN = new Object();
Romain Guy06882f82009-06-10 13:36:04 -07004392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004393 private WindowState mLastWin = null;
4394 private IBinder mLastBinder = null;
4395 private boolean mFinished = true;
4396 private boolean mGotFirstWindow = false;
4397 private boolean mEventDispatching = true;
4398 private long mTimeToSwitch = 0;
4399 /* package */ boolean mWasFrozen = false;
Romain Guy06882f82009-06-10 13:36:04 -07004400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004401 // Target of Motion events
4402 WindowState mMotionTarget;
Romain Guy06882f82009-06-10 13:36:04 -07004403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004404 // Windows above the target who would like to receive an "outside"
4405 // touch event for any down events outside of them.
4406 WindowState mOutsideTouchTargets;
4407
4408 /**
4409 * Wait for the last event dispatch to complete, then find the next
4410 * target that should receive the given event and wait for that one
4411 * to be ready to receive it.
4412 */
4413 Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
4414 MotionEvent nextMotion, boolean isPointerEvent,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004415 boolean failIfTimeout, int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004416 long startTime = SystemClock.uptimeMillis();
4417 long keyDispatchingTimeout = 5 * 1000;
4418 long waitedFor = 0;
4419
4420 while (true) {
4421 // Figure out which window we care about. It is either the
4422 // last window we are waiting to have process the event or,
4423 // if none, then the next window we think the event should go
4424 // to. Note: we retrieve mLastWin outside of the lock, so
4425 // it may change before we lock. Thus we must check it again.
4426 WindowState targetWin = mLastWin;
4427 boolean targetIsNew = targetWin == null;
4428 if (DEBUG_INPUT) Log.v(
4429 TAG, "waitForLastKey: mFinished=" + mFinished +
4430 ", mLastWin=" + mLastWin);
4431 if (targetIsNew) {
4432 Object target = findTargetWindow(nextKey, qev, nextMotion,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004433 isPointerEvent, callingPid, callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004434 if (target == SKIP_TARGET_TOKEN) {
4435 // The user has pressed a special key, and we are
4436 // dropping all pending events before it.
4437 if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey
4438 + " " + nextMotion);
4439 return null;
4440 }
4441 if (target == CONSUMED_EVENT_TOKEN) {
4442 if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
4443 + " " + nextMotion);
4444 return target;
4445 }
4446 targetWin = (WindowState)target;
4447 }
Romain Guy06882f82009-06-10 13:36:04 -07004448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004449 AppWindowToken targetApp = null;
Romain Guy06882f82009-06-10 13:36:04 -07004450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004451 // Now: is it okay to send the next event to this window?
4452 synchronized (this) {
4453 // First: did we come here based on the last window not
4454 // being null, but it changed by the time we got here?
4455 // If so, try again.
4456 if (!targetIsNew && mLastWin == null) {
4457 continue;
4458 }
Romain Guy06882f82009-06-10 13:36:04 -07004459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004460 // We never dispatch events if not finished with the
4461 // last one, or the display is frozen.
4462 if (mFinished && !mDisplayFrozen) {
4463 // If event dispatching is disabled, then we
4464 // just consume the events.
4465 if (!mEventDispatching) {
4466 if (DEBUG_INPUT) Log.v(TAG,
4467 "Skipping event; dispatching disabled: "
4468 + nextKey + " " + nextMotion);
4469 return null;
4470 }
4471 if (targetWin != null) {
4472 // If this is a new target, and that target is not
4473 // paused or unresponsive, then all looks good to
4474 // handle the event.
4475 if (targetIsNew && !targetWin.mToken.paused) {
4476 return targetWin;
4477 }
Romain Guy06882f82009-06-10 13:36:04 -07004478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004479 // If we didn't find a target window, and there is no
4480 // focused app window, then just eat the events.
4481 } else if (mFocusedApp == null) {
4482 if (DEBUG_INPUT) Log.v(TAG,
4483 "Skipping event; no focused app: "
4484 + nextKey + " " + nextMotion);
4485 return null;
4486 }
4487 }
Romain Guy06882f82009-06-10 13:36:04 -07004488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004489 if (DEBUG_INPUT) Log.v(
4490 TAG, "Waiting for last key in " + mLastBinder
4491 + " target=" + targetWin
4492 + " mFinished=" + mFinished
4493 + " mDisplayFrozen=" + mDisplayFrozen
4494 + " targetIsNew=" + targetIsNew
4495 + " paused="
4496 + (targetWin != null ? targetWin.mToken.paused : false)
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004497 + " mFocusedApp=" + mFocusedApp
4498 + " mCurrentFocus=" + mCurrentFocus);
Romain Guy06882f82009-06-10 13:36:04 -07004499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500 targetApp = targetWin != null
4501 ? targetWin.mAppToken : mFocusedApp;
Romain Guy06882f82009-06-10 13:36:04 -07004502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004503 long curTimeout = keyDispatchingTimeout;
4504 if (mTimeToSwitch != 0) {
4505 long now = SystemClock.uptimeMillis();
4506 if (mTimeToSwitch <= now) {
4507 // If an app switch key has been pressed, and we have
4508 // waited too long for the current app to finish
4509 // processing keys, then wait no more!
4510 doFinishedKeyLocked(true);
4511 continue;
4512 }
4513 long switchTimeout = mTimeToSwitch - now;
4514 if (curTimeout > switchTimeout) {
4515 curTimeout = switchTimeout;
4516 }
4517 }
Romain Guy06882f82009-06-10 13:36:04 -07004518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004519 try {
4520 // after that continue
4521 // processing keys, so we don't get stuck.
4522 if (DEBUG_INPUT) Log.v(
4523 TAG, "Waiting for key dispatch: " + curTimeout);
4524 wait(curTimeout);
4525 if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
4526 + SystemClock.uptimeMillis() + " startTime="
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004527 + startTime + " switchTime=" + mTimeToSwitch
4528 + " target=" + targetWin + " mLW=" + mLastWin
4529 + " mLB=" + mLastBinder + " fin=" + mFinished
4530 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004531 } catch (InterruptedException e) {
4532 }
4533 }
4534
4535 // If we were frozen during configuration change, restart the
4536 // timeout checks from now; otherwise look at whether we timed
4537 // out before awakening.
4538 if (mWasFrozen) {
4539 waitedFor = 0;
4540 mWasFrozen = false;
4541 } else {
4542 waitedFor = SystemClock.uptimeMillis() - startTime;
4543 }
4544
4545 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
4546 IApplicationToken at = null;
4547 synchronized (this) {
4548 Log.w(TAG, "Key dispatching timed out sending to " +
4549 (targetWin != null ? targetWin.mAttrs.getTitle()
4550 : "<null>"));
4551 // NOSHIP debugging
4552 Log.w(TAG, "Dispatch state: " + mDispatchState);
4553 Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
4554 // END NOSHIP
4555 //dump();
4556 if (targetWin != null) {
4557 at = targetWin.getAppToken();
4558 } else if (targetApp != null) {
4559 at = targetApp.appToken;
4560 }
4561 }
4562
4563 boolean abort = true;
4564 if (at != null) {
4565 try {
4566 long timeout = at.getKeyDispatchingTimeout();
4567 if (timeout > waitedFor) {
4568 // we did not wait the proper amount of time for this application.
4569 // set the timeout to be the real timeout and wait again.
4570 keyDispatchingTimeout = timeout - waitedFor;
4571 continue;
4572 } else {
4573 abort = at.keyDispatchingTimedOut();
4574 }
4575 } catch (RemoteException ex) {
4576 }
4577 }
4578
4579 synchronized (this) {
4580 if (abort && (mLastWin == targetWin || targetWin == null)) {
4581 mFinished = true;
Romain Guy06882f82009-06-10 13:36:04 -07004582 if (mLastWin != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004583 if (DEBUG_INPUT) Log.v(TAG,
4584 "Window " + mLastWin +
4585 " timed out on key input");
4586 if (mLastWin.mToken.paused) {
4587 Log.w(TAG, "Un-pausing dispatching to this window");
4588 mLastWin.mToken.paused = false;
4589 }
4590 }
4591 if (mMotionTarget == targetWin) {
4592 mMotionTarget = null;
4593 }
4594 mLastWin = null;
4595 mLastBinder = null;
4596 if (failIfTimeout || targetWin == null) {
4597 return null;
4598 }
4599 } else {
4600 Log.w(TAG, "Continuing to wait for key to be dispatched");
4601 startTime = SystemClock.uptimeMillis();
4602 }
4603 }
4604 }
4605 }
4606 }
Romain Guy06882f82009-06-10 13:36:04 -07004607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004609 MotionEvent nextMotion, boolean isPointerEvent,
4610 int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004611 mOutsideTouchTargets = null;
Romain Guy06882f82009-06-10 13:36:04 -07004612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004613 if (nextKey != null) {
4614 // Find the target window for a normal key event.
4615 final int keycode = nextKey.getKeyCode();
4616 final int repeatCount = nextKey.getRepeatCount();
4617 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
4618 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004619
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004620 if (!dispatch) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004621 if (callingUid == 0 ||
4622 mContext.checkPermission(
4623 android.Manifest.permission.INJECT_EVENTS,
4624 callingPid, callingUid)
4625 == PackageManager.PERMISSION_GRANTED) {
4626 mPolicy.interceptKeyTi(null, keycode,
4627 nextKey.getMetaState(), down, repeatCount);
4628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 Log.w(TAG, "Event timeout during app switch: dropping "
4630 + nextKey);
4631 return SKIP_TARGET_TOKEN;
4632 }
Romain Guy06882f82009-06-10 13:36:04 -07004633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
Romain Guy06882f82009-06-10 13:36:04 -07004635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004636 WindowState focus = null;
4637 synchronized(mWindowMap) {
4638 focus = getFocusedWindowLocked();
4639 }
Romain Guy06882f82009-06-10 13:36:04 -07004640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004641 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
Romain Guy06882f82009-06-10 13:36:04 -07004642
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004643 if (callingUid == 0 ||
4644 (focus != null && callingUid == focus.mSession.mUid) ||
4645 mContext.checkPermission(
4646 android.Manifest.permission.INJECT_EVENTS,
4647 callingPid, callingUid)
4648 == PackageManager.PERMISSION_GRANTED) {
4649 if (mPolicy.interceptKeyTi(focus,
4650 keycode, nextKey.getMetaState(), down, repeatCount)) {
4651 return CONSUMED_EVENT_TOKEN;
4652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004653 }
Romain Guy06882f82009-06-10 13:36:04 -07004654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004655 return focus;
Romain Guy06882f82009-06-10 13:36:04 -07004656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004657 } else if (!isPointerEvent) {
4658 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
4659 if (!dispatch) {
4660 Log.w(TAG, "Event timeout during app switch: dropping trackball "
4661 + nextMotion);
4662 return SKIP_TARGET_TOKEN;
4663 }
Romain Guy06882f82009-06-10 13:36:04 -07004664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004665 WindowState focus = null;
4666 synchronized(mWindowMap) {
4667 focus = getFocusedWindowLocked();
4668 }
Romain Guy06882f82009-06-10 13:36:04 -07004669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004670 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
4671 return focus;
4672 }
Romain Guy06882f82009-06-10 13:36:04 -07004673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 if (nextMotion == null) {
4675 return SKIP_TARGET_TOKEN;
4676 }
Romain Guy06882f82009-06-10 13:36:04 -07004677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004678 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
4679 KeyEvent.KEYCODE_UNKNOWN);
4680 if (!dispatch) {
4681 Log.w(TAG, "Event timeout during app switch: dropping pointer "
4682 + nextMotion);
4683 return SKIP_TARGET_TOKEN;
4684 }
Romain Guy06882f82009-06-10 13:36:04 -07004685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004686 // Find the target window for a pointer event.
4687 int action = nextMotion.getAction();
4688 final float xf = nextMotion.getX();
4689 final float yf = nextMotion.getY();
4690 final long eventTime = nextMotion.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004692 final boolean screenWasOff = qev != null
4693 && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07004694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 WindowState target = null;
Romain Guy06882f82009-06-10 13:36:04 -07004696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004697 synchronized(mWindowMap) {
4698 synchronized (this) {
4699 if (action == MotionEvent.ACTION_DOWN) {
4700 if (mMotionTarget != null) {
4701 // this is weird, we got a pen down, but we thought it was
4702 // already down!
4703 // XXX: We should probably send an ACTION_UP to the current
4704 // target.
4705 Log.w(TAG, "Pointer down received while already down in: "
4706 + mMotionTarget);
4707 mMotionTarget = null;
4708 }
Romain Guy06882f82009-06-10 13:36:04 -07004709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004710 // ACTION_DOWN is special, because we need to lock next events to
4711 // the window we'll land onto.
4712 final int x = (int)xf;
4713 final int y = (int)yf;
Romain Guy06882f82009-06-10 13:36:04 -07004714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004715 final ArrayList windows = mWindows;
4716 final int N = windows.size();
4717 WindowState topErrWindow = null;
4718 final Rect tmpRect = mTempRect;
4719 for (int i=N-1; i>=0; i--) {
4720 WindowState child = (WindowState)windows.get(i);
4721 //Log.i(TAG, "Checking dispatch to: " + child);
4722 final int flags = child.mAttrs.flags;
4723 if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
4724 if (topErrWindow == null) {
4725 topErrWindow = child;
4726 }
4727 }
4728 if (!child.isVisibleLw()) {
4729 //Log.i(TAG, "Not visible!");
4730 continue;
4731 }
4732 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
4733 //Log.i(TAG, "Not touchable!");
4734 if ((flags & WindowManager.LayoutParams
4735 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4736 child.mNextOutsideTouch = mOutsideTouchTargets;
4737 mOutsideTouchTargets = child;
4738 }
4739 continue;
4740 }
4741 tmpRect.set(child.mFrame);
4742 if (child.mTouchableInsets == ViewTreeObserver
4743 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
4744 // The touch is inside of the window if it is
4745 // inside the frame, AND the content part of that
4746 // frame that was given by the application.
4747 tmpRect.left += child.mGivenContentInsets.left;
4748 tmpRect.top += child.mGivenContentInsets.top;
4749 tmpRect.right -= child.mGivenContentInsets.right;
4750 tmpRect.bottom -= child.mGivenContentInsets.bottom;
4751 } else if (child.mTouchableInsets == ViewTreeObserver
4752 .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
4753 // The touch is inside of the window if it is
4754 // inside the frame, AND the visible part of that
4755 // frame that was given by the application.
4756 tmpRect.left += child.mGivenVisibleInsets.left;
4757 tmpRect.top += child.mGivenVisibleInsets.top;
4758 tmpRect.right -= child.mGivenVisibleInsets.right;
4759 tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
4760 }
4761 final int touchFlags = flags &
4762 (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
4763 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
4764 if (tmpRect.contains(x, y) || touchFlags == 0) {
4765 //Log.i(TAG, "Using this target!");
4766 if (!screenWasOff || (flags &
4767 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
4768 mMotionTarget = child;
4769 } else {
4770 //Log.i(TAG, "Waking, skip!");
4771 mMotionTarget = null;
4772 }
4773 break;
4774 }
Romain Guy06882f82009-06-10 13:36:04 -07004775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004776 if ((flags & WindowManager.LayoutParams
4777 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4778 child.mNextOutsideTouch = mOutsideTouchTargets;
4779 mOutsideTouchTargets = child;
4780 //Log.i(TAG, "Adding to outside target list: " + child);
4781 }
4782 }
4783
4784 // if there's an error window but it's not accepting
4785 // focus (typically because it is not yet visible) just
4786 // wait for it -- any other focused window may in fact
4787 // be in ANR state.
4788 if (topErrWindow != null && mMotionTarget != topErrWindow) {
4789 mMotionTarget = null;
4790 }
4791 }
Romain Guy06882f82009-06-10 13:36:04 -07004792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 target = mMotionTarget;
4794 }
4795 }
Romain Guy06882f82009-06-10 13:36:04 -07004796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004797 wakeupIfNeeded(target, eventType(nextMotion));
Romain Guy06882f82009-06-10 13:36:04 -07004798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004799 // Pointer events are a little different -- if there isn't a
4800 // target found for any event, then just drop it.
4801 return target != null ? target : SKIP_TARGET_TOKEN;
4802 }
Romain Guy06882f82009-06-10 13:36:04 -07004803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004804 boolean checkShouldDispatchKey(int keycode) {
4805 synchronized (this) {
4806 if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
4807 mTimeToSwitch = 0;
4808 return true;
4809 }
4810 if (mTimeToSwitch != 0
4811 && mTimeToSwitch < SystemClock.uptimeMillis()) {
4812 return false;
4813 }
4814 return true;
4815 }
4816 }
Romain Guy06882f82009-06-10 13:36:04 -07004817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004818 void bindTargetWindowLocked(WindowState win,
4819 int pendingWhat, QueuedEvent pendingMotion) {
4820 synchronized (this) {
4821 bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
4822 }
4823 }
Romain Guy06882f82009-06-10 13:36:04 -07004824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004825 void bindTargetWindowLocked(WindowState win) {
4826 synchronized (this) {
4827 bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
4828 }
4829 }
4830
4831 void bindTargetWindowLockedLocked(WindowState win,
4832 int pendingWhat, QueuedEvent pendingMotion) {
4833 mLastWin = win;
4834 mLastBinder = win.mClient.asBinder();
4835 mFinished = false;
4836 if (pendingMotion != null) {
4837 final Session s = win.mSession;
4838 if (pendingWhat == RETURN_PENDING_POINTER) {
4839 releasePendingPointerLocked(s);
4840 s.mPendingPointerMove = pendingMotion;
4841 s.mPendingPointerWindow = win;
Romain Guy06882f82009-06-10 13:36:04 -07004842 if (DEBUG_INPUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004843 "bindTargetToWindow " + s.mPendingPointerMove);
4844 } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
4845 releasePendingTrackballLocked(s);
4846 s.mPendingTrackballMove = pendingMotion;
4847 s.mPendingTrackballWindow = win;
4848 }
4849 }
4850 }
Romain Guy06882f82009-06-10 13:36:04 -07004851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004852 void releasePendingPointerLocked(Session s) {
4853 if (DEBUG_INPUT) Log.v(TAG,
4854 "releasePendingPointer " + s.mPendingPointerMove);
4855 if (s.mPendingPointerMove != null) {
4856 mQueue.recycleEvent(s.mPendingPointerMove);
4857 s.mPendingPointerMove = null;
4858 }
4859 }
Romain Guy06882f82009-06-10 13:36:04 -07004860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004861 void releasePendingTrackballLocked(Session s) {
4862 if (s.mPendingTrackballMove != null) {
4863 mQueue.recycleEvent(s.mPendingTrackballMove);
4864 s.mPendingTrackballMove = null;
4865 }
4866 }
Romain Guy06882f82009-06-10 13:36:04 -07004867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004868 MotionEvent finishedKey(Session session, IWindow client, boolean force,
4869 int returnWhat) {
4870 if (DEBUG_INPUT) Log.v(
4871 TAG, "finishedKey: client=" + client + ", force=" + force);
4872
4873 if (client == null) {
4874 return null;
4875 }
4876
4877 synchronized (this) {
4878 if (DEBUG_INPUT) Log.v(
4879 TAG, "finishedKey: client=" + client.asBinder()
4880 + ", force=" + force + ", last=" + mLastBinder
4881 + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
4882
4883 QueuedEvent qev = null;
4884 WindowState win = null;
4885 if (returnWhat == RETURN_PENDING_POINTER) {
4886 qev = session.mPendingPointerMove;
4887 win = session.mPendingPointerWindow;
4888 session.mPendingPointerMove = null;
4889 session.mPendingPointerWindow = null;
4890 } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
4891 qev = session.mPendingTrackballMove;
4892 win = session.mPendingTrackballWindow;
4893 session.mPendingTrackballMove = null;
4894 session.mPendingTrackballWindow = null;
4895 }
Romain Guy06882f82009-06-10 13:36:04 -07004896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004897 if (mLastBinder == client.asBinder()) {
4898 if (DEBUG_INPUT) Log.v(
4899 TAG, "finishedKey: last paused="
4900 + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
4901 if (mLastWin != null && (!mLastWin.mToken.paused || force
4902 || !mEventDispatching)) {
4903 doFinishedKeyLocked(false);
4904 } else {
4905 // Make sure to wake up anyone currently waiting to
4906 // dispatch a key, so they can re-evaluate their
4907 // current situation.
4908 mFinished = true;
4909 notifyAll();
4910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004911 }
Romain Guy06882f82009-06-10 13:36:04 -07004912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004913 if (qev != null) {
4914 MotionEvent res = (MotionEvent)qev.event;
4915 if (DEBUG_INPUT) Log.v(TAG,
4916 "Returning pending motion: " + res);
4917 mQueue.recycleEvent(qev);
4918 if (win != null && returnWhat == RETURN_PENDING_POINTER) {
4919 res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
4920 }
4921 return res;
4922 }
4923 return null;
4924 }
4925 }
4926
4927 void tickle() {
4928 synchronized (this) {
4929 notifyAll();
4930 }
4931 }
Romain Guy06882f82009-06-10 13:36:04 -07004932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004933 void handleNewWindowLocked(WindowState newWindow) {
4934 if (!newWindow.canReceiveKeys()) {
4935 return;
4936 }
4937 synchronized (this) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004938 if (DEBUG_INPUT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004939 TAG, "New key dispatch window: win="
4940 + newWindow.mClient.asBinder()
4941 + ", last=" + mLastBinder
4942 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
4943 + "), finished=" + mFinished + ", paused="
4944 + newWindow.mToken.paused);
4945
4946 // Displaying a window implicitly causes dispatching to
4947 // be unpaused. (This is to protect against bugs if someone
4948 // pauses dispatching but forgets to resume.)
4949 newWindow.mToken.paused = false;
4950
4951 mGotFirstWindow = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004952
4953 if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
4954 if (DEBUG_INPUT) Log.v(TAG,
4955 "New SYSTEM_ERROR window; resetting state");
4956 mLastWin = null;
4957 mLastBinder = null;
4958 mMotionTarget = null;
4959 mFinished = true;
4960 } else if (mLastWin != null) {
4961 // If the new window is above the window we are
4962 // waiting on, then stop waiting and let key dispatching
4963 // start on the new guy.
4964 if (DEBUG_INPUT) Log.v(
4965 TAG, "Last win layer=" + mLastWin.mLayer
4966 + ", new win layer=" + newWindow.mLayer);
4967 if (newWindow.mLayer >= mLastWin.mLayer) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004968 // The new window is above the old; finish pending input to the last
4969 // window and start directing it to the new one.
4970 mLastWin.mToken.paused = false;
4971 doFinishedKeyLocked(true); // does a notifyAll()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004972 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004973 // Either the new window is lower, so there is no need to wake key waiters,
4974 // or we just finished key input to the previous window, which implicitly
4975 // notified the key waiters. In both cases, we don't need to issue the
4976 // notification here.
4977 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004978 }
4979
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004980 // Now that we've put a new window state in place, make the event waiter
4981 // take notice and retarget its attentions.
4982 notifyAll();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004983 }
4984 }
4985
4986 void pauseDispatchingLocked(WindowToken token) {
4987 synchronized (this)
4988 {
4989 if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
4990 token.paused = true;
4991
4992 /*
4993 if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
4994 mPaused = true;
4995 } else {
4996 if (mLastWin == null) {
Dave Bortcfe65242009-04-09 14:51:04 -07004997 Log.i(TAG, "Key dispatching not paused: no last window.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004998 } else if (mFinished) {
Dave Bortcfe65242009-04-09 14:51:04 -07004999 Log.i(TAG, "Key dispatching not paused: finished last key.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005000 } else {
Dave Bortcfe65242009-04-09 14:51:04 -07005001 Log.i(TAG, "Key dispatching not paused: window in higher layer.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002 }
5003 }
5004 */
5005 }
5006 }
5007
5008 void resumeDispatchingLocked(WindowToken token) {
5009 synchronized (this) {
5010 if (token.paused) {
5011 if (DEBUG_INPUT) Log.v(
5012 TAG, "Resuming WindowToken " + token
5013 + ", last=" + mLastBinder
5014 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
5015 + "), finished=" + mFinished + ", paused="
5016 + token.paused);
5017 token.paused = false;
5018 if (mLastWin != null && mLastWin.mToken == token && mFinished) {
5019 doFinishedKeyLocked(true);
5020 } else {
5021 notifyAll();
5022 }
5023 }
5024 }
5025 }
5026
5027 void setEventDispatchingLocked(boolean enabled) {
5028 synchronized (this) {
5029 mEventDispatching = enabled;
5030 notifyAll();
5031 }
5032 }
Romain Guy06882f82009-06-10 13:36:04 -07005033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005034 void appSwitchComing() {
5035 synchronized (this) {
5036 // Don't wait for more than .5 seconds for app to finish
5037 // processing the pending events.
5038 long now = SystemClock.uptimeMillis() + 500;
5039 if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now);
5040 if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
5041 mTimeToSwitch = now;
5042 }
5043 notifyAll();
5044 }
5045 }
Romain Guy06882f82009-06-10 13:36:04 -07005046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005047 private final void doFinishedKeyLocked(boolean doRecycle) {
5048 if (mLastWin != null) {
5049 releasePendingPointerLocked(mLastWin.mSession);
5050 releasePendingTrackballLocked(mLastWin.mSession);
5051 }
Romain Guy06882f82009-06-10 13:36:04 -07005052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005053 if (mLastWin == null || !mLastWin.mToken.paused
5054 || !mLastWin.isVisibleLw()) {
5055 // If the current window has been paused, we aren't -really-
5056 // finished... so let the waiters still wait.
5057 mLastWin = null;
5058 mLastBinder = null;
5059 }
5060 mFinished = true;
5061 notifyAll();
5062 }
5063 }
5064
5065 private class KeyQ extends KeyInputQueue
5066 implements KeyInputQueue.FilterCallback {
5067 PowerManager.WakeLock mHoldingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07005068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005069 KeyQ() {
5070 super(mContext);
5071 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
5072 mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
5073 "KEEP_SCREEN_ON_FLAG");
5074 mHoldingScreen.setReferenceCounted(false);
5075 }
5076
5077 @Override
5078 boolean preprocessEvent(InputDevice device, RawInputEvent event) {
5079 if (mPolicy.preprocessInputEventTq(event)) {
5080 return true;
5081 }
Romain Guy06882f82009-06-10 13:36:04 -07005082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005083 switch (event.type) {
5084 case RawInputEvent.EV_KEY: {
5085 // XXX begin hack
5086 if (DEBUG) {
5087 if (event.keycode == KeyEvent.KEYCODE_G) {
5088 if (event.value != 0) {
5089 // G down
5090 mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
5091 }
5092 return false;
5093 }
5094 if (event.keycode == KeyEvent.KEYCODE_D) {
5095 if (event.value != 0) {
5096 //dump();
5097 }
5098 return false;
5099 }
5100 }
5101 // XXX end hack
Romain Guy06882f82009-06-10 13:36:04 -07005102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005103 boolean screenIsOff = !mPowerManager.screenIsOn();
5104 boolean screenIsDim = !mPowerManager.screenIsBright();
5105 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
Romain Guy06882f82009-06-10 13:36:04 -07005106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005107 if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
5108 mPowerManager.goToSleep(event.when);
5109 }
5110
5111 if (screenIsOff) {
5112 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5113 }
5114 if (screenIsDim) {
5115 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5116 }
5117 if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
5118 mPowerManager.userActivity(event.when, false,
Michael Chane96440f2009-05-06 10:27:36 -07005119 LocalPowerManager.BUTTON_EVENT, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005120 }
Romain Guy06882f82009-06-10 13:36:04 -07005121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005122 if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
5123 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
5124 filterQueue(this);
5125 mKeyWaiter.appSwitchComing();
5126 }
5127 return true;
5128 } else {
5129 return false;
5130 }
5131 }
Romain Guy06882f82009-06-10 13:36:04 -07005132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005133 case RawInputEvent.EV_REL: {
5134 boolean screenIsOff = !mPowerManager.screenIsOn();
5135 boolean screenIsDim = !mPowerManager.screenIsBright();
5136 if (screenIsOff) {
5137 if (!mPolicy.isWakeRelMovementTq(event.deviceId,
5138 device.classes, event)) {
5139 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5140 return false;
5141 }
5142 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5143 }
5144 if (screenIsDim) {
5145 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5146 }
5147 return true;
5148 }
Romain Guy06882f82009-06-10 13:36:04 -07005149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005150 case RawInputEvent.EV_ABS: {
5151 boolean screenIsOff = !mPowerManager.screenIsOn();
5152 boolean screenIsDim = !mPowerManager.screenIsBright();
5153 if (screenIsOff) {
5154 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
5155 device.classes, event)) {
5156 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5157 return false;
5158 }
5159 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5160 }
5161 if (screenIsDim) {
5162 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5163 }
5164 return true;
5165 }
Romain Guy06882f82009-06-10 13:36:04 -07005166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005167 default:
5168 return true;
5169 }
5170 }
5171
5172 public int filterEvent(QueuedEvent ev) {
5173 switch (ev.classType) {
5174 case RawInputEvent.CLASS_KEYBOARD:
5175 KeyEvent ke = (KeyEvent)ev.event;
5176 if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
5177 Log.w(TAG, "Dropping movement key during app switch: "
5178 + ke.getKeyCode() + ", action=" + ke.getAction());
5179 return FILTER_REMOVE;
5180 }
5181 return FILTER_ABORT;
5182 default:
5183 return FILTER_KEEP;
5184 }
5185 }
Romain Guy06882f82009-06-10 13:36:04 -07005186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005187 /**
5188 * Must be called with the main window manager lock held.
5189 */
5190 void setHoldScreenLocked(boolean holding) {
5191 boolean state = mHoldingScreen.isHeld();
5192 if (holding != state) {
5193 if (holding) {
5194 mHoldingScreen.acquire();
5195 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005196 mPolicy.screenOnStoppedLw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005197 mHoldingScreen.release();
5198 }
5199 }
5200 }
5201 };
5202
5203 public boolean detectSafeMode() {
5204 mSafeMode = mPolicy.detectSafeMode();
5205 return mSafeMode;
5206 }
Romain Guy06882f82009-06-10 13:36:04 -07005207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 public void systemReady() {
5209 mPolicy.systemReady();
5210 }
Romain Guy06882f82009-06-10 13:36:04 -07005211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005212 private final class InputDispatcherThread extends Thread {
5213 // Time to wait when there is nothing to do: 9999 seconds.
5214 static final int LONG_WAIT=9999*1000;
5215
5216 public InputDispatcherThread() {
5217 super("InputDispatcher");
5218 }
Romain Guy06882f82009-06-10 13:36:04 -07005219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005220 @Override
5221 public void run() {
5222 while (true) {
5223 try {
5224 process();
5225 } catch (Exception e) {
5226 Log.e(TAG, "Exception in input dispatcher", e);
5227 }
5228 }
5229 }
Romain Guy06882f82009-06-10 13:36:04 -07005230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005231 private void process() {
5232 android.os.Process.setThreadPriority(
5233 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -07005234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005235 // The last key event we saw
5236 KeyEvent lastKey = null;
5237
5238 // Last keydown time for auto-repeating keys
5239 long lastKeyTime = SystemClock.uptimeMillis();
5240 long nextKeyTime = lastKeyTime+LONG_WAIT;
5241
Romain Guy06882f82009-06-10 13:36:04 -07005242 // How many successive repeats we generated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005243 int keyRepeatCount = 0;
5244
5245 // Need to report that configuration has changed?
5246 boolean configChanged = false;
Romain Guy06882f82009-06-10 13:36:04 -07005247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248 while (true) {
5249 long curTime = SystemClock.uptimeMillis();
5250
5251 if (DEBUG_INPUT) Log.v(
5252 TAG, "Waiting for next key: now=" + curTime
5253 + ", repeat @ " + nextKeyTime);
5254
5255 // Retrieve next event, waiting only as long as the next
5256 // repeat timeout. If the configuration has changed, then
5257 // don't wait at all -- we'll report the change as soon as
5258 // we have processed all events.
5259 QueuedEvent ev = mQueue.getEvent(
5260 (int)((!configChanged && curTime < nextKeyTime)
5261 ? (nextKeyTime-curTime) : 0));
5262
5263 if (DEBUG_INPUT && ev != null) Log.v(
5264 TAG, "Event: type=" + ev.classType + " data=" + ev.event);
5265
5266 try {
5267 if (ev != null) {
5268 curTime = ev.when;
5269 int eventType;
5270 if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
5271 eventType = eventType((MotionEvent)ev.event);
5272 } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
5273 ev.classType == RawInputEvent.CLASS_TRACKBALL) {
5274 eventType = LocalPowerManager.BUTTON_EVENT;
5275 } else {
5276 eventType = LocalPowerManager.OTHER_EVENT;
5277 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005278 try {
Michael Chane96440f2009-05-06 10:27:36 -07005279 long now = SystemClock.uptimeMillis();
5280
5281 if ((now - mLastBatteryStatsCallTime)
5282 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
5283 mLastBatteryStatsCallTime = now;
5284 mBatteryStats.noteInputEvent();
5285 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005286 } catch (RemoteException e) {
5287 // Ignore
5288 }
Michael Chane96440f2009-05-06 10:27:36 -07005289 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005290 switch (ev.classType) {
5291 case RawInputEvent.CLASS_KEYBOARD:
5292 KeyEvent ke = (KeyEvent)ev.event;
5293 if (ke.isDown()) {
5294 lastKey = ke;
5295 keyRepeatCount = 0;
5296 lastKeyTime = curTime;
5297 nextKeyTime = lastKeyTime
5298 + KEY_REPEAT_FIRST_DELAY;
5299 if (DEBUG_INPUT) Log.v(
5300 TAG, "Received key down: first repeat @ "
5301 + nextKeyTime);
5302 } else {
5303 lastKey = null;
5304 // Arbitrary long timeout.
5305 lastKeyTime = curTime;
5306 nextKeyTime = curTime + LONG_WAIT;
5307 if (DEBUG_INPUT) Log.v(
5308 TAG, "Received key up: ignore repeat @ "
5309 + nextKeyTime);
5310 }
5311 dispatchKey((KeyEvent)ev.event, 0, 0);
5312 mQueue.recycleEvent(ev);
5313 break;
5314 case RawInputEvent.CLASS_TOUCHSCREEN:
5315 //Log.i(TAG, "Read next event " + ev);
5316 dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
5317 break;
5318 case RawInputEvent.CLASS_TRACKBALL:
5319 dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
5320 break;
5321 case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
5322 configChanged = true;
5323 break;
5324 default:
5325 mQueue.recycleEvent(ev);
5326 break;
5327 }
Romain Guy06882f82009-06-10 13:36:04 -07005328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005329 } else if (configChanged) {
5330 configChanged = false;
5331 sendNewConfiguration();
Romain Guy06882f82009-06-10 13:36:04 -07005332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005333 } else if (lastKey != null) {
5334 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005336 // Timeout occurred while key was down. If it is at or
5337 // past the key repeat time, dispatch the repeat.
5338 if (DEBUG_INPUT) Log.v(
5339 TAG, "Key timeout: repeat=" + nextKeyTime
5340 + ", now=" + curTime);
5341 if (curTime < nextKeyTime) {
5342 continue;
5343 }
Romain Guy06882f82009-06-10 13:36:04 -07005344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005345 lastKeyTime = nextKeyTime;
5346 nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
5347 keyRepeatCount++;
5348 if (DEBUG_INPUT) Log.v(
5349 TAG, "Key repeat: count=" + keyRepeatCount
5350 + ", next @ " + nextKeyTime);
The Android Open Source Project10592532009-03-18 17:39:46 -07005351 dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
Romain Guy06882f82009-06-10 13:36:04 -07005352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005353 } else {
5354 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005356 lastKeyTime = curTime;
5357 nextKeyTime = curTime + LONG_WAIT;
5358 }
Romain Guy06882f82009-06-10 13:36:04 -07005359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360 } catch (Exception e) {
5361 Log.e(TAG,
5362 "Input thread received uncaught exception: " + e, e);
5363 }
5364 }
5365 }
5366 }
5367
5368 // -------------------------------------------------------------
5369 // Client Session State
5370 // -------------------------------------------------------------
5371
5372 private final class Session extends IWindowSession.Stub
5373 implements IBinder.DeathRecipient {
5374 final IInputMethodClient mClient;
5375 final IInputContext mInputContext;
5376 final int mUid;
5377 final int mPid;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005378 final String mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005379 SurfaceSession mSurfaceSession;
5380 int mNumWindow = 0;
5381 boolean mClientDead = false;
Romain Guy06882f82009-06-10 13:36:04 -07005382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005383 /**
5384 * Current pointer move event being dispatched to client window... must
5385 * hold key lock to access.
5386 */
5387 QueuedEvent mPendingPointerMove;
5388 WindowState mPendingPointerWindow;
Romain Guy06882f82009-06-10 13:36:04 -07005389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005390 /**
5391 * Current trackball move event being dispatched to client window... must
5392 * hold key lock to access.
5393 */
5394 QueuedEvent mPendingTrackballMove;
5395 WindowState mPendingTrackballWindow;
5396
5397 public Session(IInputMethodClient client, IInputContext inputContext) {
5398 mClient = client;
5399 mInputContext = inputContext;
5400 mUid = Binder.getCallingUid();
5401 mPid = Binder.getCallingPid();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005402 StringBuilder sb = new StringBuilder();
5403 sb.append("Session{");
5404 sb.append(Integer.toHexString(System.identityHashCode(this)));
5405 sb.append(" uid ");
5406 sb.append(mUid);
5407 sb.append("}");
5408 mStringName = sb.toString();
Romain Guy06882f82009-06-10 13:36:04 -07005409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005410 synchronized (mWindowMap) {
5411 if (mInputMethodManager == null && mHaveInputMethods) {
5412 IBinder b = ServiceManager.getService(
5413 Context.INPUT_METHOD_SERVICE);
5414 mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
5415 }
5416 }
5417 long ident = Binder.clearCallingIdentity();
5418 try {
5419 // Note: it is safe to call in to the input method manager
5420 // here because we are not holding our lock.
5421 if (mInputMethodManager != null) {
5422 mInputMethodManager.addClient(client, inputContext,
5423 mUid, mPid);
5424 } else {
5425 client.setUsingInputMethod(false);
5426 }
5427 client.asBinder().linkToDeath(this, 0);
5428 } catch (RemoteException e) {
5429 // The caller has died, so we can just forget about this.
5430 try {
5431 if (mInputMethodManager != null) {
5432 mInputMethodManager.removeClient(client);
5433 }
5434 } catch (RemoteException ee) {
5435 }
5436 } finally {
5437 Binder.restoreCallingIdentity(ident);
5438 }
5439 }
Romain Guy06882f82009-06-10 13:36:04 -07005440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005441 @Override
5442 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5443 throws RemoteException {
5444 try {
5445 return super.onTransact(code, data, reply, flags);
5446 } catch (RuntimeException e) {
5447 // Log all 'real' exceptions thrown to the caller
5448 if (!(e instanceof SecurityException)) {
5449 Log.e(TAG, "Window Session Crash", e);
5450 }
5451 throw e;
5452 }
5453 }
5454
5455 public void binderDied() {
5456 // Note: it is safe to call in to the input method manager
5457 // here because we are not holding our lock.
5458 try {
5459 if (mInputMethodManager != null) {
5460 mInputMethodManager.removeClient(mClient);
5461 }
5462 } catch (RemoteException e) {
5463 }
5464 synchronized(mWindowMap) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07005465 mClient.asBinder().unlinkToDeath(this, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 mClientDead = true;
5467 killSessionLocked();
5468 }
5469 }
5470
5471 public int add(IWindow window, WindowManager.LayoutParams attrs,
5472 int viewVisibility, Rect outContentInsets) {
5473 return addWindow(this, window, attrs, viewVisibility, outContentInsets);
5474 }
Romain Guy06882f82009-06-10 13:36:04 -07005475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005476 public void remove(IWindow window) {
5477 removeWindow(this, window);
5478 }
Romain Guy06882f82009-06-10 13:36:04 -07005479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 public int relayout(IWindow window, WindowManager.LayoutParams attrs,
5481 int requestedWidth, int requestedHeight, int viewFlags,
5482 boolean insetsPending, Rect outFrame, Rect outContentInsets,
5483 Rect outVisibleInsets, Surface outSurface) {
5484 return relayoutWindow(this, window, attrs,
5485 requestedWidth, requestedHeight, viewFlags, insetsPending,
5486 outFrame, outContentInsets, outVisibleInsets, outSurface);
5487 }
Romain Guy06882f82009-06-10 13:36:04 -07005488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005489 public void setTransparentRegion(IWindow window, Region region) {
5490 setTransparentRegionWindow(this, window, region);
5491 }
Romain Guy06882f82009-06-10 13:36:04 -07005492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005493 public void setInsets(IWindow window, int touchableInsets,
5494 Rect contentInsets, Rect visibleInsets) {
5495 setInsetsWindow(this, window, touchableInsets, contentInsets,
5496 visibleInsets);
5497 }
Romain Guy06882f82009-06-10 13:36:04 -07005498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005499 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
5500 getWindowDisplayFrame(this, window, outDisplayFrame);
5501 }
Romain Guy06882f82009-06-10 13:36:04 -07005502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005503 public void finishDrawing(IWindow window) {
5504 if (localLOGV) Log.v(
5505 TAG, "IWindow finishDrawing called for " + window);
5506 finishDrawingWindow(this, window);
5507 }
5508
5509 public void finishKey(IWindow window) {
5510 if (localLOGV) Log.v(
5511 TAG, "IWindow finishKey called for " + window);
5512 mKeyWaiter.finishedKey(this, window, false,
5513 KeyWaiter.RETURN_NOTHING);
5514 }
5515
5516 public MotionEvent getPendingPointerMove(IWindow window) {
5517 if (localLOGV) Log.v(
5518 TAG, "IWindow getPendingMotionEvent called for " + window);
5519 return mKeyWaiter.finishedKey(this, window, false,
5520 KeyWaiter.RETURN_PENDING_POINTER);
5521 }
Romain Guy06882f82009-06-10 13:36:04 -07005522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005523 public MotionEvent getPendingTrackballMove(IWindow window) {
5524 if (localLOGV) Log.v(
5525 TAG, "IWindow getPendingMotionEvent called for " + window);
5526 return mKeyWaiter.finishedKey(this, window, false,
5527 KeyWaiter.RETURN_PENDING_TRACKBALL);
5528 }
5529
5530 public void setInTouchMode(boolean mode) {
5531 synchronized(mWindowMap) {
5532 mInTouchMode = mode;
5533 }
5534 }
5535
5536 public boolean getInTouchMode() {
5537 synchronized(mWindowMap) {
5538 return mInTouchMode;
5539 }
5540 }
5541
5542 public boolean performHapticFeedback(IWindow window, int effectId,
5543 boolean always) {
5544 synchronized(mWindowMap) {
5545 long ident = Binder.clearCallingIdentity();
5546 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005547 return mPolicy.performHapticFeedbackLw(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005548 windowForClientLocked(this, window), effectId, always);
5549 } finally {
5550 Binder.restoreCallingIdentity(ident);
5551 }
5552 }
5553 }
Romain Guy06882f82009-06-10 13:36:04 -07005554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005555 void windowAddedLocked() {
5556 if (mSurfaceSession == null) {
5557 if (localLOGV) Log.v(
5558 TAG, "First window added to " + this + ", creating SurfaceSession");
5559 mSurfaceSession = new SurfaceSession();
5560 mSessions.add(this);
5561 }
5562 mNumWindow++;
5563 }
5564
5565 void windowRemovedLocked() {
5566 mNumWindow--;
5567 killSessionLocked();
5568 }
Romain Guy06882f82009-06-10 13:36:04 -07005569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005570 void killSessionLocked() {
5571 if (mNumWindow <= 0 && mClientDead) {
5572 mSessions.remove(this);
5573 if (mSurfaceSession != null) {
5574 if (localLOGV) Log.v(
5575 TAG, "Last window removed from " + this
5576 + ", destroying " + mSurfaceSession);
5577 try {
5578 mSurfaceSession.kill();
5579 } catch (Exception e) {
5580 Log.w(TAG, "Exception thrown when killing surface session "
5581 + mSurfaceSession + " in session " + this
5582 + ": " + e.toString());
5583 }
5584 mSurfaceSession = null;
5585 }
5586 }
5587 }
Romain Guy06882f82009-06-10 13:36:04 -07005588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005589 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005590 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
5591 pw.print(" mClientDead="); pw.print(mClientDead);
5592 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
5593 if (mPendingPointerWindow != null || mPendingPointerMove != null) {
5594 pw.print(prefix);
5595 pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
5596 pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
5597 }
5598 if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
5599 pw.print(prefix);
5600 pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
5601 pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
5602 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005603 }
5604
5605 @Override
5606 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005607 return mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005608 }
5609 }
5610
5611 // -------------------------------------------------------------
5612 // Client Window State
5613 // -------------------------------------------------------------
5614
5615 private final class WindowState implements WindowManagerPolicy.WindowState {
5616 final Session mSession;
5617 final IWindow mClient;
5618 WindowToken mToken;
The Android Open Source Project10592532009-03-18 17:39:46 -07005619 WindowToken mRootToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005620 AppWindowToken mAppToken;
5621 AppWindowToken mTargetAppToken;
5622 final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
5623 final DeathRecipient mDeathRecipient;
5624 final WindowState mAttachedWindow;
5625 final ArrayList mChildWindows = new ArrayList();
5626 final int mBaseLayer;
5627 final int mSubLayer;
5628 final boolean mLayoutAttached;
5629 final boolean mIsImWindow;
5630 int mViewVisibility;
5631 boolean mPolicyVisibility = true;
5632 boolean mPolicyVisibilityAfterAnim = true;
5633 boolean mAppFreezing;
5634 Surface mSurface;
5635 boolean mAttachedHidden; // is our parent window hidden?
5636 boolean mLastHidden; // was this window last hidden?
5637 int mRequestedWidth;
5638 int mRequestedHeight;
5639 int mLastRequestedWidth;
5640 int mLastRequestedHeight;
5641 int mReqXPos;
5642 int mReqYPos;
5643 int mLayer;
5644 int mAnimLayer;
5645 int mLastLayer;
5646 boolean mHaveFrame;
5647
5648 WindowState mNextOutsideTouch;
Romain Guy06882f82009-06-10 13:36:04 -07005649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005650 // Actual frame shown on-screen (may be modified by animation)
5651 final Rect mShownFrame = new Rect();
5652 final Rect mLastShownFrame = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005654 /**
5655 * Insets that determine the actually visible area
5656 */
5657 final Rect mVisibleInsets = new Rect();
5658 final Rect mLastVisibleInsets = new Rect();
5659 boolean mVisibleInsetsChanged;
5660
5661 /**
5662 * Insets that are covered by system windows
5663 */
5664 final Rect mContentInsets = new Rect();
5665 final Rect mLastContentInsets = new Rect();
5666 boolean mContentInsetsChanged;
5667
5668 /**
5669 * Set to true if we are waiting for this window to receive its
5670 * given internal insets before laying out other windows based on it.
5671 */
5672 boolean mGivenInsetsPending;
Romain Guy06882f82009-06-10 13:36:04 -07005673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005674 /**
5675 * These are the content insets that were given during layout for
5676 * this window, to be applied to windows behind it.
5677 */
5678 final Rect mGivenContentInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005680 /**
5681 * These are the visible insets that were given during layout for
5682 * this window, to be applied to windows behind it.
5683 */
5684 final Rect mGivenVisibleInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005686 /**
5687 * Flag indicating whether the touchable region should be adjusted by
5688 * the visible insets; if false the area outside the visible insets is
5689 * NOT touchable, so we must use those to adjust the frame during hit
5690 * tests.
5691 */
5692 int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
Romain Guy06882f82009-06-10 13:36:04 -07005693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005694 // Current transformation being applied.
5695 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
5696 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
5697 float mHScale=1, mVScale=1;
5698 float mLastHScale=1, mLastVScale=1;
5699 final Matrix mTmpMatrix = new Matrix();
5700
5701 // "Real" frame that the application sees.
5702 final Rect mFrame = new Rect();
5703 final Rect mLastFrame = new Rect();
5704
5705 final Rect mContainingFrame = new Rect();
5706 final Rect mDisplayFrame = new Rect();
5707 final Rect mContentFrame = new Rect();
5708 final Rect mVisibleFrame = new Rect();
5709
5710 float mShownAlpha = 1;
5711 float mAlpha = 1;
5712 float mLastAlpha = 1;
5713
5714 // Set to true if, when the window gets displayed, it should perform
5715 // an enter animation.
5716 boolean mEnterAnimationPending;
5717
5718 // Currently running animation.
5719 boolean mAnimating;
5720 boolean mLocalAnimating;
5721 Animation mAnimation;
5722 boolean mAnimationIsEntrance;
5723 boolean mHasTransformation;
5724 boolean mHasLocalTransformation;
5725 final Transformation mTransformation = new Transformation();
5726
5727 // This is set after IWindowSession.relayout() has been called at
5728 // least once for the window. It allows us to detect the situation
5729 // where we don't yet have a surface, but should have one soon, so
5730 // we can give the window focus before waiting for the relayout.
5731 boolean mRelayoutCalled;
Romain Guy06882f82009-06-10 13:36:04 -07005732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005733 // This is set after the Surface has been created but before the
5734 // window has been drawn. During this time the surface is hidden.
5735 boolean mDrawPending;
5736
5737 // This is set after the window has finished drawing for the first
5738 // time but before its surface is shown. The surface will be
5739 // displayed when the next layout is run.
5740 boolean mCommitDrawPending;
5741
5742 // This is set during the time after the window's drawing has been
5743 // committed, and before its surface is actually shown. It is used
5744 // to delay showing the surface until all windows in a token are ready
5745 // to be shown.
5746 boolean mReadyToShow;
Romain Guy06882f82009-06-10 13:36:04 -07005747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005748 // Set when the window has been shown in the screen the first time.
5749 boolean mHasDrawn;
5750
5751 // Currently running an exit animation?
5752 boolean mExiting;
5753
5754 // Currently on the mDestroySurface list?
5755 boolean mDestroying;
Romain Guy06882f82009-06-10 13:36:04 -07005756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005757 // Completely remove from window manager after exit animation?
5758 boolean mRemoveOnExit;
5759
5760 // Set when the orientation is changing and this window has not yet
5761 // been updated for the new orientation.
5762 boolean mOrientationChanging;
Romain Guy06882f82009-06-10 13:36:04 -07005763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005764 // Is this window now (or just being) removed?
5765 boolean mRemoved;
Romain Guy06882f82009-06-10 13:36:04 -07005766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005767 WindowState(Session s, IWindow c, WindowToken token,
5768 WindowState attachedWindow, WindowManager.LayoutParams a,
5769 int viewVisibility) {
5770 mSession = s;
5771 mClient = c;
5772 mToken = token;
5773 mAttrs.copyFrom(a);
5774 mViewVisibility = viewVisibility;
5775 DeathRecipient deathRecipient = new DeathRecipient();
5776 mAlpha = a.alpha;
5777 if (localLOGV) Log.v(
5778 TAG, "Window " + this + " client=" + c.asBinder()
5779 + " token=" + token + " (" + mAttrs.token + ")");
5780 try {
5781 c.asBinder().linkToDeath(deathRecipient, 0);
5782 } catch (RemoteException e) {
5783 mDeathRecipient = null;
5784 mAttachedWindow = null;
5785 mLayoutAttached = false;
5786 mIsImWindow = false;
5787 mBaseLayer = 0;
5788 mSubLayer = 0;
5789 return;
5790 }
5791 mDeathRecipient = deathRecipient;
Romain Guy06882f82009-06-10 13:36:04 -07005792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005793 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
5794 mAttrs.type <= LAST_SUB_WINDOW)) {
5795 // The multiplier here is to reserve space for multiple
5796 // windows in the same type layer.
5797 mBaseLayer = mPolicy.windowTypeToLayerLw(
5798 attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
5799 + TYPE_LAYER_OFFSET;
5800 mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
5801 mAttachedWindow = attachedWindow;
5802 mAttachedWindow.mChildWindows.add(this);
5803 mLayoutAttached = mAttrs.type !=
5804 WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
5805 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
5806 || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5807 } else {
5808 // The multiplier here is to reserve space for multiple
5809 // windows in the same type layer.
5810 mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
5811 * TYPE_LAYER_MULTIPLIER
5812 + TYPE_LAYER_OFFSET;
5813 mSubLayer = 0;
5814 mAttachedWindow = null;
5815 mLayoutAttached = false;
5816 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
5817 || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5818 }
5819
5820 WindowState appWin = this;
5821 while (appWin.mAttachedWindow != null) {
5822 appWin = mAttachedWindow;
5823 }
5824 WindowToken appToken = appWin.mToken;
5825 while (appToken.appWindowToken == null) {
5826 WindowToken parent = mTokenMap.get(appToken.token);
5827 if (parent == null || appToken == parent) {
5828 break;
5829 }
5830 appToken = parent;
5831 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005832 mRootToken = appToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005833 mAppToken = appToken.appWindowToken;
5834
5835 mSurface = null;
5836 mRequestedWidth = 0;
5837 mRequestedHeight = 0;
5838 mLastRequestedWidth = 0;
5839 mLastRequestedHeight = 0;
5840 mReqXPos = 0;
5841 mReqYPos = 0;
5842 mLayer = 0;
5843 mAnimLayer = 0;
5844 mLastLayer = 0;
5845 }
5846
5847 void attach() {
5848 if (localLOGV) Log.v(
5849 TAG, "Attaching " + this + " token=" + mToken
5850 + ", list=" + mToken.windows);
5851 mSession.windowAddedLocked();
5852 }
5853
5854 public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
5855 mHaveFrame = true;
5856
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005857 final Rect container = mContainingFrame;
5858 container.set(pf);
5859
5860 final Rect display = mDisplayFrame;
5861 display.set(df);
5862
5863 if ((mAttrs.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW) != 0) {
5864 container.intersect(mCompatibleScreenFrame);
5865 display.intersect(mCompatibleScreenFrame);
5866 }
5867
5868 final int pw = container.right - container.left;
5869 final int ph = container.bottom - container.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005870
5871 int w,h;
5872 if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
5873 w = mAttrs.width < 0 ? pw : mAttrs.width;
5874 h = mAttrs.height< 0 ? ph : mAttrs.height;
5875 } else {
5876 w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
5877 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
5878 }
Romain Guy06882f82009-06-10 13:36:04 -07005879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005880 final Rect content = mContentFrame;
5881 content.set(cf);
Romain Guy06882f82009-06-10 13:36:04 -07005882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005883 final Rect visible = mVisibleFrame;
5884 visible.set(vf);
Romain Guy06882f82009-06-10 13:36:04 -07005885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005886 final Rect frame = mFrame;
Romain Guy06882f82009-06-10 13:36:04 -07005887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005888 //System.out.println("In: w=" + w + " h=" + h + " container=" +
5889 // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
5890
5891 Gravity.apply(mAttrs.gravity, w, h, container,
5892 (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
5893 (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
5894
5895 //System.out.println("Out: " + mFrame);
5896
5897 // Now make sure the window fits in the overall display.
5898 Gravity.applyDisplay(mAttrs.gravity, df, frame);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005899
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005900 // Make sure the content and visible frames are inside of the
5901 // final window frame.
5902 if (content.left < frame.left) content.left = frame.left;
5903 if (content.top < frame.top) content.top = frame.top;
5904 if (content.right > frame.right) content.right = frame.right;
5905 if (content.bottom > frame.bottom) content.bottom = frame.bottom;
5906 if (visible.left < frame.left) visible.left = frame.left;
5907 if (visible.top < frame.top) visible.top = frame.top;
5908 if (visible.right > frame.right) visible.right = frame.right;
5909 if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005911 final Rect contentInsets = mContentInsets;
5912 contentInsets.left = content.left-frame.left;
5913 contentInsets.top = content.top-frame.top;
5914 contentInsets.right = frame.right-content.right;
5915 contentInsets.bottom = frame.bottom-content.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005917 final Rect visibleInsets = mVisibleInsets;
5918 visibleInsets.left = visible.left-frame.left;
5919 visibleInsets.top = visible.top-frame.top;
5920 visibleInsets.right = frame.right-visible.right;
5921 visibleInsets.bottom = frame.bottom-visible.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005923 if (localLOGV) {
5924 //if ("com.google.android.youtube".equals(mAttrs.packageName)
5925 // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
5926 Log.v(TAG, "Resolving (mRequestedWidth="
5927 + mRequestedWidth + ", mRequestedheight="
5928 + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
5929 + "): frame=" + mFrame.toShortString()
5930 + " ci=" + contentInsets.toShortString()
5931 + " vi=" + visibleInsets.toShortString());
5932 //}
5933 }
5934 }
Romain Guy06882f82009-06-10 13:36:04 -07005935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005936 public Rect getFrameLw() {
5937 return mFrame;
5938 }
5939
5940 public Rect getShownFrameLw() {
5941 return mShownFrame;
5942 }
5943
5944 public Rect getDisplayFrameLw() {
5945 return mDisplayFrame;
5946 }
5947
5948 public Rect getContentFrameLw() {
5949 return mContentFrame;
5950 }
5951
5952 public Rect getVisibleFrameLw() {
5953 return mVisibleFrame;
5954 }
5955
5956 public boolean getGivenInsetsPendingLw() {
5957 return mGivenInsetsPending;
5958 }
5959
5960 public Rect getGivenContentInsetsLw() {
5961 return mGivenContentInsets;
5962 }
Romain Guy06882f82009-06-10 13:36:04 -07005963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005964 public Rect getGivenVisibleInsetsLw() {
5965 return mGivenVisibleInsets;
5966 }
Romain Guy06882f82009-06-10 13:36:04 -07005967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005968 public WindowManager.LayoutParams getAttrs() {
5969 return mAttrs;
5970 }
5971
5972 public int getSurfaceLayer() {
5973 return mLayer;
5974 }
Romain Guy06882f82009-06-10 13:36:04 -07005975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005976 public IApplicationToken getAppToken() {
5977 return mAppToken != null ? mAppToken.appToken : null;
5978 }
5979
5980 public boolean hasAppShownWindows() {
5981 return mAppToken != null ? mAppToken.firstWindowDrawn : false;
5982 }
5983
5984 public boolean hasAppStartingIcon() {
5985 return mAppToken != null ? (mAppToken.startingData != null) : false;
5986 }
5987
5988 public WindowManagerPolicy.WindowState getAppStartingWindow() {
5989 return mAppToken != null ? mAppToken.startingWindow : null;
5990 }
5991
5992 public void setAnimation(Animation anim) {
5993 if (localLOGV) Log.v(
5994 TAG, "Setting animation in " + this + ": " + anim);
5995 mAnimating = false;
5996 mLocalAnimating = false;
5997 mAnimation = anim;
5998 mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
5999 mAnimation.scaleCurrentDuration(mWindowAnimationScale);
6000 }
6001
6002 public void clearAnimation() {
6003 if (mAnimation != null) {
6004 mAnimating = true;
6005 mLocalAnimating = false;
6006 mAnimation = null;
6007 }
6008 }
Romain Guy06882f82009-06-10 13:36:04 -07006009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006010 Surface createSurfaceLocked() {
6011 if (mSurface == null) {
6012 mDrawPending = true;
6013 mCommitDrawPending = false;
6014 mReadyToShow = false;
6015 if (mAppToken != null) {
6016 mAppToken.allDrawn = false;
6017 }
6018
6019 int flags = 0;
6020 if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
6021 flags |= Surface.HARDWARE;
6022 } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
6023 flags |= Surface.GPU;
6024 } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
6025 flags |= Surface.PUSH_BUFFERS;
6026 }
6027
6028 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
6029 flags |= Surface.SECURE;
6030 }
6031 if (DEBUG_VISIBILITY) Log.v(
6032 TAG, "Creating surface in session "
6033 + mSession.mSurfaceSession + " window " + this
6034 + " w=" + mFrame.width()
6035 + " h=" + mFrame.height() + " format="
6036 + mAttrs.format + " flags=" + flags);
6037
6038 int w = mFrame.width();
6039 int h = mFrame.height();
6040 if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
6041 // for a scaled surface, we always want the requested
6042 // size.
6043 w = mRequestedWidth;
6044 h = mRequestedHeight;
6045 }
6046
6047 try {
6048 mSurface = new Surface(
Romain Guy06882f82009-06-10 13:36:04 -07006049 mSession.mSurfaceSession, mSession.mPid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006050 0, w, h, mAttrs.format, flags);
6051 } catch (Surface.OutOfResourcesException e) {
6052 Log.w(TAG, "OutOfResourcesException creating surface");
6053 reclaimSomeSurfaceMemoryLocked(this, "create");
6054 return null;
6055 } catch (Exception e) {
6056 Log.e(TAG, "Exception creating surface", e);
6057 return null;
6058 }
Romain Guy06882f82009-06-10 13:36:04 -07006059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006060 if (localLOGV) Log.v(
6061 TAG, "Got surface: " + mSurface
6062 + ", set left=" + mFrame.left + " top=" + mFrame.top
6063 + ", animLayer=" + mAnimLayer);
6064 if (SHOW_TRANSACTIONS) {
6065 Log.i(TAG, ">>> OPEN TRANSACTION");
6066 Log.i(TAG, " SURFACE " + mSurface + ": CREATE ("
6067 + mAttrs.getTitle() + ") pos=(" +
6068 mFrame.left + "," + mFrame.top + ") (" +
6069 mFrame.width() + "x" + mFrame.height() + "), layer=" +
6070 mAnimLayer + " HIDE");
6071 }
6072 Surface.openTransaction();
6073 try {
6074 try {
6075 mSurface.setPosition(mFrame.left, mFrame.top);
6076 mSurface.setLayer(mAnimLayer);
6077 mSurface.hide();
6078 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
6079 mSurface.setFlags(Surface.SURFACE_DITHER,
6080 Surface.SURFACE_DITHER);
6081 }
6082 } catch (RuntimeException e) {
6083 Log.w(TAG, "Error creating surface in " + w, e);
6084 reclaimSomeSurfaceMemoryLocked(this, "create-init");
6085 }
6086 mLastHidden = true;
6087 } finally {
6088 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
6089 Surface.closeTransaction();
6090 }
6091 if (localLOGV) Log.v(
6092 TAG, "Created surface " + this);
6093 }
6094 return mSurface;
6095 }
Romain Guy06882f82009-06-10 13:36:04 -07006096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006097 void destroySurfaceLocked() {
6098 // Window is no longer on-screen, so can no longer receive
6099 // key events... if we were waiting for it to finish
6100 // handling a key event, the wait is over!
6101 mKeyWaiter.finishedKey(mSession, mClient, true,
6102 KeyWaiter.RETURN_NOTHING);
6103 mKeyWaiter.releasePendingPointerLocked(mSession);
6104 mKeyWaiter.releasePendingTrackballLocked(mSession);
6105
6106 if (mAppToken != null && this == mAppToken.startingWindow) {
6107 mAppToken.startingDisplayed = false;
6108 }
Romain Guy06882f82009-06-10 13:36:04 -07006109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006110 if (localLOGV) Log.v(
6111 TAG, "Window " + this
6112 + " destroying surface " + mSurface + ", session " + mSession);
6113 if (mSurface != null) {
6114 try {
6115 if (SHOW_TRANSACTIONS) {
6116 RuntimeException ex = new RuntimeException();
6117 ex.fillInStackTrace();
6118 Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
6119 + mAttrs.getTitle() + ")", ex);
6120 }
6121 mSurface.clear();
6122 } catch (RuntimeException e) {
6123 Log.w(TAG, "Exception thrown when destroying Window " + this
6124 + " surface " + mSurface + " session " + mSession
6125 + ": " + e.toString());
6126 }
6127 mSurface = null;
6128 mDrawPending = false;
6129 mCommitDrawPending = false;
6130 mReadyToShow = false;
6131
6132 int i = mChildWindows.size();
6133 while (i > 0) {
6134 i--;
6135 WindowState c = (WindowState)mChildWindows.get(i);
6136 c.mAttachedHidden = true;
6137 }
6138 }
6139 }
6140
6141 boolean finishDrawingLocked() {
6142 if (mDrawPending) {
6143 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
6144 TAG, "finishDrawingLocked: " + mSurface);
6145 mCommitDrawPending = true;
6146 mDrawPending = false;
6147 return true;
6148 }
6149 return false;
6150 }
6151
6152 // This must be called while inside a transaction.
6153 void commitFinishDrawingLocked(long currentTime) {
6154 //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
6155 if (!mCommitDrawPending) {
6156 return;
6157 }
6158 mCommitDrawPending = false;
6159 mReadyToShow = true;
6160 final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING;
6161 final AppWindowToken atoken = mAppToken;
6162 if (atoken == null || atoken.allDrawn || starting) {
6163 performShowLocked();
6164 }
6165 }
6166
6167 // This must be called while inside a transaction.
6168 boolean performShowLocked() {
6169 if (DEBUG_VISIBILITY) {
6170 RuntimeException e = new RuntimeException();
6171 e.fillInStackTrace();
6172 Log.v(TAG, "performShow on " + this
6173 + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
6174 + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
6175 }
6176 if (mReadyToShow && isReadyForDisplay()) {
6177 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i(
6178 TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)");
6179 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this
6180 + " during animation: policyVis=" + mPolicyVisibility
6181 + " attHidden=" + mAttachedHidden
6182 + " tok.hiddenRequested="
6183 + (mAppToken != null ? mAppToken.hiddenRequested : false)
6184 + " tok.idden="
6185 + (mAppToken != null ? mAppToken.hidden : false)
6186 + " animating=" + mAnimating
6187 + " tok animating="
6188 + (mAppToken != null ? mAppToken.animating : false));
6189 if (!showSurfaceRobustlyLocked(this)) {
6190 return false;
6191 }
6192 mLastAlpha = -1;
6193 mHasDrawn = true;
6194 mLastHidden = false;
6195 mReadyToShow = false;
6196 enableScreenIfNeededLocked();
6197
6198 applyEnterAnimationLocked(this);
Romain Guy06882f82009-06-10 13:36:04 -07006199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006200 int i = mChildWindows.size();
6201 while (i > 0) {
6202 i--;
6203 WindowState c = (WindowState)mChildWindows.get(i);
6204 if (c.mSurface != null && c.mAttachedHidden) {
6205 c.mAttachedHidden = false;
6206 c.performShowLocked();
6207 }
6208 }
Romain Guy06882f82009-06-10 13:36:04 -07006209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006210 if (mAttrs.type != TYPE_APPLICATION_STARTING
6211 && mAppToken != null) {
6212 mAppToken.firstWindowDrawn = true;
6213 if (mAnimation == null && mAppToken.startingData != null) {
6214 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6215 + mToken
6216 + ": first real window is shown, no animation");
6217 mFinishedStarting.add(mAppToken);
6218 mH.sendEmptyMessage(H.FINISHED_STARTING);
6219 }
6220 mAppToken.updateReportedVisibilityLocked();
6221 }
6222 }
6223 return true;
6224 }
Romain Guy06882f82009-06-10 13:36:04 -07006225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006226 // This must be called while inside a transaction. Returns true if
6227 // there is more animation to run.
6228 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6229 if (!mDisplayFrozen) {
6230 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07006231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006232 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
6233 mHasTransformation = true;
6234 mHasLocalTransformation = true;
6235 if (!mLocalAnimating) {
6236 if (DEBUG_ANIM) Log.v(
6237 TAG, "Starting animation in " + this +
6238 " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
6239 " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
6240 mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
6241 mAnimation.setStartTime(currentTime);
6242 mLocalAnimating = true;
6243 mAnimating = true;
6244 }
6245 mTransformation.clear();
6246 final boolean more = mAnimation.getTransformation(
6247 currentTime, mTransformation);
6248 if (DEBUG_ANIM) Log.v(
6249 TAG, "Stepped animation in " + this +
6250 ": more=" + more + ", xform=" + mTransformation);
6251 if (more) {
6252 // we're not done!
6253 return true;
6254 }
6255 if (DEBUG_ANIM) Log.v(
6256 TAG, "Finished animation in " + this +
6257 " @ " + currentTime);
6258 mAnimation = null;
6259 //WindowManagerService.this.dump();
6260 }
6261 mHasLocalTransformation = false;
6262 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
6263 && mAppToken.hasTransformation) {
6264 // When our app token is animating, we kind-of pretend like
6265 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
6266 // part of this check means that we will only do this if
6267 // our window is not currently exiting, or it is not
6268 // locally animating itself. The idea being that one that
6269 // is exiting and doing a local animation should be removed
6270 // once that animation is done.
6271 mAnimating = true;
6272 mHasTransformation = true;
6273 mTransformation.clear();
6274 return false;
6275 } else if (mHasTransformation) {
6276 // Little trick to get through the path below to act like
6277 // we have finished an animation.
6278 mAnimating = true;
6279 } else if (isAnimating()) {
6280 mAnimating = true;
6281 }
6282 } else if (mAnimation != null) {
6283 // If the display is frozen, and there is a pending animation,
6284 // clear it and make sure we run the cleanup code.
6285 mAnimating = true;
6286 mLocalAnimating = true;
6287 mAnimation = null;
6288 }
Romain Guy06882f82009-06-10 13:36:04 -07006289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006290 if (!mAnimating && !mLocalAnimating) {
6291 return false;
6292 }
6293
6294 if (DEBUG_ANIM) Log.v(
6295 TAG, "Animation done in " + this + ": exiting=" + mExiting
6296 + ", reportedVisible="
6297 + (mAppToken != null ? mAppToken.reportedVisible : false));
Romain Guy06882f82009-06-10 13:36:04 -07006298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006299 mAnimating = false;
6300 mLocalAnimating = false;
6301 mAnimation = null;
6302 mAnimLayer = mLayer;
6303 if (mIsImWindow) {
6304 mAnimLayer += mInputMethodAnimLayerAdjustment;
6305 }
6306 if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
6307 + " anim layer: " + mAnimLayer);
6308 mHasTransformation = false;
6309 mHasLocalTransformation = false;
6310 mPolicyVisibility = mPolicyVisibilityAfterAnim;
6311 mTransformation.clear();
6312 if (mHasDrawn
6313 && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
6314 && mAppToken != null
6315 && mAppToken.firstWindowDrawn
6316 && mAppToken.startingData != null) {
6317 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6318 + mToken + ": first real window done animating");
6319 mFinishedStarting.add(mAppToken);
6320 mH.sendEmptyMessage(H.FINISHED_STARTING);
6321 }
Romain Guy06882f82009-06-10 13:36:04 -07006322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006323 finishExit();
6324
6325 if (mAppToken != null) {
6326 mAppToken.updateReportedVisibilityLocked();
6327 }
6328
6329 return false;
6330 }
6331
6332 void finishExit() {
6333 if (DEBUG_ANIM) Log.v(
6334 TAG, "finishExit in " + this
6335 + ": exiting=" + mExiting
6336 + " remove=" + mRemoveOnExit
6337 + " windowAnimating=" + isWindowAnimating());
Romain Guy06882f82009-06-10 13:36:04 -07006338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006339 final int N = mChildWindows.size();
6340 for (int i=0; i<N; i++) {
6341 ((WindowState)mChildWindows.get(i)).finishExit();
6342 }
Romain Guy06882f82009-06-10 13:36:04 -07006343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006344 if (!mExiting) {
6345 return;
6346 }
Romain Guy06882f82009-06-10 13:36:04 -07006347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006348 if (isWindowAnimating()) {
6349 return;
6350 }
6351
6352 if (localLOGV) Log.v(
6353 TAG, "Exit animation finished in " + this
6354 + ": remove=" + mRemoveOnExit);
6355 if (mSurface != null) {
6356 mDestroySurface.add(this);
6357 mDestroying = true;
6358 if (SHOW_TRANSACTIONS) Log.i(
6359 TAG, " SURFACE " + mSurface + ": HIDE (finishExit)");
6360 try {
6361 mSurface.hide();
6362 } catch (RuntimeException e) {
6363 Log.w(TAG, "Error hiding surface in " + this, e);
6364 }
6365 mLastHidden = true;
6366 mKeyWaiter.releasePendingPointerLocked(mSession);
6367 }
6368 mExiting = false;
6369 if (mRemoveOnExit) {
6370 mPendingRemove.add(this);
6371 mRemoveOnExit = false;
6372 }
6373 }
Romain Guy06882f82009-06-10 13:36:04 -07006374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006375 boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
6376 if (dsdx < .99999f || dsdx > 1.00001f) return false;
6377 if (dtdy < .99999f || dtdy > 1.00001f) return false;
6378 if (dtdx < -.000001f || dtdx > .000001f) return false;
6379 if (dsdy < -.000001f || dsdy > .000001f) return false;
6380 return true;
6381 }
Romain Guy06882f82009-06-10 13:36:04 -07006382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006383 void computeShownFrameLocked() {
6384 final boolean selfTransformation = mHasLocalTransformation;
6385 Transformation attachedTransformation =
6386 (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
6387 ? mAttachedWindow.mTransformation : null;
6388 Transformation appTransformation =
6389 (mAppToken != null && mAppToken.hasTransformation)
6390 ? mAppToken.transformation : null;
6391 if (selfTransformation || attachedTransformation != null
6392 || appTransformation != null) {
Romain Guy06882f82009-06-10 13:36:04 -07006393 // cache often used attributes locally
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006394 final Rect frame = mFrame;
6395 final float tmpFloats[] = mTmpFloats;
6396 final Matrix tmpMatrix = mTmpMatrix;
6397
6398 // Compute the desired transformation.
6399 tmpMatrix.setTranslate(frame.left, frame.top);
6400 if (selfTransformation) {
6401 tmpMatrix.preConcat(mTransformation.getMatrix());
6402 }
6403 if (attachedTransformation != null) {
6404 tmpMatrix.preConcat(attachedTransformation.getMatrix());
6405 }
6406 if (appTransformation != null) {
6407 tmpMatrix.preConcat(appTransformation.getMatrix());
6408 }
6409
6410 // "convert" it into SurfaceFlinger's format
6411 // (a 2x2 matrix + an offset)
6412 // Here we must not transform the position of the surface
6413 // since it is already included in the transformation.
6414 //Log.i(TAG, "Transform: " + matrix);
Romain Guy06882f82009-06-10 13:36:04 -07006415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006416 tmpMatrix.getValues(tmpFloats);
6417 mDsDx = tmpFloats[Matrix.MSCALE_X];
6418 mDtDx = tmpFloats[Matrix.MSKEW_X];
6419 mDsDy = tmpFloats[Matrix.MSKEW_Y];
6420 mDtDy = tmpFloats[Matrix.MSCALE_Y];
6421 int x = (int)tmpFloats[Matrix.MTRANS_X];
6422 int y = (int)tmpFloats[Matrix.MTRANS_Y];
6423 int w = frame.width();
6424 int h = frame.height();
6425 mShownFrame.set(x, y, x+w, y+h);
6426
6427 // Now set the alpha... but because our current hardware
6428 // can't do alpha transformation on a non-opaque surface,
6429 // turn it off if we are running an animation that is also
6430 // transforming since it is more important to have that
6431 // animation be smooth.
6432 mShownAlpha = mAlpha;
6433 if (!mLimitedAlphaCompositing
6434 || (!PixelFormat.formatHasAlpha(mAttrs.format)
6435 || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
6436 && x == frame.left && y == frame.top))) {
6437 //Log.i(TAG, "Applying alpha transform");
6438 if (selfTransformation) {
6439 mShownAlpha *= mTransformation.getAlpha();
6440 }
6441 if (attachedTransformation != null) {
6442 mShownAlpha *= attachedTransformation.getAlpha();
6443 }
6444 if (appTransformation != null) {
6445 mShownAlpha *= appTransformation.getAlpha();
6446 }
6447 } else {
6448 //Log.i(TAG, "Not applying alpha transform");
6449 }
Romain Guy06882f82009-06-10 13:36:04 -07006450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006451 if (localLOGV) Log.v(
6452 TAG, "Continuing animation in " + this +
6453 ": " + mShownFrame +
6454 ", alpha=" + mTransformation.getAlpha());
6455 return;
6456 }
Romain Guy06882f82009-06-10 13:36:04 -07006457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006458 mShownFrame.set(mFrame);
6459 mShownAlpha = mAlpha;
6460 mDsDx = 1;
6461 mDtDx = 0;
6462 mDsDy = 0;
6463 mDtDy = 1;
6464 }
Romain Guy06882f82009-06-10 13:36:04 -07006465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006466 /**
6467 * Is this window visible? It is not visible if there is no
6468 * surface, or we are in the process of running an exit animation
6469 * that will remove the surface, or its app token has been hidden.
6470 */
6471 public boolean isVisibleLw() {
6472 final AppWindowToken atoken = mAppToken;
6473 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6474 && (atoken == null || !atoken.hiddenRequested)
6475 && !mExiting && !mDestroying;
6476 }
6477
6478 /**
6479 * Is this window visible, ignoring its app token? It is not visible
6480 * if there is no surface, or we are in the process of running an exit animation
6481 * that will remove the surface.
6482 */
6483 public boolean isWinVisibleLw() {
6484 final AppWindowToken atoken = mAppToken;
6485 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6486 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
6487 && !mExiting && !mDestroying;
6488 }
6489
6490 /**
6491 * The same as isVisible(), but follows the current hidden state of
6492 * the associated app token, not the pending requested hidden state.
6493 */
6494 boolean isVisibleNow() {
6495 return mSurface != null && mPolicyVisibility && !mAttachedHidden
The Android Open Source Project10592532009-03-18 17:39:46 -07006496 && !mRootToken.hidden && !mExiting && !mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006497 }
6498
6499 /**
6500 * Same as isVisible(), but we also count it as visible between the
6501 * call to IWindowSession.add() and the first relayout().
6502 */
6503 boolean isVisibleOrAdding() {
6504 final AppWindowToken atoken = mAppToken;
6505 return (mSurface != null
6506 || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
6507 && mPolicyVisibility && !mAttachedHidden
6508 && (atoken == null || !atoken.hiddenRequested)
6509 && !mExiting && !mDestroying;
6510 }
6511
6512 /**
6513 * Is this window currently on-screen? It is on-screen either if it
6514 * is visible or it is currently running an animation before no longer
6515 * being visible.
6516 */
6517 boolean isOnScreen() {
6518 final AppWindowToken atoken = mAppToken;
6519 if (atoken != null) {
6520 return mSurface != null && mPolicyVisibility && !mDestroying
6521 && ((!mAttachedHidden && !atoken.hiddenRequested)
6522 || mAnimating || atoken.animating);
6523 } else {
6524 return mSurface != null && mPolicyVisibility && !mDestroying
6525 && (!mAttachedHidden || mAnimating);
6526 }
6527 }
Romain Guy06882f82009-06-10 13:36:04 -07006528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006529 /**
6530 * Like isOnScreen(), but we don't return true if the window is part
6531 * of a transition that has not yet been started.
6532 */
6533 boolean isReadyForDisplay() {
6534 final AppWindowToken atoken = mAppToken;
6535 final boolean animating = atoken != null ? atoken.animating : false;
6536 return mSurface != null && mPolicyVisibility && !mDestroying
The Android Open Source Project10592532009-03-18 17:39:46 -07006537 && ((!mAttachedHidden && !mRootToken.hidden)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006538 || mAnimating || animating);
6539 }
6540
6541 /** Is the window or its container currently animating? */
6542 boolean isAnimating() {
6543 final WindowState attached = mAttachedWindow;
6544 final AppWindowToken atoken = mAppToken;
6545 return mAnimation != null
6546 || (attached != null && attached.mAnimation != null)
Romain Guy06882f82009-06-10 13:36:04 -07006547 || (atoken != null &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006548 (atoken.animation != null
6549 || atoken.inPendingTransaction));
6550 }
6551
6552 /** Is this window currently animating? */
6553 boolean isWindowAnimating() {
6554 return mAnimation != null;
6555 }
6556
6557 /**
6558 * Like isOnScreen, but returns false if the surface hasn't yet
6559 * been drawn.
6560 */
6561 public boolean isDisplayedLw() {
6562 final AppWindowToken atoken = mAppToken;
6563 return mSurface != null && mPolicyVisibility && !mDestroying
6564 && !mDrawPending && !mCommitDrawPending
6565 && ((!mAttachedHidden &&
6566 (atoken == null || !atoken.hiddenRequested))
6567 || mAnimating);
6568 }
6569
6570 public boolean fillsScreenLw(int screenWidth, int screenHeight,
6571 boolean shownFrame, boolean onlyOpaque) {
6572 if (mSurface == null) {
6573 return false;
6574 }
6575 if (mAppToken != null && !mAppToken.appFullscreen) {
6576 return false;
6577 }
6578 if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
6579 return false;
6580 }
6581 final Rect frame = shownFrame ? mShownFrame : mFrame;
6582 if (frame.left <= 0 && frame.top <= 0
6583 && frame.right >= screenWidth
6584 && frame.bottom >= screenHeight) {
6585 return true;
6586 }
6587 return false;
6588 }
Romain Guy06882f82009-06-10 13:36:04 -07006589
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006590 /**
6591 * Return true if the window is opaque and fully drawn.
6592 */
6593 boolean isOpaqueDrawn() {
6594 return mAttrs.format == PixelFormat.OPAQUE && mSurface != null
6595 && mAnimation == null && !mDrawPending && !mCommitDrawPending;
6596 }
6597
6598 boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
6599 return
6600 // only if the application is requesting compatible window
6601 (mAttrs.flags & mAttrs.FLAG_COMPATIBLE_WINDOW) != 0 &&
6602 // and only if the application wanted to fill the screen
6603 mAttrs.width == mAttrs.FILL_PARENT &&
6604 mAttrs.height == mAttrs.FILL_PARENT &&
6605 // and only if the screen is bigger
6606 ((mFrame.right - mFrame.right) < screenWidth ||
6607 (mFrame.bottom - mFrame.top) < screenHeight);
6608 }
6609
6610 boolean isFullscreen(int screenWidth, int screenHeight) {
6611 return mFrame.left <= 0 && mFrame.top <= 0 &&
6612 mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006613 }
6614
6615 void removeLocked() {
6616 if (mAttachedWindow != null) {
6617 mAttachedWindow.mChildWindows.remove(this);
6618 }
6619 destroySurfaceLocked();
6620 mSession.windowRemovedLocked();
6621 try {
6622 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
6623 } catch (RuntimeException e) {
6624 // Ignore if it has already been removed (usually because
6625 // we are doing this as part of processing a death note.)
6626 }
6627 }
6628
6629 private class DeathRecipient implements IBinder.DeathRecipient {
6630 public void binderDied() {
6631 try {
6632 synchronized(mWindowMap) {
6633 WindowState win = windowForClientLocked(mSession, mClient);
6634 Log.i(TAG, "WIN DEATH: " + win);
6635 if (win != null) {
6636 removeWindowLocked(mSession, win);
6637 }
6638 }
6639 } catch (IllegalArgumentException ex) {
6640 // This will happen if the window has already been
6641 // removed.
6642 }
6643 }
6644 }
6645
6646 /** Returns true if this window desires key events. */
6647 public final boolean canReceiveKeys() {
6648 return isVisibleOrAdding()
6649 && (mViewVisibility == View.VISIBLE)
6650 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
6651 }
6652
6653 public boolean hasDrawnLw() {
6654 return mHasDrawn;
6655 }
6656
6657 public boolean showLw(boolean doAnimation) {
6658 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
6659 mPolicyVisibility = true;
6660 mPolicyVisibilityAfterAnim = true;
6661 if (doAnimation) {
6662 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
6663 }
6664 requestAnimationLocked(0);
6665 return true;
6666 }
6667 return false;
6668 }
6669
6670 public boolean hideLw(boolean doAnimation) {
6671 boolean current = doAnimation ? mPolicyVisibilityAfterAnim
6672 : mPolicyVisibility;
6673 if (current) {
6674 if (doAnimation) {
6675 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
6676 if (mAnimation == null) {
6677 doAnimation = false;
6678 }
6679 }
6680 if (doAnimation) {
6681 mPolicyVisibilityAfterAnim = false;
6682 } else {
6683 mPolicyVisibilityAfterAnim = false;
6684 mPolicyVisibility = false;
6685 }
6686 requestAnimationLocked(0);
6687 return true;
6688 }
6689 return false;
6690 }
6691
6692 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006693 StringBuilder sb = new StringBuilder(64);
Romain Guy06882f82009-06-10 13:36:04 -07006694
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006695 pw.print(prefix); pw.print("mSession="); pw.print(mSession);
6696 pw.print(" mClient="); pw.println(mClient.asBinder());
6697 pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
6698 if (mAttachedWindow != null || mLayoutAttached) {
6699 pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
6700 pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
6701 }
6702 if (mIsImWindow) {
6703 pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
6704 }
6705 pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
6706 pw.print(" mSubLayer="); pw.print(mSubLayer);
6707 pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
6708 pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
6709 : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)));
6710 pw.print("="); pw.print(mAnimLayer);
6711 pw.print(" mLastLayer="); pw.println(mLastLayer);
6712 if (mSurface != null) {
6713 pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
6714 }
6715 pw.print(prefix); pw.print("mToken="); pw.println(mToken);
6716 pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
6717 if (mAppToken != null) {
6718 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
6719 }
6720 if (mTargetAppToken != null) {
6721 pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken);
6722 }
6723 pw.print(prefix); pw.print("mViewVisibility=0x");
6724 pw.print(Integer.toHexString(mViewVisibility));
6725 pw.print(" mLastHidden="); pw.print(mLastHidden);
6726 pw.print(" mHaveFrame="); pw.println(mHaveFrame);
6727 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
6728 pw.print(prefix); pw.print("mPolicyVisibility=");
6729 pw.print(mPolicyVisibility);
6730 pw.print(" mPolicyVisibilityAfterAnim=");
6731 pw.print(mPolicyVisibilityAfterAnim);
6732 pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
6733 }
6734 pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
6735 pw.print(" h="); pw.print(mRequestedHeight);
6736 pw.print(" x="); pw.print(mReqXPos);
6737 pw.print(" y="); pw.println(mReqYPos);
6738 pw.print(prefix); pw.print("mGivenContentInsets=");
6739 mGivenContentInsets.printShortString(pw);
6740 pw.print(" mGivenVisibleInsets=");
6741 mGivenVisibleInsets.printShortString(pw);
6742 pw.println();
6743 if (mTouchableInsets != 0 || mGivenInsetsPending) {
6744 pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
6745 pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
6746 }
6747 pw.print(prefix); pw.print("mShownFrame=");
6748 mShownFrame.printShortString(pw);
6749 pw.print(" last="); mLastShownFrame.printShortString(pw);
6750 pw.println();
6751 pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
6752 pw.print(" last="); mLastFrame.printShortString(pw);
6753 pw.println();
6754 pw.print(prefix); pw.print("mContainingFrame=");
6755 mContainingFrame.printShortString(pw);
6756 pw.print(" mDisplayFrame=");
6757 mDisplayFrame.printShortString(pw);
6758 pw.println();
6759 pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw);
6760 pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw);
6761 pw.println();
6762 pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw);
6763 pw.print(" last="); mLastContentInsets.printShortString(pw);
6764 pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw);
6765 pw.print(" last="); mLastVisibleInsets.printShortString(pw);
6766 pw.println();
6767 if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
6768 pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
6769 pw.print(" mAlpha="); pw.print(mAlpha);
6770 pw.print(" mLastAlpha="); pw.println(mLastAlpha);
6771 }
6772 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
6773 || mAnimation != null) {
6774 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
6775 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
6776 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
6777 pw.print(" mAnimation="); pw.println(mAnimation);
6778 }
6779 if (mHasTransformation || mHasLocalTransformation) {
6780 pw.print(prefix); pw.print("XForm: has=");
6781 pw.print(mHasTransformation);
6782 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
6783 pw.print(" "); mTransformation.printShortString(pw);
6784 pw.println();
6785 }
6786 pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending);
6787 pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending);
6788 pw.print(" mReadyToShow="); pw.print(mReadyToShow);
6789 pw.print(" mHasDrawn="); pw.println(mHasDrawn);
6790 if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
6791 pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
6792 pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
6793 pw.print(" mDestroying="); pw.print(mDestroying);
6794 pw.print(" mRemoved="); pw.println(mRemoved);
6795 }
6796 if (mOrientationChanging || mAppFreezing) {
6797 pw.print(prefix); pw.print("mOrientationChanging=");
6798 pw.print(mOrientationChanging);
6799 pw.print(" mAppFreezing="); pw.println(mAppFreezing);
6800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006801 }
6802
6803 @Override
6804 public String toString() {
6805 return "Window{"
6806 + Integer.toHexString(System.identityHashCode(this))
6807 + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
6808 }
6809 }
Romain Guy06882f82009-06-10 13:36:04 -07006810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006811 // -------------------------------------------------------------
6812 // Window Token State
6813 // -------------------------------------------------------------
6814
6815 class WindowToken {
6816 // The actual token.
6817 final IBinder token;
6818
6819 // The type of window this token is for, as per WindowManager.LayoutParams.
6820 final int windowType;
Romain Guy06882f82009-06-10 13:36:04 -07006821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006822 // Set if this token was explicitly added by a client, so should
6823 // not be removed when all windows are removed.
6824 final boolean explicit;
Romain Guy06882f82009-06-10 13:36:04 -07006825
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006826 // For printing.
6827 String stringName;
Romain Guy06882f82009-06-10 13:36:04 -07006828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006829 // If this is an AppWindowToken, this is non-null.
6830 AppWindowToken appWindowToken;
Romain Guy06882f82009-06-10 13:36:04 -07006831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006832 // All of the windows associated with this token.
6833 final ArrayList<WindowState> windows = new ArrayList<WindowState>();
6834
6835 // Is key dispatching paused for this token?
6836 boolean paused = false;
6837
6838 // Should this token's windows be hidden?
6839 boolean hidden;
6840
6841 // Temporary for finding which tokens no longer have visible windows.
6842 boolean hasVisible;
6843
6844 WindowToken(IBinder _token, int type, boolean _explicit) {
6845 token = _token;
6846 windowType = type;
6847 explicit = _explicit;
6848 }
6849
6850 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006851 pw.print(prefix); pw.print("token="); pw.println(token);
6852 pw.print(prefix); pw.print("windows="); pw.println(windows);
6853 pw.print(prefix); pw.print("windowType="); pw.print(windowType);
6854 pw.print(" hidden="); pw.print(hidden);
6855 pw.print(" hasVisible="); pw.println(hasVisible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006856 }
6857
6858 @Override
6859 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006860 if (stringName == null) {
6861 StringBuilder sb = new StringBuilder();
6862 sb.append("WindowToken{");
6863 sb.append(Integer.toHexString(System.identityHashCode(this)));
6864 sb.append(" token="); sb.append(token); sb.append('}');
6865 stringName = sb.toString();
6866 }
6867 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006868 }
6869 };
6870
6871 class AppWindowToken extends WindowToken {
6872 // Non-null only for application tokens.
6873 final IApplicationToken appToken;
6874
6875 // All of the windows and child windows that are included in this
6876 // application token. Note this list is NOT sorted!
6877 final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
6878
6879 int groupId = -1;
6880 boolean appFullscreen;
6881 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Romain Guy06882f82009-06-10 13:36:04 -07006882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006883 // These are used for determining when all windows associated with
6884 // an activity have been drawn, so they can be made visible together
6885 // at the same time.
6886 int lastTransactionSequence = mTransactionSequence-1;
6887 int numInterestingWindows;
6888 int numDrawnWindows;
6889 boolean inPendingTransaction;
6890 boolean allDrawn;
Romain Guy06882f82009-06-10 13:36:04 -07006891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006892 // Is this token going to be hidden in a little while? If so, it
6893 // won't be taken into account for setting the screen orientation.
6894 boolean willBeHidden;
Romain Guy06882f82009-06-10 13:36:04 -07006895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006896 // Is this window's surface needed? This is almost like hidden, except
6897 // it will sometimes be true a little earlier: when the token has
6898 // been shown, but is still waiting for its app transition to execute
6899 // before making its windows shown.
6900 boolean hiddenRequested;
Romain Guy06882f82009-06-10 13:36:04 -07006901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006902 // Have we told the window clients to hide themselves?
6903 boolean clientHidden;
Romain Guy06882f82009-06-10 13:36:04 -07006904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006905 // Last visibility state we reported to the app token.
6906 boolean reportedVisible;
6907
6908 // Set to true when the token has been removed from the window mgr.
6909 boolean removed;
6910
6911 // Have we been asked to have this token keep the screen frozen?
6912 boolean freezingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07006913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006914 boolean animating;
6915 Animation animation;
6916 boolean hasTransformation;
6917 final Transformation transformation = new Transformation();
Romain Guy06882f82009-06-10 13:36:04 -07006918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006919 // Offset to the window of all layers in the token, for use by
6920 // AppWindowToken animations.
6921 int animLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -07006922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006923 // Information about an application starting window if displayed.
6924 StartingData startingData;
6925 WindowState startingWindow;
6926 View startingView;
6927 boolean startingDisplayed;
6928 boolean startingMoved;
6929 boolean firstWindowDrawn;
6930
6931 AppWindowToken(IApplicationToken _token) {
6932 super(_token.asBinder(),
6933 WindowManager.LayoutParams.TYPE_APPLICATION, true);
6934 appWindowToken = this;
6935 appToken = _token;
6936 }
Romain Guy06882f82009-06-10 13:36:04 -07006937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006938 public void setAnimation(Animation anim) {
6939 if (localLOGV) Log.v(
6940 TAG, "Setting animation in " + this + ": " + anim);
6941 animation = anim;
6942 animating = false;
6943 anim.restrictDuration(MAX_ANIMATION_DURATION);
6944 anim.scaleCurrentDuration(mTransitionAnimationScale);
6945 int zorder = anim.getZAdjustment();
6946 int adj = 0;
6947 if (zorder == Animation.ZORDER_TOP) {
6948 adj = TYPE_LAYER_OFFSET;
6949 } else if (zorder == Animation.ZORDER_BOTTOM) {
6950 adj = -TYPE_LAYER_OFFSET;
6951 }
Romain Guy06882f82009-06-10 13:36:04 -07006952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 if (animLayerAdjustment != adj) {
6954 animLayerAdjustment = adj;
6955 updateLayers();
6956 }
6957 }
Romain Guy06882f82009-06-10 13:36:04 -07006958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006959 public void setDummyAnimation() {
6960 if (animation == null) {
6961 if (localLOGV) Log.v(
6962 TAG, "Setting dummy animation in " + this);
6963 animation = sDummyAnimation;
6964 }
6965 }
6966
6967 public void clearAnimation() {
6968 if (animation != null) {
6969 animation = null;
6970 animating = true;
6971 }
6972 }
Romain Guy06882f82009-06-10 13:36:04 -07006973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006974 void updateLayers() {
6975 final int N = allAppWindows.size();
6976 final int adj = animLayerAdjustment;
6977 for (int i=0; i<N; i++) {
6978 WindowState w = allAppWindows.get(i);
6979 w.mAnimLayer = w.mLayer + adj;
6980 if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
6981 + w.mAnimLayer);
6982 if (w == mInputMethodTarget) {
6983 setInputMethodAnimLayerAdjustment(adj);
6984 }
6985 }
6986 }
Romain Guy06882f82009-06-10 13:36:04 -07006987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006988 void sendAppVisibilityToClients() {
6989 final int N = allAppWindows.size();
6990 for (int i=0; i<N; i++) {
6991 WindowState win = allAppWindows.get(i);
6992 if (win == startingWindow && clientHidden) {
6993 // Don't hide the starting window.
6994 continue;
6995 }
6996 try {
6997 if (DEBUG_VISIBILITY) Log.v(TAG,
6998 "Setting visibility of " + win + ": " + (!clientHidden));
6999 win.mClient.dispatchAppVisibility(!clientHidden);
7000 } catch (RemoteException e) {
7001 }
7002 }
7003 }
Romain Guy06882f82009-06-10 13:36:04 -07007004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007005 void showAllWindowsLocked() {
7006 final int NW = allAppWindows.size();
7007 for (int i=0; i<NW; i++) {
7008 WindowState w = allAppWindows.get(i);
7009 if (DEBUG_VISIBILITY) Log.v(TAG,
7010 "performing show on: " + w);
7011 w.performShowLocked();
7012 }
7013 }
Romain Guy06882f82009-06-10 13:36:04 -07007014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007015 // This must be called while inside a transaction.
7016 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
7017 if (!mDisplayFrozen) {
7018 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07007019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 if (animation == sDummyAnimation) {
7021 // This guy is going to animate, but not yet. For now count
7022 // it is not animating for purposes of scheduling transactions;
7023 // when it is really time to animate, this will be set to
7024 // a real animation and the next call will execute normally.
7025 return false;
7026 }
Romain Guy06882f82009-06-10 13:36:04 -07007027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007028 if ((allDrawn || animating || startingDisplayed) && animation != null) {
7029 if (!animating) {
7030 if (DEBUG_ANIM) Log.v(
7031 TAG, "Starting animation in " + this +
7032 " @ " + currentTime + ": dw=" + dw + " dh=" + dh
7033 + " scale=" + mTransitionAnimationScale
7034 + " allDrawn=" + allDrawn + " animating=" + animating);
7035 animation.initialize(dw, dh, dw, dh);
7036 animation.setStartTime(currentTime);
7037 animating = true;
7038 }
7039 transformation.clear();
7040 final boolean more = animation.getTransformation(
7041 currentTime, transformation);
7042 if (DEBUG_ANIM) Log.v(
7043 TAG, "Stepped animation in " + this +
7044 ": more=" + more + ", xform=" + transformation);
7045 if (more) {
7046 // we're done!
7047 hasTransformation = true;
7048 return true;
7049 }
7050 if (DEBUG_ANIM) Log.v(
7051 TAG, "Finished animation in " + this +
7052 " @ " + currentTime);
7053 animation = null;
7054 }
7055 } else if (animation != null) {
7056 // If the display is frozen, and there is a pending animation,
7057 // clear it and make sure we run the cleanup code.
7058 animating = true;
7059 animation = null;
7060 }
7061
7062 hasTransformation = false;
Romain Guy06882f82009-06-10 13:36:04 -07007063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 if (!animating) {
7065 return false;
7066 }
7067
7068 clearAnimation();
7069 animating = false;
7070 if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
7071 moveInputMethodWindowsIfNeededLocked(true);
7072 }
Romain Guy06882f82009-06-10 13:36:04 -07007073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007074 if (DEBUG_ANIM) Log.v(
7075 TAG, "Animation done in " + this
7076 + ": reportedVisible=" + reportedVisible);
7077
7078 transformation.clear();
7079 if (animLayerAdjustment != 0) {
7080 animLayerAdjustment = 0;
7081 updateLayers();
7082 }
Romain Guy06882f82009-06-10 13:36:04 -07007083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007084 final int N = windows.size();
7085 for (int i=0; i<N; i++) {
7086 ((WindowState)windows.get(i)).finishExit();
7087 }
7088 updateReportedVisibilityLocked();
Romain Guy06882f82009-06-10 13:36:04 -07007089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 return false;
7091 }
7092
7093 void updateReportedVisibilityLocked() {
7094 if (appToken == null) {
7095 return;
7096 }
Romain Guy06882f82009-06-10 13:36:04 -07007097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007098 int numInteresting = 0;
7099 int numVisible = 0;
7100 boolean nowGone = true;
Romain Guy06882f82009-06-10 13:36:04 -07007101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007102 if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
7103 final int N = allAppWindows.size();
7104 for (int i=0; i<N; i++) {
7105 WindowState win = allAppWindows.get(i);
7106 if (win == startingWindow || win.mAppFreezing) {
7107 continue;
7108 }
7109 if (DEBUG_VISIBILITY) {
7110 Log.v(TAG, "Win " + win + ": isDisplayed="
7111 + win.isDisplayedLw()
7112 + ", isAnimating=" + win.isAnimating());
7113 if (!win.isDisplayedLw()) {
7114 Log.v(TAG, "Not displayed: s=" + win.mSurface
7115 + " pv=" + win.mPolicyVisibility
7116 + " dp=" + win.mDrawPending
7117 + " cdp=" + win.mCommitDrawPending
7118 + " ah=" + win.mAttachedHidden
7119 + " th="
7120 + (win.mAppToken != null
7121 ? win.mAppToken.hiddenRequested : false)
7122 + " a=" + win.mAnimating);
7123 }
7124 }
7125 numInteresting++;
7126 if (win.isDisplayedLw()) {
7127 if (!win.isAnimating()) {
7128 numVisible++;
7129 }
7130 nowGone = false;
7131 } else if (win.isAnimating()) {
7132 nowGone = false;
7133 }
7134 }
Romain Guy06882f82009-06-10 13:36:04 -07007135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007136 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
7137 if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
7138 + numInteresting + " visible=" + numVisible);
7139 if (nowVisible != reportedVisible) {
7140 if (DEBUG_VISIBILITY) Log.v(
7141 TAG, "Visibility changed in " + this
7142 + ": vis=" + nowVisible);
7143 reportedVisible = nowVisible;
7144 Message m = mH.obtainMessage(
7145 H.REPORT_APPLICATION_TOKEN_WINDOWS,
7146 nowVisible ? 1 : 0,
7147 nowGone ? 1 : 0,
7148 this);
7149 mH.sendMessage(m);
7150 }
7151 }
Romain Guy06882f82009-06-10 13:36:04 -07007152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007153 void dump(PrintWriter pw, String prefix) {
7154 super.dump(pw, prefix);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007155 if (appToken != null) {
7156 pw.print(prefix); pw.println("app=true");
7157 }
7158 if (allAppWindows.size() > 0) {
7159 pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
7160 }
7161 pw.print(prefix); pw.print("groupId="); pw.print(groupId);
7162 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
7163 pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
7164 pw.print(" clientHidden="); pw.print(clientHidden);
7165 pw.print(" willBeHidden="); pw.print(willBeHidden);
7166 pw.print(" reportedVisible="); pw.println(reportedVisible);
7167 if (paused || freezingScreen) {
7168 pw.print(prefix); pw.print("paused="); pw.print(paused);
7169 pw.print(" freezingScreen="); pw.println(freezingScreen);
7170 }
7171 if (numInterestingWindows != 0 || numDrawnWindows != 0
7172 || inPendingTransaction || allDrawn) {
7173 pw.print(prefix); pw.print("numInterestingWindows=");
7174 pw.print(numInterestingWindows);
7175 pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
7176 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
7177 pw.print(" allDrawn="); pw.println(allDrawn);
7178 }
7179 if (animating || animation != null) {
7180 pw.print(prefix); pw.print("animating="); pw.print(animating);
7181 pw.print(" animation="); pw.println(animation);
7182 }
7183 if (animLayerAdjustment != 0) {
7184 pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
7185 }
7186 if (hasTransformation) {
7187 pw.print(prefix); pw.print("hasTransformation="); pw.print(hasTransformation);
7188 pw.print(" transformation="); transformation.printShortString(pw);
7189 pw.println();
7190 }
7191 if (startingData != null || removed || firstWindowDrawn) {
7192 pw.print(prefix); pw.print("startingData="); pw.print(startingData);
7193 pw.print(" removed="); pw.print(removed);
7194 pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
7195 }
7196 if (startingWindow != null || startingView != null
7197 || startingDisplayed || startingMoved) {
7198 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
7199 pw.print(" startingView="); pw.print(startingView);
7200 pw.print(" startingDisplayed="); pw.print(startingDisplayed);
7201 pw.print(" startingMoved"); pw.println(startingMoved);
7202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007203 }
7204
7205 @Override
7206 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007207 if (stringName == null) {
7208 StringBuilder sb = new StringBuilder();
7209 sb.append("AppWindowToken{");
7210 sb.append(Integer.toHexString(System.identityHashCode(this)));
7211 sb.append(" token="); sb.append(token); sb.append('}');
7212 stringName = sb.toString();
7213 }
7214 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007215 }
7216 }
Romain Guy06882f82009-06-10 13:36:04 -07007217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 public static WindowManager.LayoutParams findAnimations(
7219 ArrayList<AppWindowToken> order,
7220 ArrayList<AppWindowToken> tokenList1,
7221 ArrayList<AppWindowToken> tokenList2) {
7222 // We need to figure out which animation to use...
7223 WindowManager.LayoutParams animParams = null;
7224 int animSrc = 0;
Romain Guy06882f82009-06-10 13:36:04 -07007225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007226 //Log.i(TAG, "Looking for animations...");
7227 for (int i=order.size()-1; i>=0; i--) {
7228 AppWindowToken wtoken = order.get(i);
7229 //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
7230 if (tokenList1.contains(wtoken) || tokenList2.contains(wtoken)) {
7231 int j = wtoken.windows.size();
7232 while (j > 0) {
7233 j--;
7234 WindowState win = wtoken.windows.get(j);
7235 //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
7236 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
7237 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
7238 //Log.i(TAG, "Found base or application window, done!");
7239 if (wtoken.appFullscreen) {
7240 return win.mAttrs;
7241 }
7242 if (animSrc < 2) {
7243 animParams = win.mAttrs;
7244 animSrc = 2;
7245 }
7246 } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
7247 //Log.i(TAG, "Found normal window, we may use this...");
7248 animParams = win.mAttrs;
7249 animSrc = 1;
7250 }
7251 }
7252 }
7253 }
Romain Guy06882f82009-06-10 13:36:04 -07007254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007255 return animParams;
7256 }
Romain Guy06882f82009-06-10 13:36:04 -07007257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007258 // -------------------------------------------------------------
7259 // DummyAnimation
7260 // -------------------------------------------------------------
7261
7262 // This is an animation that does nothing: it just immediately finishes
7263 // itself every time it is called. It is used as a stub animation in cases
7264 // where we want to synchronize multiple things that may be animating.
7265 static final class DummyAnimation extends Animation {
7266 public boolean getTransformation(long currentTime, Transformation outTransformation) {
7267 return false;
7268 }
7269 }
7270 static final Animation sDummyAnimation = new DummyAnimation();
Romain Guy06882f82009-06-10 13:36:04 -07007271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007272 // -------------------------------------------------------------
7273 // Async Handler
7274 // -------------------------------------------------------------
7275
7276 static final class StartingData {
7277 final String pkg;
7278 final int theme;
7279 final CharSequence nonLocalizedLabel;
7280 final int labelRes;
7281 final int icon;
Romain Guy06882f82009-06-10 13:36:04 -07007282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007283 StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
7284 int _labelRes, int _icon) {
7285 pkg = _pkg;
7286 theme = _theme;
7287 nonLocalizedLabel = _nonLocalizedLabel;
7288 labelRes = _labelRes;
7289 icon = _icon;
7290 }
7291 }
7292
7293 private final class H extends Handler {
7294 public static final int REPORT_FOCUS_CHANGE = 2;
7295 public static final int REPORT_LOSING_FOCUS = 3;
7296 public static final int ANIMATE = 4;
7297 public static final int ADD_STARTING = 5;
7298 public static final int REMOVE_STARTING = 6;
7299 public static final int FINISHED_STARTING = 7;
7300 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007301 public static final int WINDOW_FREEZE_TIMEOUT = 11;
7302 public static final int HOLD_SCREEN_CHANGED = 12;
7303 public static final int APP_TRANSITION_TIMEOUT = 13;
7304 public static final int PERSIST_ANIMATION_SCALE = 14;
7305 public static final int FORCE_GC = 15;
7306 public static final int ENABLE_SCREEN = 16;
7307 public static final int APP_FREEZE_TIMEOUT = 17;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007308 public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
Romain Guy06882f82009-06-10 13:36:04 -07007309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007310 private Session mLastReportedHold;
Romain Guy06882f82009-06-10 13:36:04 -07007311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007312 public H() {
7313 }
Romain Guy06882f82009-06-10 13:36:04 -07007314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007315 @Override
7316 public void handleMessage(Message msg) {
7317 switch (msg.what) {
7318 case REPORT_FOCUS_CHANGE: {
7319 WindowState lastFocus;
7320 WindowState newFocus;
Romain Guy06882f82009-06-10 13:36:04 -07007321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007322 synchronized(mWindowMap) {
7323 lastFocus = mLastFocus;
7324 newFocus = mCurrentFocus;
7325 if (lastFocus == newFocus) {
7326 // Focus is not changing, so nothing to do.
7327 return;
7328 }
7329 mLastFocus = newFocus;
7330 //Log.i(TAG, "Focus moving from " + lastFocus
7331 // + " to " + newFocus);
7332 if (newFocus != null && lastFocus != null
7333 && !newFocus.isDisplayedLw()) {
7334 //Log.i(TAG, "Delaying loss of focus...");
7335 mLosingFocus.add(lastFocus);
7336 lastFocus = null;
7337 }
7338 }
7339
7340 if (lastFocus != newFocus) {
7341 //System.out.println("Changing focus from " + lastFocus
7342 // + " to " + newFocus);
7343 if (newFocus != null) {
7344 try {
7345 //Log.i(TAG, "Gaining focus: " + newFocus);
7346 newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7347 } catch (RemoteException e) {
7348 // Ignore if process has died.
7349 }
7350 }
7351
7352 if (lastFocus != null) {
7353 try {
7354 //Log.i(TAG, "Losing focus: " + lastFocus);
7355 lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7356 } catch (RemoteException e) {
7357 // Ignore if process has died.
7358 }
7359 }
7360 }
7361 } break;
7362
7363 case REPORT_LOSING_FOCUS: {
7364 ArrayList<WindowState> losers;
Romain Guy06882f82009-06-10 13:36:04 -07007365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007366 synchronized(mWindowMap) {
7367 losers = mLosingFocus;
7368 mLosingFocus = new ArrayList<WindowState>();
7369 }
7370
7371 final int N = losers.size();
7372 for (int i=0; i<N; i++) {
7373 try {
7374 //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
7375 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7376 } catch (RemoteException e) {
7377 // Ignore if process has died.
7378 }
7379 }
7380 } break;
7381
7382 case ANIMATE: {
7383 synchronized(mWindowMap) {
7384 mAnimationPending = false;
7385 performLayoutAndPlaceSurfacesLocked();
7386 }
7387 } break;
7388
7389 case ADD_STARTING: {
7390 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7391 final StartingData sd = wtoken.startingData;
7392
7393 if (sd == null) {
7394 // Animation has been canceled... do nothing.
7395 return;
7396 }
Romain Guy06882f82009-06-10 13:36:04 -07007397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007398 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
7399 + wtoken + ": pkg=" + sd.pkg);
Romain Guy06882f82009-06-10 13:36:04 -07007400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007401 View view = null;
7402 try {
7403 view = mPolicy.addStartingWindow(
7404 wtoken.token, sd.pkg,
7405 sd.theme, sd.nonLocalizedLabel, sd.labelRes,
7406 sd.icon);
7407 } catch (Exception e) {
7408 Log.w(TAG, "Exception when adding starting window", e);
7409 }
7410
7411 if (view != null) {
7412 boolean abort = false;
7413
7414 synchronized(mWindowMap) {
7415 if (wtoken.removed || wtoken.startingData == null) {
7416 // If the window was successfully added, then
7417 // we need to remove it.
7418 if (wtoken.startingWindow != null) {
7419 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7420 "Aborted starting " + wtoken
7421 + ": removed=" + wtoken.removed
7422 + " startingData=" + wtoken.startingData);
7423 wtoken.startingWindow = null;
7424 wtoken.startingData = null;
7425 abort = true;
7426 }
7427 } else {
7428 wtoken.startingView = view;
7429 }
7430 if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
7431 "Added starting " + wtoken
7432 + ": startingWindow="
7433 + wtoken.startingWindow + " startingView="
7434 + wtoken.startingView);
7435 }
7436
7437 if (abort) {
7438 try {
7439 mPolicy.removeStartingWindow(wtoken.token, view);
7440 } catch (Exception e) {
7441 Log.w(TAG, "Exception when removing starting window", e);
7442 }
7443 }
7444 }
7445 } break;
7446
7447 case REMOVE_STARTING: {
7448 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7449 IBinder token = null;
7450 View view = null;
7451 synchronized (mWindowMap) {
7452 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
7453 + wtoken + ": startingWindow="
7454 + wtoken.startingWindow + " startingView="
7455 + wtoken.startingView);
7456 if (wtoken.startingWindow != null) {
7457 view = wtoken.startingView;
7458 token = wtoken.token;
7459 wtoken.startingData = null;
7460 wtoken.startingView = null;
7461 wtoken.startingWindow = null;
7462 }
7463 }
7464 if (view != null) {
7465 try {
7466 mPolicy.removeStartingWindow(token, view);
7467 } catch (Exception e) {
7468 Log.w(TAG, "Exception when removing starting window", e);
7469 }
7470 }
7471 } break;
7472
7473 case FINISHED_STARTING: {
7474 IBinder token = null;
7475 View view = null;
7476 while (true) {
7477 synchronized (mWindowMap) {
7478 final int N = mFinishedStarting.size();
7479 if (N <= 0) {
7480 break;
7481 }
7482 AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7483
7484 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7485 "Finished starting " + wtoken
7486 + ": startingWindow=" + wtoken.startingWindow
7487 + " startingView=" + wtoken.startingView);
7488
7489 if (wtoken.startingWindow == null) {
7490 continue;
7491 }
7492
7493 view = wtoken.startingView;
7494 token = wtoken.token;
7495 wtoken.startingData = null;
7496 wtoken.startingView = null;
7497 wtoken.startingWindow = null;
7498 }
7499
7500 try {
7501 mPolicy.removeStartingWindow(token, view);
7502 } catch (Exception e) {
7503 Log.w(TAG, "Exception when removing starting window", e);
7504 }
7505 }
7506 } break;
7507
7508 case REPORT_APPLICATION_TOKEN_WINDOWS: {
7509 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7510
7511 boolean nowVisible = msg.arg1 != 0;
7512 boolean nowGone = msg.arg2 != 0;
7513
7514 try {
7515 if (DEBUG_VISIBILITY) Log.v(
7516 TAG, "Reporting visible in " + wtoken
7517 + " visible=" + nowVisible
7518 + " gone=" + nowGone);
7519 if (nowVisible) {
7520 wtoken.appToken.windowsVisible();
7521 } else {
7522 wtoken.appToken.windowsGone();
7523 }
7524 } catch (RemoteException ex) {
7525 }
7526 } break;
Romain Guy06882f82009-06-10 13:36:04 -07007527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007528 case WINDOW_FREEZE_TIMEOUT: {
7529 synchronized (mWindowMap) {
7530 Log.w(TAG, "Window freeze timeout expired.");
7531 int i = mWindows.size();
7532 while (i > 0) {
7533 i--;
7534 WindowState w = (WindowState)mWindows.get(i);
7535 if (w.mOrientationChanging) {
7536 w.mOrientationChanging = false;
7537 Log.w(TAG, "Force clearing orientation change: " + w);
7538 }
7539 }
7540 performLayoutAndPlaceSurfacesLocked();
7541 }
7542 break;
7543 }
Romain Guy06882f82009-06-10 13:36:04 -07007544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007545 case HOLD_SCREEN_CHANGED: {
7546 Session oldHold;
7547 Session newHold;
7548 synchronized (mWindowMap) {
7549 oldHold = mLastReportedHold;
7550 newHold = (Session)msg.obj;
7551 mLastReportedHold = newHold;
7552 }
Romain Guy06882f82009-06-10 13:36:04 -07007553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007554 if (oldHold != newHold) {
7555 try {
7556 if (oldHold != null) {
7557 mBatteryStats.noteStopWakelock(oldHold.mUid,
7558 "window",
7559 BatteryStats.WAKE_TYPE_WINDOW);
7560 }
7561 if (newHold != null) {
7562 mBatteryStats.noteStartWakelock(newHold.mUid,
7563 "window",
7564 BatteryStats.WAKE_TYPE_WINDOW);
7565 }
7566 } catch (RemoteException e) {
7567 }
7568 }
7569 break;
7570 }
Romain Guy06882f82009-06-10 13:36:04 -07007571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007572 case APP_TRANSITION_TIMEOUT: {
7573 synchronized (mWindowMap) {
7574 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
7575 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7576 "*** APP TRANSITION TIMEOUT");
7577 mAppTransitionReady = true;
7578 mAppTransitionTimeout = true;
7579 performLayoutAndPlaceSurfacesLocked();
7580 }
7581 }
7582 break;
7583 }
Romain Guy06882f82009-06-10 13:36:04 -07007584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007585 case PERSIST_ANIMATION_SCALE: {
7586 Settings.System.putFloat(mContext.getContentResolver(),
7587 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7588 Settings.System.putFloat(mContext.getContentResolver(),
7589 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7590 break;
7591 }
Romain Guy06882f82009-06-10 13:36:04 -07007592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007593 case FORCE_GC: {
7594 synchronized(mWindowMap) {
7595 if (mAnimationPending) {
7596 // If we are animating, don't do the gc now but
7597 // delay a bit so we don't interrupt the animation.
7598 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7599 2000);
7600 return;
7601 }
7602 // If we are currently rotating the display, it will
7603 // schedule a new message when done.
7604 if (mDisplayFrozen) {
7605 return;
7606 }
7607 mFreezeGcPending = 0;
7608 }
7609 Runtime.getRuntime().gc();
7610 break;
7611 }
Romain Guy06882f82009-06-10 13:36:04 -07007612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007613 case ENABLE_SCREEN: {
7614 performEnableScreen();
7615 break;
7616 }
Romain Guy06882f82009-06-10 13:36:04 -07007617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007618 case APP_FREEZE_TIMEOUT: {
7619 synchronized (mWindowMap) {
7620 Log.w(TAG, "App freeze timeout expired.");
7621 int i = mAppTokens.size();
7622 while (i > 0) {
7623 i--;
7624 AppWindowToken tok = mAppTokens.get(i);
7625 if (tok.freezingScreen) {
7626 Log.w(TAG, "Force clearing freeze: " + tok);
7627 unsetAppFreezingScreenLocked(tok, true, true);
7628 }
7629 }
7630 }
7631 break;
7632 }
Romain Guy06882f82009-06-10 13:36:04 -07007633
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007634 case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
Dianne Hackborncfaef692009-06-15 14:24:44 -07007635 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007636 sendNewConfiguration();
7637 }
7638 break;
7639 }
Romain Guy06882f82009-06-10 13:36:04 -07007640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007641 }
7642 }
7643 }
7644
7645 // -------------------------------------------------------------
7646 // IWindowManager API
7647 // -------------------------------------------------------------
7648
7649 public IWindowSession openSession(IInputMethodClient client,
7650 IInputContext inputContext) {
7651 if (client == null) throw new IllegalArgumentException("null client");
7652 if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7653 return new Session(client, inputContext);
7654 }
7655
7656 public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7657 synchronized (mWindowMap) {
7658 // The focus for the client is the window immediately below
7659 // where we would place the input method window.
7660 int idx = findDesiredInputMethodWindowIndexLocked(false);
7661 WindowState imFocus;
7662 if (idx > 0) {
7663 imFocus = (WindowState)mWindows.get(idx-1);
7664 if (imFocus != null) {
7665 if (imFocus.mSession.mClient != null &&
7666 imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7667 return true;
7668 }
7669 }
7670 }
7671 }
7672 return false;
7673 }
Romain Guy06882f82009-06-10 13:36:04 -07007674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007675 // -------------------------------------------------------------
7676 // Internals
7677 // -------------------------------------------------------------
7678
7679 final WindowState windowForClientLocked(Session session, IWindow client) {
7680 return windowForClientLocked(session, client.asBinder());
7681 }
Romain Guy06882f82009-06-10 13:36:04 -07007682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007683 final WindowState windowForClientLocked(Session session, IBinder client) {
7684 WindowState win = mWindowMap.get(client);
7685 if (localLOGV) Log.v(
7686 TAG, "Looking up client " + client + ": " + win);
7687 if (win == null) {
7688 RuntimeException ex = new RuntimeException();
7689 Log.w(TAG, "Requested window " + client + " does not exist", ex);
7690 return null;
7691 }
7692 if (session != null && win.mSession != session) {
7693 RuntimeException ex = new RuntimeException();
7694 Log.w(TAG, "Requested window " + client + " is in session " +
7695 win.mSession + ", not " + session, ex);
7696 return null;
7697 }
7698
7699 return win;
7700 }
7701
7702 private final void assignLayersLocked() {
7703 int N = mWindows.size();
7704 int curBaseLayer = 0;
7705 int curLayer = 0;
7706 int i;
Romain Guy06882f82009-06-10 13:36:04 -07007707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007708 for (i=0; i<N; i++) {
7709 WindowState w = (WindowState)mWindows.get(i);
7710 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
7711 curLayer += WINDOW_LAYER_MULTIPLIER;
7712 w.mLayer = curLayer;
7713 } else {
7714 curBaseLayer = curLayer = w.mBaseLayer;
7715 w.mLayer = curLayer;
7716 }
7717 if (w.mTargetAppToken != null) {
7718 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
7719 } else if (w.mAppToken != null) {
7720 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
7721 } else {
7722 w.mAnimLayer = w.mLayer;
7723 }
7724 if (w.mIsImWindow) {
7725 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
7726 }
7727 if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
7728 + w.mAnimLayer);
7729 //System.out.println(
7730 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7731 }
7732 }
7733
7734 private boolean mInLayout = false;
7735 private final void performLayoutAndPlaceSurfacesLocked() {
7736 if (mInLayout) {
Dave Bortcfe65242009-04-09 14:51:04 -07007737 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007738 throw new RuntimeException("Recursive call!");
7739 }
7740 Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7741 return;
7742 }
7743
7744 boolean recoveringMemory = false;
7745 if (mForceRemoves != null) {
7746 recoveringMemory = true;
7747 // Wait a little it for things to settle down, and off we go.
7748 for (int i=0; i<mForceRemoves.size(); i++) {
7749 WindowState ws = mForceRemoves.get(i);
7750 Log.i(TAG, "Force removing: " + ws);
7751 removeWindowInnerLocked(ws.mSession, ws);
7752 }
7753 mForceRemoves = null;
7754 Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
7755 Object tmp = new Object();
7756 synchronized (tmp) {
7757 try {
7758 tmp.wait(250);
7759 } catch (InterruptedException e) {
7760 }
7761 }
7762 }
Romain Guy06882f82009-06-10 13:36:04 -07007763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007764 mInLayout = true;
7765 try {
7766 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
Romain Guy06882f82009-06-10 13:36:04 -07007767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007768 int i = mPendingRemove.size()-1;
7769 if (i >= 0) {
7770 while (i >= 0) {
7771 WindowState w = mPendingRemove.get(i);
7772 removeWindowInnerLocked(w.mSession, w);
7773 i--;
7774 }
7775 mPendingRemove.clear();
7776
7777 mInLayout = false;
7778 assignLayersLocked();
7779 mLayoutNeeded = true;
7780 performLayoutAndPlaceSurfacesLocked();
7781
7782 } else {
7783 mInLayout = false;
7784 if (mLayoutNeeded) {
7785 requestAnimationLocked(0);
7786 }
7787 }
7788 } catch (RuntimeException e) {
7789 mInLayout = false;
7790 Log.e(TAG, "Unhandled exception while layout out windows", e);
7791 }
7792 }
7793
7794 private final void performLayoutLockedInner() {
7795 final int dw = mDisplay.getWidth();
7796 final int dh = mDisplay.getHeight();
7797
7798 final int N = mWindows.size();
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007799 int repeats = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007800 int i;
7801
7802 // FIRST LOOP: Perform a layout, if needed.
Romain Guy06882f82009-06-10 13:36:04 -07007803
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007804 while (mLayoutNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007805 mPolicy.beginLayoutLw(dw, dh);
7806
7807 // First perform layout of any root windows (not attached
7808 // to another window).
7809 int topAttached = -1;
7810 for (i = N-1; i >= 0; i--) {
7811 WindowState win = (WindowState) mWindows.get(i);
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007812
7813 // Don't do layout of a window if it is not visible, or
7814 // soon won't be visible, to avoid wasting time and funky
7815 // changes while a window is animating away.
7816 final AppWindowToken atoken = win.mAppToken;
7817 final boolean gone = win.mViewVisibility == View.GONE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007818 || !win.mRelayoutCalled
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007819 || win.mRootToken.hidden
7820 || (atoken != null && atoken.hiddenRequested)
7821 || !win.mPolicyVisibility
7822 || win.mAttachedHidden
7823 || win.mExiting || win.mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007824
7825 // If this view is GONE, then skip it -- keep the current
7826 // frame, and let the caller know so they can ignore it
7827 // if they want. (We do the normal layout for INVISIBLE
7828 // windows, since that means "perform layout as normal,
7829 // just don't display").
7830 if (!gone || !win.mHaveFrame) {
7831 if (!win.mLayoutAttached) {
7832 mPolicy.layoutWindowLw(win, win.mAttrs, null);
7833 } else {
7834 if (topAttached < 0) topAttached = i;
7835 }
7836 }
7837 }
Romain Guy06882f82009-06-10 13:36:04 -07007838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007839 // Now perform layout of attached windows, which usually
7840 // depend on the position of the window they are attached to.
7841 // XXX does not deal with windows that are attached to windows
7842 // that are themselves attached.
7843 for (i = topAttached; i >= 0; i--) {
7844 WindowState win = (WindowState) mWindows.get(i);
7845
7846 // If this view is GONE, then skip it -- keep the current
7847 // frame, and let the caller know so they can ignore it
7848 // if they want. (We do the normal layout for INVISIBLE
7849 // windows, since that means "perform layout as normal,
7850 // just don't display").
7851 if (win.mLayoutAttached) {
7852 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7853 || !win.mHaveFrame) {
7854 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7855 }
7856 }
7857 }
7858
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007859 if (!mPolicy.finishLayoutLw()) {
7860 mLayoutNeeded = false;
7861 } else if (repeats > 2) {
7862 Log.w(TAG, "Layout repeat aborted after too many iterations");
7863 mLayoutNeeded = false;
7864 } else {
7865 repeats++;
7866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007867 }
7868 }
Romain Guy06882f82009-06-10 13:36:04 -07007869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007870 private final void performLayoutAndPlaceSurfacesLockedInner(
7871 boolean recoveringMemory) {
7872 final long currentTime = SystemClock.uptimeMillis();
7873 final int dw = mDisplay.getWidth();
7874 final int dh = mDisplay.getHeight();
7875
7876 final int N = mWindows.size();
7877 int i;
7878
7879 // FIRST LOOP: Perform a layout, if needed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007880 performLayoutLockedInner();
Romain Guy06882f82009-06-10 13:36:04 -07007881
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007882 if (mFxSession == null) {
7883 mFxSession = new SurfaceSession();
7884 }
Romain Guy06882f82009-06-10 13:36:04 -07007885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007886 if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
7887
7888 // Initialize state of exiting tokens.
7889 for (i=mExitingTokens.size()-1; i>=0; i--) {
7890 mExitingTokens.get(i).hasVisible = false;
7891 }
7892
7893 // Initialize state of exiting applications.
7894 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7895 mExitingAppTokens.get(i).hasVisible = false;
7896 }
7897
7898 // SECOND LOOP: Execute animations and update visibility of windows.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007899 boolean orientationChangeComplete = true;
7900 Session holdScreen = null;
7901 float screenBrightness = -1;
7902 boolean focusDisplayed = false;
7903 boolean animating = false;
7904
7905 Surface.openTransaction();
7906 try {
7907 boolean restart;
7908
7909 do {
7910 final int transactionSequence = ++mTransactionSequence;
7911
7912 // Update animations of all applications, including those
7913 // associated with exiting/removed apps
7914 boolean tokensAnimating = false;
7915 final int NAT = mAppTokens.size();
7916 for (i=0; i<NAT; i++) {
7917 if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7918 tokensAnimating = true;
7919 }
7920 }
7921 final int NEAT = mExitingAppTokens.size();
7922 for (i=0; i<NEAT; i++) {
7923 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7924 tokensAnimating = true;
7925 }
7926 }
7927
7928 animating = tokensAnimating;
7929 restart = false;
7930
7931 boolean tokenMayBeDrawn = false;
7932
7933 mPolicy.beginAnimationLw(dw, dh);
7934
7935 for (i=N-1; i>=0; i--) {
7936 WindowState w = (WindowState)mWindows.get(i);
7937
7938 final WindowManager.LayoutParams attrs = w.mAttrs;
7939
7940 if (w.mSurface != null) {
7941 // Execute animation.
7942 w.commitFinishDrawingLocked(currentTime);
7943 if (w.stepAnimationLocked(currentTime, dw, dh)) {
7944 animating = true;
7945 //w.dump(" ");
7946 }
7947
7948 mPolicy.animatingWindowLw(w, attrs);
7949 }
7950
7951 final AppWindowToken atoken = w.mAppToken;
7952 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7953 if (atoken.lastTransactionSequence != transactionSequence) {
7954 atoken.lastTransactionSequence = transactionSequence;
7955 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7956 atoken.startingDisplayed = false;
7957 }
7958 if ((w.isOnScreen() || w.mAttrs.type
7959 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7960 && !w.mExiting && !w.mDestroying) {
7961 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7962 Log.v(TAG, "Eval win " + w + ": isDisplayed="
7963 + w.isDisplayedLw()
7964 + ", isAnimating=" + w.isAnimating());
7965 if (!w.isDisplayedLw()) {
7966 Log.v(TAG, "Not displayed: s=" + w.mSurface
7967 + " pv=" + w.mPolicyVisibility
7968 + " dp=" + w.mDrawPending
7969 + " cdp=" + w.mCommitDrawPending
7970 + " ah=" + w.mAttachedHidden
7971 + " th=" + atoken.hiddenRequested
7972 + " a=" + w.mAnimating);
7973 }
7974 }
7975 if (w != atoken.startingWindow) {
7976 if (!atoken.freezingScreen || !w.mAppFreezing) {
7977 atoken.numInterestingWindows++;
7978 if (w.isDisplayedLw()) {
7979 atoken.numDrawnWindows++;
7980 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
7981 "tokenMayBeDrawn: " + atoken
7982 + " freezingScreen=" + atoken.freezingScreen
7983 + " mAppFreezing=" + w.mAppFreezing);
7984 tokenMayBeDrawn = true;
7985 }
7986 }
7987 } else if (w.isDisplayedLw()) {
7988 atoken.startingDisplayed = true;
7989 }
7990 }
7991 } else if (w.mReadyToShow) {
7992 w.performShowLocked();
7993 }
7994 }
7995
7996 if (mPolicy.finishAnimationLw()) {
7997 restart = true;
7998 }
7999
8000 if (tokenMayBeDrawn) {
8001 // See if any windows have been drawn, so they (and others
8002 // associated with them) can now be shown.
8003 final int NT = mTokenList.size();
8004 for (i=0; i<NT; i++) {
8005 AppWindowToken wtoken = mTokenList.get(i).appWindowToken;
8006 if (wtoken == null) {
8007 continue;
8008 }
8009 if (wtoken.freezingScreen) {
8010 int numInteresting = wtoken.numInterestingWindows;
8011 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8012 if (DEBUG_VISIBILITY) Log.v(TAG,
8013 "allDrawn: " + wtoken
8014 + " interesting=" + numInteresting
8015 + " drawn=" + wtoken.numDrawnWindows);
8016 wtoken.showAllWindowsLocked();
8017 unsetAppFreezingScreenLocked(wtoken, false, true);
8018 orientationChangeComplete = true;
8019 }
8020 } else if (!wtoken.allDrawn) {
8021 int numInteresting = wtoken.numInterestingWindows;
8022 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8023 if (DEBUG_VISIBILITY) Log.v(TAG,
8024 "allDrawn: " + wtoken
8025 + " interesting=" + numInteresting
8026 + " drawn=" + wtoken.numDrawnWindows);
8027 wtoken.allDrawn = true;
8028 restart = true;
8029
8030 // We can now show all of the drawn windows!
8031 if (!mOpeningApps.contains(wtoken)) {
8032 wtoken.showAllWindowsLocked();
8033 }
8034 }
8035 }
8036 }
8037 }
8038
8039 // If we are ready to perform an app transition, check through
8040 // all of the app tokens to be shown and see if they are ready
8041 // to go.
8042 if (mAppTransitionReady) {
8043 int NN = mOpeningApps.size();
8044 boolean goodToGo = true;
8045 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8046 "Checking " + NN + " opening apps (frozen="
8047 + mDisplayFrozen + " timeout="
8048 + mAppTransitionTimeout + ")...");
8049 if (!mDisplayFrozen && !mAppTransitionTimeout) {
8050 // If the display isn't frozen, wait to do anything until
8051 // all of the apps are ready. Otherwise just go because
8052 // we'll unfreeze the display when everyone is ready.
8053 for (i=0; i<NN && goodToGo; i++) {
8054 AppWindowToken wtoken = mOpeningApps.get(i);
8055 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8056 "Check opening app" + wtoken + ": allDrawn="
8057 + wtoken.allDrawn + " startingDisplayed="
8058 + wtoken.startingDisplayed);
8059 if (!wtoken.allDrawn && !wtoken.startingDisplayed
8060 && !wtoken.startingMoved) {
8061 goodToGo = false;
8062 }
8063 }
8064 }
8065 if (goodToGo) {
8066 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
8067 int transit = mNextAppTransition;
8068 if (mSkipAppTransitionAnimation) {
8069 transit = WindowManagerPolicy.TRANSIT_NONE;
8070 }
8071 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8072 mAppTransitionReady = false;
8073 mAppTransitionTimeout = false;
8074 mStartingIconInTransition = false;
8075 mSkipAppTransitionAnimation = false;
8076
8077 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8078
8079 // We need to figure out which animation to use...
8080 WindowManager.LayoutParams lp = findAnimations(mAppTokens,
8081 mOpeningApps, mClosingApps);
8082
8083 NN = mOpeningApps.size();
8084 for (i=0; i<NN; i++) {
8085 AppWindowToken wtoken = mOpeningApps.get(i);
8086 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8087 "Now opening app" + wtoken);
8088 wtoken.reportedVisible = false;
8089 wtoken.inPendingTransaction = false;
8090 setTokenVisibilityLocked(wtoken, lp, true, transit, false);
8091 wtoken.updateReportedVisibilityLocked();
8092 wtoken.showAllWindowsLocked();
8093 }
8094 NN = mClosingApps.size();
8095 for (i=0; i<NN; i++) {
8096 AppWindowToken wtoken = mClosingApps.get(i);
8097 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8098 "Now closing app" + wtoken);
8099 wtoken.inPendingTransaction = false;
8100 setTokenVisibilityLocked(wtoken, lp, false, transit, false);
8101 wtoken.updateReportedVisibilityLocked();
8102 // Force the allDrawn flag, because we want to start
8103 // this guy's animations regardless of whether it's
8104 // gotten drawn.
8105 wtoken.allDrawn = true;
8106 }
8107
8108 mOpeningApps.clear();
8109 mClosingApps.clear();
8110
8111 // This has changed the visibility of windows, so perform
8112 // a new layout to get them all up-to-date.
8113 mLayoutNeeded = true;
8114 moveInputMethodWindowsIfNeededLocked(true);
8115 performLayoutLockedInner();
8116 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
8117
8118 restart = true;
8119 }
8120 }
8121 } while (restart);
8122
8123 // THIRD LOOP: Update the surfaces of all windows.
8124
8125 final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8126
8127 boolean obscured = false;
8128 boolean blurring = false;
8129 boolean dimming = false;
8130 boolean covered = false;
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008131 boolean syswin = false;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008132 boolean backgroundFillerShown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008133
8134 for (i=N-1; i>=0; i--) {
8135 WindowState w = (WindowState)mWindows.get(i);
8136
8137 boolean displayed = false;
8138 final WindowManager.LayoutParams attrs = w.mAttrs;
8139 final int attrFlags = attrs.flags;
8140
8141 if (w.mSurface != null) {
8142 w.computeShownFrameLocked();
8143 if (localLOGV) Log.v(
8144 TAG, "Placing surface #" + i + " " + w.mSurface
8145 + ": new=" + w.mShownFrame + ", old="
8146 + w.mLastShownFrame);
8147
8148 boolean resize;
8149 int width, height;
8150 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8151 resize = w.mLastRequestedWidth != w.mRequestedWidth ||
8152 w.mLastRequestedHeight != w.mRequestedHeight;
8153 // for a scaled surface, we just want to use
8154 // the requested size.
8155 width = w.mRequestedWidth;
8156 height = w.mRequestedHeight;
8157 w.mLastRequestedWidth = width;
8158 w.mLastRequestedHeight = height;
8159 w.mLastShownFrame.set(w.mShownFrame);
8160 try {
8161 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8162 } catch (RuntimeException e) {
8163 Log.w(TAG, "Error positioning surface in " + w, e);
8164 if (!recoveringMemory) {
8165 reclaimSomeSurfaceMemoryLocked(w, "position");
8166 }
8167 }
8168 } else {
8169 resize = !w.mLastShownFrame.equals(w.mShownFrame);
8170 width = w.mShownFrame.width();
8171 height = w.mShownFrame.height();
8172 w.mLastShownFrame.set(w.mShownFrame);
8173 if (resize) {
8174 if (SHOW_TRANSACTIONS) Log.i(
8175 TAG, " SURFACE " + w.mSurface + ": ("
8176 + w.mShownFrame.left + ","
8177 + w.mShownFrame.top + ") ("
8178 + w.mShownFrame.width() + "x"
8179 + w.mShownFrame.height() + ")");
8180 }
8181 }
8182
8183 if (resize) {
8184 if (width < 1) width = 1;
8185 if (height < 1) height = 1;
8186 if (w.mSurface != null) {
8187 try {
8188 w.mSurface.setSize(width, height);
8189 w.mSurface.setPosition(w.mShownFrame.left,
8190 w.mShownFrame.top);
8191 } catch (RuntimeException e) {
8192 // If something goes wrong with the surface (such
8193 // as running out of memory), don't take down the
8194 // entire system.
8195 Log.e(TAG, "Failure updating surface of " + w
8196 + "size=(" + width + "x" + height
8197 + "), pos=(" + w.mShownFrame.left
8198 + "," + w.mShownFrame.top + ")", e);
8199 if (!recoveringMemory) {
8200 reclaimSomeSurfaceMemoryLocked(w, "size");
8201 }
8202 }
8203 }
8204 }
8205 if (!w.mAppFreezing) {
8206 w.mContentInsetsChanged =
8207 !w.mLastContentInsets.equals(w.mContentInsets);
8208 w.mVisibleInsetsChanged =
8209 !w.mLastVisibleInsets.equals(w.mVisibleInsets);
Romain Guy06882f82009-06-10 13:36:04 -07008210 if (!w.mLastFrame.equals(w.mFrame)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008211 || w.mContentInsetsChanged
8212 || w.mVisibleInsetsChanged) {
8213 w.mLastFrame.set(w.mFrame);
8214 w.mLastContentInsets.set(w.mContentInsets);
8215 w.mLastVisibleInsets.set(w.mVisibleInsets);
8216 // If the orientation is changing, then we need to
8217 // hold off on unfreezing the display until this
8218 // window has been redrawn; to do that, we need
8219 // to go through the process of getting informed
8220 // by the application when it has finished drawing.
8221 if (w.mOrientationChanging) {
8222 if (DEBUG_ORIENTATION) Log.v(TAG,
8223 "Orientation start waiting for draw in "
8224 + w + ", surface " + w.mSurface);
8225 w.mDrawPending = true;
8226 w.mCommitDrawPending = false;
8227 w.mReadyToShow = false;
8228 if (w.mAppToken != null) {
8229 w.mAppToken.allDrawn = false;
8230 }
8231 }
Romain Guy06882f82009-06-10 13:36:04 -07008232 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008233 "Resizing window " + w + " to " + w.mFrame);
8234 mResizingWindows.add(w);
8235 } else if (w.mOrientationChanging) {
8236 if (!w.mDrawPending && !w.mCommitDrawPending) {
8237 if (DEBUG_ORIENTATION) Log.v(TAG,
8238 "Orientation not waiting for draw in "
8239 + w + ", surface " + w.mSurface);
8240 w.mOrientationChanging = false;
8241 }
8242 }
8243 }
8244
8245 if (w.mAttachedHidden) {
8246 if (!w.mLastHidden) {
8247 //dump();
8248 w.mLastHidden = true;
8249 if (SHOW_TRANSACTIONS) Log.i(
8250 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)");
8251 if (w.mSurface != null) {
8252 try {
8253 w.mSurface.hide();
8254 } catch (RuntimeException e) {
8255 Log.w(TAG, "Exception hiding surface in " + w);
8256 }
8257 }
8258 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8259 }
8260 // If we are waiting for this window to handle an
8261 // orientation change, well, it is hidden, so
8262 // doesn't really matter. Note that this does
8263 // introduce a potential glitch if the window
8264 // becomes unhidden before it has drawn for the
8265 // new orientation.
8266 if (w.mOrientationChanging) {
8267 w.mOrientationChanging = false;
8268 if (DEBUG_ORIENTATION) Log.v(TAG,
8269 "Orientation change skips hidden " + w);
8270 }
8271 } else if (!w.isReadyForDisplay()) {
8272 if (!w.mLastHidden) {
8273 //dump();
8274 w.mLastHidden = true;
8275 if (SHOW_TRANSACTIONS) Log.i(
8276 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)");
8277 if (w.mSurface != null) {
8278 try {
8279 w.mSurface.hide();
8280 } catch (RuntimeException e) {
8281 Log.w(TAG, "Exception exception hiding surface in " + w);
8282 }
8283 }
8284 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8285 }
8286 // If we are waiting for this window to handle an
8287 // orientation change, well, it is hidden, so
8288 // doesn't really matter. Note that this does
8289 // introduce a potential glitch if the window
8290 // becomes unhidden before it has drawn for the
8291 // new orientation.
8292 if (w.mOrientationChanging) {
8293 w.mOrientationChanging = false;
8294 if (DEBUG_ORIENTATION) Log.v(TAG,
8295 "Orientation change skips hidden " + w);
8296 }
8297 } else if (w.mLastLayer != w.mAnimLayer
8298 || w.mLastAlpha != w.mShownAlpha
8299 || w.mLastDsDx != w.mDsDx
8300 || w.mLastDtDx != w.mDtDx
8301 || w.mLastDsDy != w.mDsDy
8302 || w.mLastDtDy != w.mDtDy
8303 || w.mLastHScale != w.mHScale
8304 || w.mLastVScale != w.mVScale
8305 || w.mLastHidden) {
8306 displayed = true;
8307 w.mLastAlpha = w.mShownAlpha;
8308 w.mLastLayer = w.mAnimLayer;
8309 w.mLastDsDx = w.mDsDx;
8310 w.mLastDtDx = w.mDtDx;
8311 w.mLastDsDy = w.mDsDy;
8312 w.mLastDtDy = w.mDtDy;
8313 w.mLastHScale = w.mHScale;
8314 w.mLastVScale = w.mVScale;
8315 if (SHOW_TRANSACTIONS) Log.i(
8316 TAG, " SURFACE " + w.mSurface + ": alpha="
8317 + w.mShownAlpha + " layer=" + w.mAnimLayer);
8318 if (w.mSurface != null) {
8319 try {
8320 w.mSurface.setAlpha(w.mShownAlpha);
8321 w.mSurface.setLayer(w.mAnimLayer);
8322 w.mSurface.setMatrix(
8323 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8324 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8325 } catch (RuntimeException e) {
8326 Log.w(TAG, "Error updating surface in " + w, e);
8327 if (!recoveringMemory) {
8328 reclaimSomeSurfaceMemoryLocked(w, "update");
8329 }
8330 }
8331 }
8332
8333 if (w.mLastHidden && !w.mDrawPending
8334 && !w.mCommitDrawPending
8335 && !w.mReadyToShow) {
8336 if (SHOW_TRANSACTIONS) Log.i(
8337 TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)");
8338 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w
8339 + " during relayout");
8340 if (showSurfaceRobustlyLocked(w)) {
8341 w.mHasDrawn = true;
8342 w.mLastHidden = false;
8343 } else {
8344 w.mOrientationChanging = false;
8345 }
8346 }
8347 if (w.mSurface != null) {
8348 w.mToken.hasVisible = true;
8349 }
8350 } else {
8351 displayed = true;
8352 }
8353
8354 if (displayed) {
8355 if (!covered) {
8356 if (attrs.width == LayoutParams.FILL_PARENT
8357 && attrs.height == LayoutParams.FILL_PARENT) {
8358 covered = true;
8359 }
8360 }
8361 if (w.mOrientationChanging) {
8362 if (w.mDrawPending || w.mCommitDrawPending) {
8363 orientationChangeComplete = false;
8364 if (DEBUG_ORIENTATION) Log.v(TAG,
8365 "Orientation continue waiting for draw in " + w);
8366 } else {
8367 w.mOrientationChanging = false;
8368 if (DEBUG_ORIENTATION) Log.v(TAG,
8369 "Orientation change complete in " + w);
8370 }
8371 }
8372 w.mToken.hasVisible = true;
8373 }
8374 } else if (w.mOrientationChanging) {
8375 if (DEBUG_ORIENTATION) Log.v(TAG,
8376 "Orientation change skips hidden " + w);
8377 w.mOrientationChanging = false;
8378 }
8379
8380 final boolean canBeSeen = w.isDisplayedLw();
8381
8382 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8383 focusDisplayed = true;
8384 }
8385
8386 // Update effect.
8387 if (!obscured) {
8388 if (w.mSurface != null) {
8389 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8390 holdScreen = w.mSession;
8391 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008392 if (!syswin && w.mAttrs.screenBrightness >= 0
8393 && screenBrightness < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008394 screenBrightness = w.mAttrs.screenBrightness;
8395 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008396 if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8397 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8398 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
8399 syswin = true;
8400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008401 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008402
8403 boolean opaqueDrawn = w.isOpaqueDrawn();
8404 if (opaqueDrawn && w.isFullscreen(dw, dh)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008405 // This window completely covers everything behind it,
8406 // so we want to leave all of them as unblurred (for
8407 // performance reasons).
8408 obscured = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008409 } else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
8410 if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
8411 // This window is in compatibility mode, and needs background filler.
8412 obscured = true;
8413 if (mBackgroundFillerSurface == null) {
8414 try {
8415 mBackgroundFillerSurface = new Surface(mFxSession, 0,
8416 0, dw, dh,
8417 PixelFormat.OPAQUE,
8418 Surface.FX_SURFACE_NORMAL);
8419 } catch (Exception e) {
8420 Log.e(TAG, "Exception creating filler surface", e);
8421 }
8422 }
8423 try {
8424 mBackgroundFillerSurface.setPosition(0, 0);
8425 mBackgroundFillerSurface.setSize(dw, dh);
8426 // Using the same layer as Dim because they will never be shown at the
8427 // same time.
8428 mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
8429 mBackgroundFillerSurface.show();
8430 } catch (RuntimeException e) {
8431 Log.e(TAG, "Exception showing filler surface");
8432 }
8433 backgroundFillerShown = true;
8434 mBackgroundFillerShown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008435 } else if (canBeSeen && !obscured &&
8436 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8437 if (localLOGV) Log.v(TAG, "Win " + w
8438 + ": blurring=" + blurring
8439 + " obscured=" + obscured
8440 + " displayed=" + displayed);
8441 if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8442 if (!dimming) {
8443 //Log.i(TAG, "DIM BEHIND: " + w);
8444 dimming = true;
8445 mDimShown = true;
8446 if (mDimSurface == null) {
8447 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8448 + mDimSurface + ": CREATE");
8449 try {
Romain Guy06882f82009-06-10 13:36:04 -07008450 mDimSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008451 -1, 16, 16,
8452 PixelFormat.OPAQUE,
8453 Surface.FX_SURFACE_DIM);
8454 } catch (Exception e) {
8455 Log.e(TAG, "Exception creating Dim surface", e);
8456 }
8457 }
8458 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8459 + mDimSurface + ": SHOW pos=(0,0) (" +
8460 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8461 if (mDimSurface != null) {
8462 try {
8463 mDimSurface.setPosition(0, 0);
8464 mDimSurface.setSize(dw, dh);
8465 mDimSurface.show();
8466 } catch (RuntimeException e) {
8467 Log.w(TAG, "Failure showing dim surface", e);
8468 }
8469 }
8470 }
8471 mDimSurface.setLayer(w.mAnimLayer-1);
8472 final float target = w.mExiting ? 0 : attrs.dimAmount;
8473 if (mDimTargetAlpha != target) {
8474 // If the desired dim level has changed, then
8475 // start an animation to it.
8476 mLastDimAnimTime = currentTime;
8477 long duration = (w.mAnimating && w.mAnimation != null)
8478 ? w.mAnimation.computeDurationHint()
8479 : DEFAULT_DIM_DURATION;
8480 if (target > mDimTargetAlpha) {
8481 // This is happening behind the activity UI,
8482 // so we can make it run a little longer to
8483 // give a stronger impression without disrupting
8484 // the user.
8485 duration *= DIM_DURATION_MULTIPLIER;
8486 }
8487 if (duration < 1) {
8488 // Don't divide by zero
8489 duration = 1;
8490 }
8491 mDimTargetAlpha = target;
8492 mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha)
8493 / duration;
8494 }
8495 }
8496 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8497 if (!blurring) {
8498 //Log.i(TAG, "BLUR BEHIND: " + w);
8499 blurring = true;
8500 mBlurShown = true;
8501 if (mBlurSurface == null) {
8502 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8503 + mBlurSurface + ": CREATE");
8504 try {
Romain Guy06882f82009-06-10 13:36:04 -07008505 mBlurSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008506 -1, 16, 16,
8507 PixelFormat.OPAQUE,
8508 Surface.FX_SURFACE_BLUR);
8509 } catch (Exception e) {
8510 Log.e(TAG, "Exception creating Blur surface", e);
8511 }
8512 }
8513 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8514 + mBlurSurface + ": SHOW pos=(0,0) (" +
8515 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8516 if (mBlurSurface != null) {
8517 mBlurSurface.setPosition(0, 0);
8518 mBlurSurface.setSize(dw, dh);
8519 try {
8520 mBlurSurface.show();
8521 } catch (RuntimeException e) {
8522 Log.w(TAG, "Failure showing blur surface", e);
8523 }
8524 }
8525 }
8526 mBlurSurface.setLayer(w.mAnimLayer-2);
8527 }
8528 }
8529 }
8530 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008531
8532 if (backgroundFillerShown == false && mBackgroundFillerShown) {
8533 mBackgroundFillerShown = false;
8534 if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
8535 try {
8536 mBackgroundFillerSurface.hide();
8537 } catch (RuntimeException e) {
8538 Log.e(TAG, "Exception hiding filler surface", e);
8539 }
8540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008541
8542 if (!dimming && mDimShown) {
8543 // Time to hide the dim surface... start fading.
8544 if (mDimTargetAlpha != 0) {
8545 mLastDimAnimTime = currentTime;
8546 mDimTargetAlpha = 0;
8547 mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
8548 }
8549 }
8550
8551 if (mDimShown && mLastDimAnimTime != 0) {
8552 mDimCurrentAlpha += mDimDeltaPerMs
8553 * (currentTime-mLastDimAnimTime);
8554 boolean more = true;
8555 if (mDisplayFrozen) {
8556 // If the display is frozen, there is no reason to animate.
8557 more = false;
8558 } else if (mDimDeltaPerMs > 0) {
8559 if (mDimCurrentAlpha > mDimTargetAlpha) {
8560 more = false;
8561 }
8562 } else if (mDimDeltaPerMs < 0) {
8563 if (mDimCurrentAlpha < mDimTargetAlpha) {
8564 more = false;
8565 }
8566 } else {
8567 more = false;
8568 }
Romain Guy06882f82009-06-10 13:36:04 -07008569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008570 // Do we need to continue animating?
8571 if (more) {
8572 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8573 + mDimSurface + ": alpha=" + mDimCurrentAlpha);
8574 mLastDimAnimTime = currentTime;
8575 mDimSurface.setAlpha(mDimCurrentAlpha);
8576 animating = true;
8577 } else {
8578 mDimCurrentAlpha = mDimTargetAlpha;
8579 mLastDimAnimTime = 0;
8580 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8581 + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
8582 mDimSurface.setAlpha(mDimCurrentAlpha);
8583 if (!dimming) {
8584 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
8585 + ": HIDE");
8586 try {
8587 mDimSurface.hide();
8588 } catch (RuntimeException e) {
8589 Log.w(TAG, "Illegal argument exception hiding dim surface");
8590 }
8591 mDimShown = false;
8592 }
8593 }
8594 }
Romain Guy06882f82009-06-10 13:36:04 -07008595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008596 if (!blurring && mBlurShown) {
8597 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
8598 + ": HIDE");
8599 try {
8600 mBlurSurface.hide();
8601 } catch (IllegalArgumentException e) {
8602 Log.w(TAG, "Illegal argument exception hiding blur surface");
8603 }
8604 mBlurShown = false;
8605 }
8606
8607 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
8608 } catch (RuntimeException e) {
8609 Log.e(TAG, "Unhandled exception in Window Manager", e);
8610 }
8611
8612 Surface.closeTransaction();
Romain Guy06882f82009-06-10 13:36:04 -07008613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008614 if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
8615 "With display frozen, orientationChangeComplete="
8616 + orientationChangeComplete);
8617 if (orientationChangeComplete) {
8618 if (mWindowsFreezingScreen) {
8619 mWindowsFreezingScreen = false;
8620 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8621 }
8622 if (mAppsFreezingScreen == 0) {
8623 stopFreezingDisplayLocked();
8624 }
8625 }
Romain Guy06882f82009-06-10 13:36:04 -07008626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008627 i = mResizingWindows.size();
8628 if (i > 0) {
8629 do {
8630 i--;
8631 WindowState win = mResizingWindows.get(i);
8632 try {
8633 win.mClient.resized(win.mFrame.width(),
8634 win.mFrame.height(), win.mLastContentInsets,
8635 win.mLastVisibleInsets, win.mDrawPending);
8636 win.mContentInsetsChanged = false;
8637 win.mVisibleInsetsChanged = false;
8638 } catch (RemoteException e) {
8639 win.mOrientationChanging = false;
8640 }
8641 } while (i > 0);
8642 mResizingWindows.clear();
8643 }
Romain Guy06882f82009-06-10 13:36:04 -07008644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008645 // Destroy the surface of any windows that are no longer visible.
8646 i = mDestroySurface.size();
8647 if (i > 0) {
8648 do {
8649 i--;
8650 WindowState win = mDestroySurface.get(i);
8651 win.mDestroying = false;
8652 if (mInputMethodWindow == win) {
8653 mInputMethodWindow = null;
8654 }
8655 win.destroySurfaceLocked();
8656 } while (i > 0);
8657 mDestroySurface.clear();
8658 }
8659
8660 // Time to remove any exiting tokens?
8661 for (i=mExitingTokens.size()-1; i>=0; i--) {
8662 WindowToken token = mExitingTokens.get(i);
8663 if (!token.hasVisible) {
8664 mExitingTokens.remove(i);
8665 }
8666 }
8667
8668 // Time to remove any exiting applications?
8669 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8670 AppWindowToken token = mExitingAppTokens.get(i);
8671 if (!token.hasVisible && !mClosingApps.contains(token)) {
8672 mAppTokens.remove(token);
8673 mExitingAppTokens.remove(i);
8674 }
8675 }
8676
8677 if (focusDisplayed) {
8678 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8679 }
8680 if (animating) {
8681 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8682 }
8683 mQueue.setHoldScreenLocked(holdScreen != null);
8684 if (screenBrightness < 0 || screenBrightness > 1.0f) {
8685 mPowerManager.setScreenBrightnessOverride(-1);
8686 } else {
8687 mPowerManager.setScreenBrightnessOverride((int)
8688 (screenBrightness * Power.BRIGHTNESS_ON));
8689 }
8690 if (holdScreen != mHoldingScreenOn) {
8691 mHoldingScreenOn = holdScreen;
8692 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8693 mH.sendMessage(m);
8694 }
8695 }
8696
8697 void requestAnimationLocked(long delay) {
8698 if (!mAnimationPending) {
8699 mAnimationPending = true;
8700 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8701 }
8702 }
Romain Guy06882f82009-06-10 13:36:04 -07008703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008704 /**
8705 * Have the surface flinger show a surface, robustly dealing with
8706 * error conditions. In particular, if there is not enough memory
8707 * to show the surface, then we will try to get rid of other surfaces
8708 * in order to succeed.
Romain Guy06882f82009-06-10 13:36:04 -07008709 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008710 * @return Returns true if the surface was successfully shown.
8711 */
8712 boolean showSurfaceRobustlyLocked(WindowState win) {
8713 try {
8714 if (win.mSurface != null) {
8715 win.mSurface.show();
8716 }
8717 return true;
8718 } catch (RuntimeException e) {
8719 Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
8720 }
Romain Guy06882f82009-06-10 13:36:04 -07008721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008722 reclaimSomeSurfaceMemoryLocked(win, "show");
Romain Guy06882f82009-06-10 13:36:04 -07008723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008724 return false;
8725 }
Romain Guy06882f82009-06-10 13:36:04 -07008726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008727 void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
8728 final Surface surface = win.mSurface;
Romain Guy06882f82009-06-10 13:36:04 -07008729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008730 EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
8731 win.mSession.mPid, operation);
Romain Guy06882f82009-06-10 13:36:04 -07008732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008733 if (mForceRemoves == null) {
8734 mForceRemoves = new ArrayList<WindowState>();
8735 }
Romain Guy06882f82009-06-10 13:36:04 -07008736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008737 long callingIdentity = Binder.clearCallingIdentity();
8738 try {
8739 // There was some problem... first, do a sanity check of the
8740 // window list to make sure we haven't left any dangling surfaces
8741 // around.
8742 int N = mWindows.size();
8743 boolean leakedSurface = false;
8744 Log.i(TAG, "Out of memory for surface! Looking for leaks...");
8745 for (int i=0; i<N; i++) {
8746 WindowState ws = (WindowState)mWindows.get(i);
8747 if (ws.mSurface != null) {
8748 if (!mSessions.contains(ws.mSession)) {
8749 Log.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8750 + ws + " surface=" + ws.mSurface
8751 + " token=" + win.mToken
8752 + " pid=" + ws.mSession.mPid
8753 + " uid=" + ws.mSession.mUid);
8754 ws.mSurface.clear();
8755 ws.mSurface = null;
8756 mForceRemoves.add(ws);
8757 i--;
8758 N--;
8759 leakedSurface = true;
8760 } else if (win.mAppToken != null && win.mAppToken.clientHidden) {
8761 Log.w(TAG, "LEAKED SURFACE (app token hidden): "
8762 + ws + " surface=" + ws.mSurface
8763 + " token=" + win.mAppToken);
8764 ws.mSurface.clear();
8765 ws.mSurface = null;
8766 leakedSurface = true;
8767 }
8768 }
8769 }
Romain Guy06882f82009-06-10 13:36:04 -07008770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008771 boolean killedApps = false;
8772 if (!leakedSurface) {
8773 Log.w(TAG, "No leaked surfaces; killing applicatons!");
8774 SparseIntArray pidCandidates = new SparseIntArray();
8775 for (int i=0; i<N; i++) {
8776 WindowState ws = (WindowState)mWindows.get(i);
8777 if (ws.mSurface != null) {
8778 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8779 }
8780 }
8781 if (pidCandidates.size() > 0) {
8782 int[] pids = new int[pidCandidates.size()];
8783 for (int i=0; i<pids.length; i++) {
8784 pids[i] = pidCandidates.keyAt(i);
8785 }
8786 try {
8787 if (mActivityManager.killPidsForMemory(pids)) {
8788 killedApps = true;
8789 }
8790 } catch (RemoteException e) {
8791 }
8792 }
8793 }
Romain Guy06882f82009-06-10 13:36:04 -07008794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008795 if (leakedSurface || killedApps) {
8796 // We managed to reclaim some memory, so get rid of the trouble
8797 // surface and ask the app to request another one.
8798 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8799 if (surface != null) {
8800 surface.clear();
8801 win.mSurface = null;
8802 }
Romain Guy06882f82009-06-10 13:36:04 -07008803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008804 try {
8805 win.mClient.dispatchGetNewSurface();
8806 } catch (RemoteException e) {
8807 }
8808 }
8809 } finally {
8810 Binder.restoreCallingIdentity(callingIdentity);
8811 }
8812 }
Romain Guy06882f82009-06-10 13:36:04 -07008813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008814 private boolean updateFocusedWindowLocked(int mode) {
8815 WindowState newFocus = computeFocusedWindowLocked();
8816 if (mCurrentFocus != newFocus) {
8817 // This check makes sure that we don't already have the focus
8818 // change message pending.
8819 mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8820 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8821 if (localLOGV) Log.v(
8822 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8823 final WindowState oldFocus = mCurrentFocus;
8824 mCurrentFocus = newFocus;
8825 mLosingFocus.remove(newFocus);
Romain Guy06882f82009-06-10 13:36:04 -07008826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008827 final WindowState imWindow = mInputMethodWindow;
8828 if (newFocus != imWindow && oldFocus != imWindow) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008829 if (moveInputMethodWindowsIfNeededLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008830 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008831 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8832 mLayoutNeeded = true;
8833 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008834 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8835 performLayoutLockedInner();
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008836 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8837 // Client will do the layout, but we need to assign layers
8838 // for handleNewWindowLocked() below.
8839 assignLayersLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 }
8841 }
Romain Guy06882f82009-06-10 13:36:04 -07008842
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008843 if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8844 mKeyWaiter.handleNewWindowLocked(newFocus);
8845 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008846 return true;
8847 }
8848 return false;
8849 }
8850
8851 private WindowState computeFocusedWindowLocked() {
8852 WindowState result = null;
8853 WindowState win;
8854
8855 int i = mWindows.size() - 1;
8856 int nextAppIndex = mAppTokens.size()-1;
8857 WindowToken nextApp = nextAppIndex >= 0
8858 ? mAppTokens.get(nextAppIndex) : null;
8859
8860 while (i >= 0) {
8861 win = (WindowState)mWindows.get(i);
8862
8863 if (localLOGV || DEBUG_FOCUS) Log.v(
8864 TAG, "Looking for focus: " + i
8865 + " = " + win
8866 + ", flags=" + win.mAttrs.flags
8867 + ", canReceive=" + win.canReceiveKeys());
8868
8869 AppWindowToken thisApp = win.mAppToken;
Romain Guy06882f82009-06-10 13:36:04 -07008870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008871 // If this window's application has been removed, just skip it.
8872 if (thisApp != null && thisApp.removed) {
8873 i--;
8874 continue;
8875 }
Romain Guy06882f82009-06-10 13:36:04 -07008876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008877 // If there is a focused app, don't allow focus to go to any
8878 // windows below it. If this is an application window, step
8879 // through the app tokens until we find its app.
8880 if (thisApp != null && nextApp != null && thisApp != nextApp
8881 && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8882 int origAppIndex = nextAppIndex;
8883 while (nextAppIndex > 0) {
8884 if (nextApp == mFocusedApp) {
8885 // Whoops, we are below the focused app... no focus
8886 // for you!
8887 if (localLOGV || DEBUG_FOCUS) Log.v(
8888 TAG, "Reached focused app: " + mFocusedApp);
8889 return null;
8890 }
8891 nextAppIndex--;
8892 nextApp = mAppTokens.get(nextAppIndex);
8893 if (nextApp == thisApp) {
8894 break;
8895 }
8896 }
8897 if (thisApp != nextApp) {
8898 // Uh oh, the app token doesn't exist! This shouldn't
8899 // happen, but if it does we can get totally hosed...
8900 // so restart at the original app.
8901 nextAppIndex = origAppIndex;
8902 nextApp = mAppTokens.get(nextAppIndex);
8903 }
8904 }
8905
8906 // Dispatch to this window if it is wants key events.
8907 if (win.canReceiveKeys()) {
8908 if (DEBUG_FOCUS) Log.v(
8909 TAG, "Found focus @ " + i + " = " + win);
8910 result = win;
8911 break;
8912 }
8913
8914 i--;
8915 }
8916
8917 return result;
8918 }
8919
8920 private void startFreezingDisplayLocked() {
8921 if (mDisplayFrozen) {
Chris Tate2ad63a92009-03-25 17:36:48 -07008922 // Freezing the display also suspends key event delivery, to
8923 // keep events from going astray while the display is reconfigured.
8924 // If someone has changed orientation again while the screen is
8925 // still frozen, the events will continue to be blocked while the
8926 // successive orientation change is processed. To prevent spurious
8927 // ANRs, we reset the event dispatch timeout in this case.
8928 synchronized (mKeyWaiter) {
8929 mKeyWaiter.mWasFrozen = true;
8930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 return;
8932 }
Romain Guy06882f82009-06-10 13:36:04 -07008933
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 mScreenFrozenLock.acquire();
Romain Guy06882f82009-06-10 13:36:04 -07008935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008936 long now = SystemClock.uptimeMillis();
8937 //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8938 if (mFreezeGcPending != 0) {
8939 if (now > (mFreezeGcPending+1000)) {
8940 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
8941 mH.removeMessages(H.FORCE_GC);
8942 Runtime.getRuntime().gc();
8943 mFreezeGcPending = now;
8944 }
8945 } else {
8946 mFreezeGcPending = now;
8947 }
Romain Guy06882f82009-06-10 13:36:04 -07008948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008949 mDisplayFrozen = true;
8950 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
8951 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8952 mAppTransitionReady = true;
8953 }
Romain Guy06882f82009-06-10 13:36:04 -07008954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008955 if (PROFILE_ORIENTATION) {
8956 File file = new File("/data/system/frozen");
8957 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8958 }
8959 Surface.freezeDisplay(0);
8960 }
Romain Guy06882f82009-06-10 13:36:04 -07008961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008962 private void stopFreezingDisplayLocked() {
8963 if (!mDisplayFrozen) {
8964 return;
8965 }
Romain Guy06882f82009-06-10 13:36:04 -07008966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 mDisplayFrozen = false;
8968 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8969 if (PROFILE_ORIENTATION) {
8970 Debug.stopMethodTracing();
8971 }
8972 Surface.unfreezeDisplay(0);
Romain Guy06882f82009-06-10 13:36:04 -07008973
Chris Tate2ad63a92009-03-25 17:36:48 -07008974 // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
8975 // too because regular key delivery processing should resume immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008976 synchronized (mKeyWaiter) {
8977 mKeyWaiter.mWasFrozen = true;
8978 mKeyWaiter.notifyAll();
8979 }
8980
8981 // A little kludge: a lot could have happened while the
8982 // display was frozen, so now that we are coming back we
8983 // do a gc so that any remote references the system
8984 // processes holds on others can be released if they are
8985 // no longer needed.
8986 mH.removeMessages(H.FORCE_GC);
8987 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8988 2000);
Romain Guy06882f82009-06-10 13:36:04 -07008989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008990 mScreenFrozenLock.release();
8991 }
Romain Guy06882f82009-06-10 13:36:04 -07008992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008993 @Override
8994 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8995 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
8996 != PackageManager.PERMISSION_GRANTED) {
8997 pw.println("Permission Denial: can't dump WindowManager from from pid="
8998 + Binder.getCallingPid()
8999 + ", uid=" + Binder.getCallingUid());
9000 return;
9001 }
Romain Guy06882f82009-06-10 13:36:04 -07009002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009003 synchronized(mWindowMap) {
9004 pw.println("Current Window Manager state:");
9005 for (int i=mWindows.size()-1; i>=0; i--) {
9006 WindowState w = (WindowState)mWindows.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009007 pw.print(" Window #"); pw.print(i); pw.print(' ');
9008 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009009 w.dump(pw, " ");
9010 }
9011 if (mInputMethodDialogs.size() > 0) {
9012 pw.println(" ");
9013 pw.println(" Input method dialogs:");
9014 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9015 WindowState w = mInputMethodDialogs.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009016 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009017 }
9018 }
9019 if (mPendingRemove.size() > 0) {
9020 pw.println(" ");
9021 pw.println(" Remove pending for:");
9022 for (int i=mPendingRemove.size()-1; i>=0; i--) {
9023 WindowState w = mPendingRemove.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009024 pw.print(" Remove #"); pw.print(i); pw.print(' ');
9025 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009026 w.dump(pw, " ");
9027 }
9028 }
9029 if (mForceRemoves != null && mForceRemoves.size() > 0) {
9030 pw.println(" ");
9031 pw.println(" Windows force removing:");
9032 for (int i=mForceRemoves.size()-1; i>=0; i--) {
9033 WindowState w = mForceRemoves.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009034 pw.print(" Removing #"); pw.print(i); pw.print(' ');
9035 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 w.dump(pw, " ");
9037 }
9038 }
9039 if (mDestroySurface.size() > 0) {
9040 pw.println(" ");
9041 pw.println(" Windows waiting to destroy their surface:");
9042 for (int i=mDestroySurface.size()-1; i>=0; i--) {
9043 WindowState w = mDestroySurface.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009044 pw.print(" Destroy #"); pw.print(i); pw.print(' ');
9045 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009046 w.dump(pw, " ");
9047 }
9048 }
9049 if (mLosingFocus.size() > 0) {
9050 pw.println(" ");
9051 pw.println(" Windows losing focus:");
9052 for (int i=mLosingFocus.size()-1; i>=0; i--) {
9053 WindowState w = mLosingFocus.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009054 pw.print(" Losing #"); pw.print(i); pw.print(' ');
9055 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 w.dump(pw, " ");
9057 }
9058 }
9059 if (mSessions.size() > 0) {
9060 pw.println(" ");
9061 pw.println(" All active sessions:");
9062 Iterator<Session> it = mSessions.iterator();
9063 while (it.hasNext()) {
9064 Session s = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009065 pw.print(" Session "); pw.print(s); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009066 s.dump(pw, " ");
9067 }
9068 }
9069 if (mTokenMap.size() > 0) {
9070 pw.println(" ");
9071 pw.println(" All tokens:");
9072 Iterator<WindowToken> it = mTokenMap.values().iterator();
9073 while (it.hasNext()) {
9074 WindowToken token = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009075 pw.print(" Token "); pw.print(token.token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009076 token.dump(pw, " ");
9077 }
9078 }
9079 if (mTokenList.size() > 0) {
9080 pw.println(" ");
9081 pw.println(" Window token list:");
9082 for (int i=0; i<mTokenList.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009083 pw.print(" #"); pw.print(i); pw.print(": ");
9084 pw.println(mTokenList.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 }
9086 }
9087 if (mAppTokens.size() > 0) {
9088 pw.println(" ");
9089 pw.println(" Application tokens in Z order:");
9090 for (int i=mAppTokens.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009091 pw.print(" App #"); pw.print(i); pw.print(": ");
9092 pw.println(mAppTokens.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009093 }
9094 }
9095 if (mFinishedStarting.size() > 0) {
9096 pw.println(" ");
9097 pw.println(" Finishing start of application tokens:");
9098 for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9099 WindowToken token = mFinishedStarting.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009100 pw.print(" Finished Starting #"); pw.print(i);
9101 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009102 token.dump(pw, " ");
9103 }
9104 }
9105 if (mExitingTokens.size() > 0) {
9106 pw.println(" ");
9107 pw.println(" Exiting tokens:");
9108 for (int i=mExitingTokens.size()-1; i>=0; i--) {
9109 WindowToken token = mExitingTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009110 pw.print(" Exiting #"); pw.print(i);
9111 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009112 token.dump(pw, " ");
9113 }
9114 }
9115 if (mExitingAppTokens.size() > 0) {
9116 pw.println(" ");
9117 pw.println(" Exiting application tokens:");
9118 for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9119 WindowToken token = mExitingAppTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009120 pw.print(" Exiting App #"); pw.print(i);
9121 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009122 token.dump(pw, " ");
9123 }
9124 }
9125 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009126 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
9127 pw.print(" mLastFocus="); pw.println(mLastFocus);
9128 pw.print(" mFocusedApp="); pw.println(mFocusedApp);
9129 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
9130 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
9131 pw.print(" mInTouchMode="); pw.println(mInTouchMode);
9132 pw.print(" mSystemBooted="); pw.print(mSystemBooted);
9133 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9134 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
9135 pw.print(" mBlurShown="); pw.println(mBlurShown);
9136 pw.print(" mDimShown="); pw.print(mDimShown);
9137 pw.print(" current="); pw.print(mDimCurrentAlpha);
9138 pw.print(" target="); pw.print(mDimTargetAlpha);
9139 pw.print(" delta="); pw.print(mDimDeltaPerMs);
9140 pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
9141 pw.print(" mInputMethodAnimLayerAdjustment=");
9142 pw.println(mInputMethodAnimLayerAdjustment);
9143 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
9144 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9145 pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
9146 pw.print(" mRotation="); pw.print(mRotation);
9147 pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
9148 pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
9149 pw.print(" mAnimationPending="); pw.print(mAnimationPending);
9150 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9151 pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9152 pw.print(" mNextAppTransition=0x");
9153 pw.print(Integer.toHexString(mNextAppTransition));
9154 pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
9155 pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9156 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9157 pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9158 if (mOpeningApps.size() > 0) {
9159 pw.print(" mOpeningApps="); pw.println(mOpeningApps);
9160 }
9161 if (mClosingApps.size() > 0) {
9162 pw.print(" mClosingApps="); pw.println(mClosingApps);
9163 }
9164 pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth());
9165 pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009166 pw.println(" KeyWaiter state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009167 pw.print(" mLastWin="); pw.print(mKeyWaiter.mLastWin);
9168 pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
9169 pw.print(" mFinished="); pw.print(mKeyWaiter.mFinished);
9170 pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
9171 pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
9172 pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009173 }
9174 }
9175
9176 public void monitor() {
9177 synchronized (mWindowMap) { }
9178 synchronized (mKeyguardDisabled) { }
9179 synchronized (mKeyWaiter) { }
9180 }
9181}