blob: 4baf202869c19d4ceedcae926bd1900cd2322d1c [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;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -070027import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
29import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
30import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
31import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
32import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
33import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
34import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
35import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
36import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
37import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
38import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
39import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
40import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
41import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
42
43import com.android.internal.app.IBatteryStats;
44import com.android.internal.policy.PolicyManager;
45import com.android.internal.view.IInputContext;
46import com.android.internal.view.IInputMethodClient;
47import com.android.internal.view.IInputMethodManager;
48import com.android.server.KeyInputQueue.QueuedEvent;
49import com.android.server.am.BatteryStatsService;
50
51import android.Manifest;
52import android.app.ActivityManagerNative;
53import android.app.IActivityManager;
54import android.content.Context;
55import android.content.pm.ActivityInfo;
56import android.content.pm.PackageManager;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -070057import android.content.res.CompatibilityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.res.Configuration;
59import android.graphics.Matrix;
60import android.graphics.PixelFormat;
61import android.graphics.Rect;
62import android.graphics.Region;
63import android.os.BatteryStats;
64import android.os.Binder;
65import android.os.Debug;
66import android.os.Handler;
67import android.os.IBinder;
68import android.os.LocalPowerManager;
69import android.os.Looper;
70import android.os.Message;
71import android.os.Parcel;
72import android.os.ParcelFileDescriptor;
73import android.os.Power;
74import android.os.PowerManager;
75import android.os.Process;
76import android.os.RemoteException;
77import android.os.ServiceManager;
78import android.os.SystemClock;
79import android.os.SystemProperties;
80import android.os.TokenWatcher;
81import android.provider.Settings;
Dianne Hackborn723738c2009-06-25 19:48:04 -070082import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.util.EventLog;
84import android.util.Log;
85import android.util.SparseIntArray;
86import android.view.Display;
87import android.view.Gravity;
88import android.view.IApplicationToken;
89import android.view.IOnKeyguardExitResult;
90import android.view.IRotationWatcher;
91import android.view.IWindow;
92import android.view.IWindowManager;
93import android.view.IWindowSession;
94import android.view.KeyEvent;
95import android.view.MotionEvent;
96import android.view.RawInputEvent;
97import android.view.Surface;
98import android.view.SurfaceSession;
99import android.view.View;
100import android.view.ViewTreeObserver;
101import android.view.WindowManager;
102import android.view.WindowManagerImpl;
103import android.view.WindowManagerPolicy;
104import android.view.WindowManager.LayoutParams;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700105import android.view.animation.AccelerateInterpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import android.view.animation.Animation;
107import android.view.animation.AnimationUtils;
108import android.view.animation.Transformation;
109
110import java.io.BufferedWriter;
111import java.io.File;
112import java.io.FileDescriptor;
113import java.io.IOException;
114import java.io.OutputStream;
115import java.io.OutputStreamWriter;
116import java.io.PrintWriter;
117import java.io.StringWriter;
118import java.net.Socket;
119import java.util.ArrayList;
120import java.util.HashMap;
121import java.util.HashSet;
122import java.util.Iterator;
123import java.util.List;
124
125/** {@hide} */
126public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
127 static final String TAG = "WindowManager";
128 static final boolean DEBUG = false;
129 static final boolean DEBUG_FOCUS = false;
130 static final boolean DEBUG_ANIM = false;
131 static final boolean DEBUG_LAYERS = false;
132 static final boolean DEBUG_INPUT = false;
133 static final boolean DEBUG_INPUT_METHOD = false;
134 static final boolean DEBUG_VISIBILITY = false;
135 static final boolean DEBUG_ORIENTATION = false;
136 static final boolean DEBUG_APP_TRANSITIONS = false;
137 static final boolean DEBUG_STARTING_WINDOW = false;
138 static final boolean DEBUG_REORDER = false;
139 static final boolean SHOW_TRANSACTIONS = false;
Romain Guy06882f82009-06-10 13:36:04 -0700140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean PROFILE_ORIENTATION = false;
142 static final boolean BLUR = true;
Dave Bortcfe65242009-04-09 14:51:04 -0700143 static final boolean localLOGV = DEBUG;
Romain Guy06882f82009-06-10 13:36:04 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
Romain Guy06882f82009-06-10 13:36:04 -0700146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 /** How long to wait for first key repeat, in milliseconds */
148 static final int KEY_REPEAT_FIRST_DELAY = 750;
Romain Guy06882f82009-06-10 13:36:04 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 /** How long to wait for subsequent key repeats, in milliseconds */
151 static final int KEY_REPEAT_DELAY = 50;
152
153 /** How much to multiply the policy's type layer, to reserve room
154 * for multiple windows of the same type and Z-ordering adjustment
155 * with TYPE_LAYER_OFFSET. */
156 static final int TYPE_LAYER_MULTIPLIER = 10000;
Romain Guy06882f82009-06-10 13:36:04 -0700157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
159 * or below others in the same layer. */
160 static final int TYPE_LAYER_OFFSET = 1000;
Romain Guy06882f82009-06-10 13:36:04 -0700161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 /** How much to increment the layer for each window, to reserve room
163 * for effect surfaces between them.
164 */
165 static final int WINDOW_LAYER_MULTIPLIER = 5;
Romain Guy06882f82009-06-10 13:36:04 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 /** The maximum length we will accept for a loaded animation duration:
168 * this is 10 seconds.
169 */
170 static final int MAX_ANIMATION_DURATION = 10*1000;
171
172 /** Amount of time (in milliseconds) to animate the dim surface from one
173 * value to another, when no window animation is driving it.
174 */
175 static final int DEFAULT_DIM_DURATION = 200;
176
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700177 /** Amount of time (in milliseconds) to animate the fade-in-out transition for
178 * compatible windows.
179 */
180 static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 /** Adjustment to time to perform a dim, to make it more dramatic.
183 */
184 static final int DIM_DURATION_MULTIPLIER = 6;
Romain Guy06882f82009-06-10 13:36:04 -0700185
Dianne Hackborncfaef692009-06-15 14:24:44 -0700186 static final int INJECT_FAILED = 0;
187 static final int INJECT_SUCCEEDED = 1;
188 static final int INJECT_NO_PERMISSION = -1;
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 static final int UPDATE_FOCUS_NORMAL = 0;
191 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
192 static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
193 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
Romain Guy06882f82009-06-10 13:36:04 -0700194
Michael Chane96440f2009-05-06 10:27:36 -0700195 /** The minimum time between dispatching touch events. */
196 int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
197
198 // Last touch event time
199 long mLastTouchEventTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700200
Michael Chane96440f2009-05-06 10:27:36 -0700201 // Last touch event type
202 int mLastTouchEventType = OTHER_EVENT;
Romain Guy06882f82009-06-10 13:36:04 -0700203
Michael Chane96440f2009-05-06 10:27:36 -0700204 // Time to wait before calling useractivity again. This saves CPU usage
205 // when we get a flood of touch events.
206 static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
207
208 // Last time we call user activity
209 long mLastUserActivityCallTime = 0;
210
Romain Guy06882f82009-06-10 13:36:04 -0700211 // Last time we updated battery stats
Michael Chane96440f2009-05-06 10:27:36 -0700212 long mLastBatteryStatsCallTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 private static final String SYSTEM_SECURE = "ro.secure";
Romain Guy06882f82009-06-10 13:36:04 -0700215 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
217 /**
218 * Condition waited on by {@link #reenableKeyguard} to know the call to
219 * the window policy has finished.
220 */
221 private boolean mWaitingUntilKeyguardReenabled = false;
222
223
224 final TokenWatcher mKeyguardDisabled = new TokenWatcher(
225 new Handler(), "WindowManagerService.mKeyguardDisabled") {
226 public void acquired() {
227 mPolicy.enableKeyguard(false);
228 }
229 public void released() {
230 synchronized (mKeyguardDisabled) {
231 mPolicy.enableKeyguard(true);
232 mWaitingUntilKeyguardReenabled = false;
233 mKeyguardDisabled.notifyAll();
234 }
235 }
236 };
237
238 final Context mContext;
239
240 final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 final boolean mLimitedAlphaCompositing;
Romain Guy06882f82009-06-10 13:36:04 -0700243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
245
246 final IActivityManager mActivityManager;
Romain Guy06882f82009-06-10 13:36:04 -0700247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 final IBatteryStats mBatteryStats;
Romain Guy06882f82009-06-10 13:36:04 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 /**
251 * All currently active sessions with clients.
252 */
253 final HashSet<Session> mSessions = new HashSet<Session>();
Romain Guy06882f82009-06-10 13:36:04 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 /**
256 * Mapping from an IWindow IBinder to the server's Window object.
257 * This is also used as the lock for all of our state.
258 */
259 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
260
261 /**
262 * Mapping from a token IBinder to a WindowToken object.
263 */
264 final HashMap<IBinder, WindowToken> mTokenMap =
265 new HashMap<IBinder, WindowToken>();
266
267 /**
268 * The same tokens as mTokenMap, stored in a list for efficient iteration
269 * over them.
270 */
271 final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 /**
274 * Window tokens that are in the process of exiting, but still
275 * on screen for animations.
276 */
277 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
278
279 /**
280 * Z-ordered (bottom-most first) list of all application tokens, for
281 * controlling the ordering of windows in different applications. This
282 * contains WindowToken objects.
283 */
284 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
285
286 /**
287 * Application tokens that are in the process of exiting, but still
288 * on screen for animations.
289 */
290 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
291
292 /**
293 * List of window tokens that have finished starting their application,
294 * and now need to have the policy remove their windows.
295 */
296 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
297
298 /**
299 * Z-ordered (bottom-most first) list of all Window objects.
300 */
301 final ArrayList mWindows = new ArrayList();
302
303 /**
304 * Windows that are being resized. Used so we can tell the client about
305 * the resize after closing the transaction in which we resized the
306 * underlying surface.
307 */
308 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
309
310 /**
311 * Windows whose animations have ended and now must be removed.
312 */
313 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
314
315 /**
316 * Windows whose surface should be destroyed.
317 */
318 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
319
320 /**
321 * Windows that have lost input focus and are waiting for the new
322 * focus window to be displayed before they are told about this.
323 */
324 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
325
326 /**
327 * This is set when we have run out of memory, and will either be an empty
328 * list or contain windows that need to be force removed.
329 */
330 ArrayList<WindowState> mForceRemoves;
Romain Guy06882f82009-06-10 13:36:04 -0700331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 IInputMethodManager mInputMethodManager;
Romain Guy06882f82009-06-10 13:36:04 -0700333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 SurfaceSession mFxSession;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700335 private DimAnimator mDimAnimator = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 Surface mBlurSurface;
337 boolean mBlurShown;
Romain Guy06882f82009-06-10 13:36:04 -0700338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 int mTransactionSequence = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 final float[] mTmpFloats = new float[9];
342
343 boolean mSafeMode;
344 boolean mDisplayEnabled = false;
345 boolean mSystemBooted = false;
346 int mRotation = 0;
347 int mRequestedRotation = 0;
348 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Dianne Hackborn321ae682009-03-27 16:16:03 -0700349 int mLastRotationFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 ArrayList<IRotationWatcher> mRotationWatchers
351 = new ArrayList<IRotationWatcher>();
Romain Guy06882f82009-06-10 13:36:04 -0700352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 boolean mLayoutNeeded = true;
354 boolean mAnimationPending = false;
355 boolean mDisplayFrozen = false;
356 boolean mWindowsFreezingScreen = false;
357 long mFreezeGcPending = 0;
358 int mAppsFreezingScreen = 0;
359
360 // This is held as long as we have the screen frozen, to give us time to
361 // perform a rotation animation when turning off shows the lock screen which
362 // changes the orientation.
363 PowerManager.WakeLock mScreenFrozenLock;
Romain Guy06882f82009-06-10 13:36:04 -0700364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 // State management of app transitions. When we are preparing for a
366 // transition, mNextAppTransition will be the kind of transition to
367 // perform or TRANSIT_NONE if we are not waiting. If we are waiting,
368 // mOpeningApps and mClosingApps are the lists of tokens that will be
369 // made visible or hidden at the next transition.
370 int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
371 boolean mAppTransitionReady = false;
372 boolean mAppTransitionTimeout = false;
373 boolean mStartingIconInTransition = false;
374 boolean mSkipAppTransitionAnimation = false;
375 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
376 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 //flag to detect fat touch events
379 boolean mFatTouch = false;
380 Display mDisplay;
Romain Guy06882f82009-06-10 13:36:04 -0700381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 H mH = new H();
383
384 WindowState mCurrentFocus = null;
385 WindowState mLastFocus = null;
Romain Guy06882f82009-06-10 13:36:04 -0700386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 // This just indicates the window the input method is on top of, not
388 // necessarily the window its input is going to.
389 WindowState mInputMethodTarget = null;
390 WindowState mUpcomingInputMethodTarget = null;
391 boolean mInputMethodTargetWaitingAnim;
392 int mInputMethodAnimLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -0700393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 WindowState mInputMethodWindow = null;
395 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
396
397 AppWindowToken mFocusedApp = null;
398
399 PowerManagerService mPowerManager;
Romain Guy06882f82009-06-10 13:36:04 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 float mWindowAnimationScale = 1.0f;
402 float mTransitionAnimationScale = 1.0f;
Romain Guy06882f82009-06-10 13:36:04 -0700403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 final KeyWaiter mKeyWaiter = new KeyWaiter();
405 final KeyQ mQueue;
406 final InputDispatcherThread mInputThread;
407
408 // Who is holding the screen on.
409 Session mHoldingScreenOn;
Romain Guy06882f82009-06-10 13:36:04 -0700410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 /**
412 * Whether the UI is currently running in touch mode (not showing
413 * navigational focus because the user is directly pressing the screen).
414 */
415 boolean mInTouchMode = false;
416
417 private ViewServer mViewServer;
418
419 final Rect mTempRect = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -0700420
Dianne Hackbornc485a602009-03-24 22:39:49 -0700421 final Configuration mTempConfiguration = new Configuration();
Dianne Hackborn723738c2009-06-25 19:48:04 -0700422 int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700423
424 // The frame use to limit the size of the app running in compatibility mode.
425 Rect mCompatibleScreenFrame = new Rect();
426 // The surface used to fill the outer rim of the app running in compatibility mode.
427 Surface mBackgroundFillerSurface = null;
428 boolean mBackgroundFillerShown = false;
429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 public static WindowManagerService main(Context context,
431 PowerManagerService pm, boolean haveInputMethods) {
432 WMThread thr = new WMThread(context, pm, haveInputMethods);
433 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 synchronized (thr) {
436 while (thr.mService == null) {
437 try {
438 thr.wait();
439 } catch (InterruptedException e) {
440 }
441 }
442 }
Romain Guy06882f82009-06-10 13:36:04 -0700443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 return thr.mService;
445 }
Romain Guy06882f82009-06-10 13:36:04 -0700446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 static class WMThread extends Thread {
448 WindowManagerService mService;
Romain Guy06882f82009-06-10 13:36:04 -0700449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 private final Context mContext;
451 private final PowerManagerService mPM;
452 private final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 public WMThread(Context context, PowerManagerService pm,
455 boolean haveInputMethods) {
456 super("WindowManager");
457 mContext = context;
458 mPM = pm;
459 mHaveInputMethods = haveInputMethods;
460 }
Romain Guy06882f82009-06-10 13:36:04 -0700461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 public void run() {
463 Looper.prepare();
464 WindowManagerService s = new WindowManagerService(mContext, mPM,
465 mHaveInputMethods);
466 android.os.Process.setThreadPriority(
467 android.os.Process.THREAD_PRIORITY_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -0700468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 synchronized (this) {
470 mService = s;
471 notifyAll();
472 }
Romain Guy06882f82009-06-10 13:36:04 -0700473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 Looper.loop();
475 }
476 }
477
478 static class PolicyThread extends Thread {
479 private final WindowManagerPolicy mPolicy;
480 private final WindowManagerService mService;
481 private final Context mContext;
482 private final PowerManagerService mPM;
483 boolean mRunning = false;
Romain Guy06882f82009-06-10 13:36:04 -0700484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 public PolicyThread(WindowManagerPolicy policy,
486 WindowManagerService service, Context context,
487 PowerManagerService pm) {
488 super("WindowManagerPolicy");
489 mPolicy = policy;
490 mService = service;
491 mContext = context;
492 mPM = pm;
493 }
Romain Guy06882f82009-06-10 13:36:04 -0700494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 public void run() {
496 Looper.prepare();
497 //Looper.myLooper().setMessageLogging(new LogPrinter(
498 // Log.VERBOSE, "WindowManagerPolicy"));
499 android.os.Process.setThreadPriority(
500 android.os.Process.THREAD_PRIORITY_FOREGROUND);
501 mPolicy.init(mContext, mService, mPM);
Romain Guy06882f82009-06-10 13:36:04 -0700502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 synchronized (this) {
504 mRunning = true;
505 notifyAll();
506 }
Romain Guy06882f82009-06-10 13:36:04 -0700507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 Looper.loop();
509 }
510 }
511
512 private WindowManagerService(Context context, PowerManagerService pm,
513 boolean haveInputMethods) {
514 mContext = context;
515 mHaveInputMethods = haveInputMethods;
516 mLimitedAlphaCompositing = context.getResources().getBoolean(
517 com.android.internal.R.bool.config_sf_limitedAlpha);
Romain Guy06882f82009-06-10 13:36:04 -0700518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 mPowerManager = pm;
520 mPowerManager.setPolicy(mPolicy);
521 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
522 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
523 "SCREEN_FROZEN");
524 mScreenFrozenLock.setReferenceCounted(false);
525
526 mActivityManager = ActivityManagerNative.getDefault();
527 mBatteryStats = BatteryStatsService.getService();
528
529 // Get persisted window scale setting
530 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
531 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
532 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
533 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
Romain Guy06882f82009-06-10 13:36:04 -0700534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 mQueue = new KeyQ();
536
537 mInputThread = new InputDispatcherThread();
Romain Guy06882f82009-06-10 13:36:04 -0700538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
540 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 synchronized (thr) {
543 while (!thr.mRunning) {
544 try {
545 thr.wait();
546 } catch (InterruptedException e) {
547 }
548 }
549 }
Romain Guy06882f82009-06-10 13:36:04 -0700550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 mInputThread.start();
Romain Guy06882f82009-06-10 13:36:04 -0700552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 // Add ourself to the Watchdog monitors.
554 Watchdog.getInstance().addMonitor(this);
555 }
556
557 @Override
558 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
559 throws RemoteException {
560 try {
561 return super.onTransact(code, data, reply, flags);
562 } catch (RuntimeException e) {
563 // The window manager only throws security exceptions, so let's
564 // log all others.
565 if (!(e instanceof SecurityException)) {
566 Log.e(TAG, "Window Manager Crash", e);
567 }
568 throw e;
569 }
570 }
571
572 private void placeWindowAfter(Object pos, WindowState window) {
573 final int i = mWindows.indexOf(pos);
574 if (localLOGV || DEBUG_FOCUS) Log.v(
575 TAG, "Adding window " + window + " at "
576 + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
577 mWindows.add(i+1, window);
578 }
579
580 private void placeWindowBefore(Object pos, WindowState window) {
581 final int i = mWindows.indexOf(pos);
582 if (localLOGV || DEBUG_FOCUS) Log.v(
583 TAG, "Adding window " + window + " at "
584 + i + " of " + mWindows.size() + " (before " + pos + ")");
585 mWindows.add(i, window);
586 }
587
588 //This method finds out the index of a window that has the same app token as
589 //win. used for z ordering the windows in mWindows
590 private int findIdxBasedOnAppTokens(WindowState win) {
591 //use a local variable to cache mWindows
592 ArrayList localmWindows = mWindows;
593 int jmax = localmWindows.size();
594 if(jmax == 0) {
595 return -1;
596 }
597 for(int j = (jmax-1); j >= 0; j--) {
598 WindowState wentry = (WindowState)localmWindows.get(j);
599 if(wentry.mAppToken == win.mAppToken) {
600 return j;
601 }
602 }
603 return -1;
604 }
Romain Guy06882f82009-06-10 13:36:04 -0700605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
607 final IWindow client = win.mClient;
608 final WindowToken token = win.mToken;
609 final ArrayList localmWindows = mWindows;
Romain Guy06882f82009-06-10 13:36:04 -0700610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 final int N = localmWindows.size();
612 final WindowState attached = win.mAttachedWindow;
613 int i;
614 if (attached == null) {
615 int tokenWindowsPos = token.windows.size();
616 if (token.appWindowToken != null) {
617 int index = tokenWindowsPos-1;
618 if (index >= 0) {
619 // If this application has existing windows, we
620 // simply place the new window on top of them... but
621 // keep the starting window on top.
622 if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
623 // Base windows go behind everything else.
624 placeWindowBefore(token.windows.get(0), win);
625 tokenWindowsPos = 0;
626 } else {
627 AppWindowToken atoken = win.mAppToken;
628 if (atoken != null &&
629 token.windows.get(index) == atoken.startingWindow) {
630 placeWindowBefore(token.windows.get(index), win);
631 tokenWindowsPos--;
632 } else {
633 int newIdx = findIdxBasedOnAppTokens(win);
634 if(newIdx != -1) {
Romain Guy06882f82009-06-10 13:36:04 -0700635 //there is a window above this one associated with the same
636 //apptoken note that the window could be a floating window
637 //that was created later or a window at the top of the list of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 //windows associated with this token.
639 localmWindows.add(newIdx+1, win);
Romain Guy06882f82009-06-10 13:36:04 -0700640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
642 }
643 } else {
644 if (localLOGV) Log.v(
645 TAG, "Figuring out where to add app window "
646 + client.asBinder() + " (token=" + token + ")");
647 // Figure out where the window should go, based on the
648 // order of applications.
649 final int NA = mAppTokens.size();
650 Object pos = null;
651 for (i=NA-1; i>=0; i--) {
652 AppWindowToken t = mAppTokens.get(i);
653 if (t == token) {
654 i--;
655 break;
656 }
657 if (t.windows.size() > 0) {
658 pos = t.windows.get(0);
659 }
660 }
661 // We now know the index into the apps. If we found
662 // an app window above, that gives us the position; else
663 // we need to look some more.
664 if (pos != null) {
665 // Move behind any windows attached to this one.
Romain Guy06882f82009-06-10 13:36:04 -0700666 WindowToken atoken =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 mTokenMap.get(((WindowState)pos).mClient.asBinder());
668 if (atoken != null) {
669 final int NC = atoken.windows.size();
670 if (NC > 0) {
671 WindowState bottom = atoken.windows.get(0);
672 if (bottom.mSubLayer < 0) {
673 pos = bottom;
674 }
675 }
676 }
677 placeWindowBefore(pos, win);
678 } else {
679 while (i >= 0) {
680 AppWindowToken t = mAppTokens.get(i);
681 final int NW = t.windows.size();
682 if (NW > 0) {
683 pos = t.windows.get(NW-1);
684 break;
685 }
686 i--;
687 }
688 if (pos != null) {
689 // Move in front of any windows attached to this
690 // one.
691 WindowToken atoken =
692 mTokenMap.get(((WindowState)pos).mClient.asBinder());
693 if (atoken != null) {
694 final int NC = atoken.windows.size();
695 if (NC > 0) {
696 WindowState top = atoken.windows.get(NC-1);
697 if (top.mSubLayer >= 0) {
698 pos = top;
699 }
700 }
701 }
702 placeWindowAfter(pos, win);
703 } else {
704 // Just search for the start of this layer.
705 final int myLayer = win.mBaseLayer;
706 for (i=0; i<N; i++) {
707 WindowState w = (WindowState)localmWindows.get(i);
708 if (w.mBaseLayer > myLayer) {
709 break;
710 }
711 }
712 if (localLOGV || DEBUG_FOCUS) Log.v(
713 TAG, "Adding window " + win + " at "
714 + i + " of " + N);
715 localmWindows.add(i, win);
716 }
717 }
718 }
719 } else {
720 // Figure out where window should go, based on layer.
721 final int myLayer = win.mBaseLayer;
722 for (i=N-1; i>=0; i--) {
723 if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
724 i++;
725 break;
726 }
727 }
728 if (i < 0) i = 0;
729 if (localLOGV || DEBUG_FOCUS) Log.v(
730 TAG, "Adding window " + win + " at "
731 + i + " of " + N);
732 localmWindows.add(i, win);
733 }
734 if (addToToken) {
735 token.windows.add(tokenWindowsPos, win);
736 }
737
738 } else {
739 // Figure out this window's ordering relative to the window
740 // it is attached to.
741 final int NA = token.windows.size();
742 final int sublayer = win.mSubLayer;
743 int largestSublayer = Integer.MIN_VALUE;
744 WindowState windowWithLargestSublayer = null;
745 for (i=0; i<NA; i++) {
746 WindowState w = token.windows.get(i);
747 final int wSublayer = w.mSubLayer;
748 if (wSublayer >= largestSublayer) {
749 largestSublayer = wSublayer;
750 windowWithLargestSublayer = w;
751 }
752 if (sublayer < 0) {
753 // For negative sublayers, we go below all windows
754 // in the same sublayer.
755 if (wSublayer >= sublayer) {
756 if (addToToken) {
757 token.windows.add(i, win);
758 }
759 placeWindowBefore(
760 wSublayer >= 0 ? attached : w, win);
761 break;
762 }
763 } else {
764 // For positive sublayers, we go above all windows
765 // in the same sublayer.
766 if (wSublayer > sublayer) {
767 if (addToToken) {
768 token.windows.add(i, win);
769 }
770 placeWindowBefore(w, win);
771 break;
772 }
773 }
774 }
775 if (i >= NA) {
776 if (addToToken) {
777 token.windows.add(win);
778 }
779 if (sublayer < 0) {
780 placeWindowBefore(attached, win);
781 } else {
782 placeWindowAfter(largestSublayer >= 0
783 ? windowWithLargestSublayer
784 : attached,
785 win);
786 }
787 }
788 }
Romain Guy06882f82009-06-10 13:36:04 -0700789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 if (win.mAppToken != null && addToToken) {
791 win.mAppToken.allAppWindows.add(win);
792 }
793 }
Romain Guy06882f82009-06-10 13:36:04 -0700794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 static boolean canBeImeTarget(WindowState w) {
796 final int fl = w.mAttrs.flags
797 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
798 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
799 return w.isVisibleOrAdding();
800 }
801 return false;
802 }
Romain Guy06882f82009-06-10 13:36:04 -0700803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
805 final ArrayList localmWindows = mWindows;
806 final int N = localmWindows.size();
807 WindowState w = null;
808 int i = N;
809 while (i > 0) {
810 i--;
811 w = (WindowState)localmWindows.get(i);
Romain Guy06882f82009-06-10 13:36:04 -0700812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
814 // + Integer.toHexString(w.mAttrs.flags));
815 if (canBeImeTarget(w)) {
816 //Log.i(TAG, "Putting input method here!");
Romain Guy06882f82009-06-10 13:36:04 -0700817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 // Yet more tricksyness! If this window is a "starting"
819 // window, we do actually want to be on top of it, but
820 // it is not -really- where input will go. So if the caller
821 // is not actually looking to move the IME, look down below
822 // for a real window to target...
823 if (!willMove
824 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
825 && i > 0) {
826 WindowState wb = (WindowState)localmWindows.get(i-1);
827 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
828 i--;
829 w = wb;
830 }
831 }
832 break;
833 }
834 }
Romain Guy06882f82009-06-10 13:36:04 -0700835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 mUpcomingInputMethodTarget = w;
Romain Guy06882f82009-06-10 13:36:04 -0700837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
839 + w + " willMove=" + willMove);
Romain Guy06882f82009-06-10 13:36:04 -0700840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 if (willMove && w != null) {
842 final WindowState curTarget = mInputMethodTarget;
843 if (curTarget != null && curTarget.mAppToken != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 // Now some fun for dealing with window animations that
846 // modify the Z order. We need to look at all windows below
847 // the current target that are in this app, finding the highest
848 // visible one in layering.
849 AppWindowToken token = curTarget.mAppToken;
850 WindowState highestTarget = null;
851 int highestPos = 0;
852 if (token.animating || token.animation != null) {
853 int pos = 0;
854 pos = localmWindows.indexOf(curTarget);
855 while (pos >= 0) {
856 WindowState win = (WindowState)localmWindows.get(pos);
857 if (win.mAppToken != token) {
858 break;
859 }
860 if (!win.mRemoved) {
861 if (highestTarget == null || win.mAnimLayer >
862 highestTarget.mAnimLayer) {
863 highestTarget = win;
864 highestPos = pos;
865 }
866 }
867 pos--;
868 }
869 }
Romain Guy06882f82009-06-10 13:36:04 -0700870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 if (highestTarget != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700872 if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 + mNextAppTransition + " " + highestTarget
874 + " animating=" + highestTarget.isAnimating()
875 + " layer=" + highestTarget.mAnimLayer
876 + " new layer=" + w.mAnimLayer);
Romain Guy06882f82009-06-10 13:36:04 -0700877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
879 // If we are currently setting up for an animation,
880 // hold everything until we can find out what will happen.
881 mInputMethodTargetWaitingAnim = true;
882 mInputMethodTarget = highestTarget;
883 return highestPos + 1;
884 } else if (highestTarget.isAnimating() &&
885 highestTarget.mAnimLayer > w.mAnimLayer) {
886 // If the window we are currently targeting is involved
887 // with an animation, and it is on top of the next target
888 // we will be over, then hold off on moving until
889 // that is done.
890 mInputMethodTarget = highestTarget;
891 return highestPos + 1;
892 }
893 }
894 }
895 }
Romain Guy06882f82009-06-10 13:36:04 -0700896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 //Log.i(TAG, "Placing input method @" + (i+1));
898 if (w != null) {
899 if (willMove) {
900 RuntimeException e = new RuntimeException();
901 e.fillInStackTrace();
902 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
903 + mInputMethodTarget + " to " + w, e);
904 mInputMethodTarget = w;
905 if (w.mAppToken != null) {
906 setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
907 } else {
908 setInputMethodAnimLayerAdjustment(0);
909 }
910 }
911 return i+1;
912 }
913 if (willMove) {
914 RuntimeException e = new RuntimeException();
915 e.fillInStackTrace();
916 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
917 + mInputMethodTarget + " to null", e);
918 mInputMethodTarget = null;
919 setInputMethodAnimLayerAdjustment(0);
920 }
921 return -1;
922 }
Romain Guy06882f82009-06-10 13:36:04 -0700923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 void addInputMethodWindowToListLocked(WindowState win) {
925 int pos = findDesiredInputMethodWindowIndexLocked(true);
926 if (pos >= 0) {
927 win.mTargetAppToken = mInputMethodTarget.mAppToken;
928 mWindows.add(pos, win);
929 moveInputMethodDialogsLocked(pos+1);
930 return;
931 }
932 win.mTargetAppToken = null;
933 addWindowToListInOrderLocked(win, true);
934 moveInputMethodDialogsLocked(pos);
935 }
Romain Guy06882f82009-06-10 13:36:04 -0700936
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 void setInputMethodAnimLayerAdjustment(int adj) {
938 if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
939 mInputMethodAnimLayerAdjustment = adj;
940 WindowState imw = mInputMethodWindow;
941 if (imw != null) {
942 imw.mAnimLayer = imw.mLayer + adj;
943 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
944 + " anim layer: " + imw.mAnimLayer);
945 int wi = imw.mChildWindows.size();
946 while (wi > 0) {
947 wi--;
948 WindowState cw = (WindowState)imw.mChildWindows.get(wi);
949 cw.mAnimLayer = cw.mLayer + adj;
950 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
951 + " anim layer: " + cw.mAnimLayer);
952 }
953 }
954 int di = mInputMethodDialogs.size();
955 while (di > 0) {
956 di --;
957 imw = mInputMethodDialogs.get(di);
958 imw.mAnimLayer = imw.mLayer + adj;
959 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
960 + " anim layer: " + imw.mAnimLayer);
961 }
962 }
Romain Guy06882f82009-06-10 13:36:04 -0700963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
965 int wpos = mWindows.indexOf(win);
966 if (wpos >= 0) {
967 if (wpos < interestingPos) interestingPos--;
968 mWindows.remove(wpos);
969 int NC = win.mChildWindows.size();
970 while (NC > 0) {
971 NC--;
972 WindowState cw = (WindowState)win.mChildWindows.get(NC);
973 int cpos = mWindows.indexOf(cw);
974 if (cpos >= 0) {
975 if (cpos < interestingPos) interestingPos--;
976 mWindows.remove(cpos);
977 }
978 }
979 }
980 return interestingPos;
981 }
Romain Guy06882f82009-06-10 13:36:04 -0700982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 private void reAddWindowToListInOrderLocked(WindowState win) {
984 addWindowToListInOrderLocked(win, false);
985 // This is a hack to get all of the child windows added as well
986 // at the right position. Child windows should be rare and
987 // this case should be rare, so it shouldn't be that big a deal.
988 int wpos = mWindows.indexOf(win);
989 if (wpos >= 0) {
990 mWindows.remove(wpos);
991 reAddWindowLocked(wpos, win);
992 }
993 }
Romain Guy06882f82009-06-10 13:36:04 -0700994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 void logWindowList(String prefix) {
996 int N = mWindows.size();
997 while (N > 0) {
998 N--;
999 Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
1000 }
1001 }
Romain Guy06882f82009-06-10 13:36:04 -07001002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 void moveInputMethodDialogsLocked(int pos) {
1004 ArrayList<WindowState> dialogs = mInputMethodDialogs;
Romain Guy06882f82009-06-10 13:36:04 -07001005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 final int N = dialogs.size();
1007 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
1008 for (int i=0; i<N; i++) {
1009 pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
1010 }
1011 if (DEBUG_INPUT_METHOD) {
1012 Log.v(TAG, "Window list w/pos=" + pos);
1013 logWindowList(" ");
1014 }
Romain Guy06882f82009-06-10 13:36:04 -07001015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 if (pos >= 0) {
1017 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
1018 if (pos < mWindows.size()) {
1019 WindowState wp = (WindowState)mWindows.get(pos);
1020 if (wp == mInputMethodWindow) {
1021 pos++;
1022 }
1023 }
1024 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
1025 for (int i=0; i<N; i++) {
1026 WindowState win = dialogs.get(i);
1027 win.mTargetAppToken = targetAppToken;
1028 pos = reAddWindowLocked(pos, win);
1029 }
1030 if (DEBUG_INPUT_METHOD) {
1031 Log.v(TAG, "Final window list:");
1032 logWindowList(" ");
1033 }
1034 return;
1035 }
1036 for (int i=0; i<N; i++) {
1037 WindowState win = dialogs.get(i);
1038 win.mTargetAppToken = null;
1039 reAddWindowToListInOrderLocked(win);
1040 if (DEBUG_INPUT_METHOD) {
1041 Log.v(TAG, "No IM target, final list:");
1042 logWindowList(" ");
1043 }
1044 }
1045 }
Romain Guy06882f82009-06-10 13:36:04 -07001046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
1048 final WindowState imWin = mInputMethodWindow;
1049 final int DN = mInputMethodDialogs.size();
1050 if (imWin == null && DN == 0) {
1051 return false;
1052 }
Romain Guy06882f82009-06-10 13:36:04 -07001053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 int imPos = findDesiredInputMethodWindowIndexLocked(true);
1055 if (imPos >= 0) {
1056 // In this case, the input method windows are to be placed
1057 // immediately above the window they are targeting.
Romain Guy06882f82009-06-10 13:36:04 -07001058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 // First check to see if the input method windows are already
1060 // located here, and contiguous.
1061 final int N = mWindows.size();
1062 WindowState firstImWin = imPos < N
1063 ? (WindowState)mWindows.get(imPos) : null;
Romain Guy06882f82009-06-10 13:36:04 -07001064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 // Figure out the actual input method window that should be
1066 // at the bottom of their stack.
1067 WindowState baseImWin = imWin != null
1068 ? imWin : mInputMethodDialogs.get(0);
1069 if (baseImWin.mChildWindows.size() > 0) {
1070 WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
1071 if (cw.mSubLayer < 0) baseImWin = cw;
1072 }
Romain Guy06882f82009-06-10 13:36:04 -07001073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 if (firstImWin == baseImWin) {
1075 // The windows haven't moved... but are they still contiguous?
1076 // First find the top IM window.
1077 int pos = imPos+1;
1078 while (pos < N) {
1079 if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
1080 break;
1081 }
1082 pos++;
1083 }
1084 pos++;
1085 // Now there should be no more input method windows above.
1086 while (pos < N) {
1087 if (((WindowState)mWindows.get(pos)).mIsImWindow) {
1088 break;
1089 }
1090 pos++;
1091 }
1092 if (pos >= N) {
1093 // All is good!
1094 return false;
1095 }
1096 }
Romain Guy06882f82009-06-10 13:36:04 -07001097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 if (imWin != null) {
1099 if (DEBUG_INPUT_METHOD) {
1100 Log.v(TAG, "Moving IM from " + imPos);
1101 logWindowList(" ");
1102 }
1103 imPos = tmpRemoveWindowLocked(imPos, imWin);
1104 if (DEBUG_INPUT_METHOD) {
1105 Log.v(TAG, "List after moving with new pos " + imPos + ":");
1106 logWindowList(" ");
1107 }
1108 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
1109 reAddWindowLocked(imPos, imWin);
1110 if (DEBUG_INPUT_METHOD) {
1111 Log.v(TAG, "List after moving IM to " + imPos + ":");
1112 logWindowList(" ");
1113 }
1114 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
1115 } else {
1116 moveInputMethodDialogsLocked(imPos);
1117 }
Romain Guy06882f82009-06-10 13:36:04 -07001118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 } else {
1120 // In this case, the input method windows go in a fixed layer,
1121 // because they aren't currently associated with a focus window.
Romain Guy06882f82009-06-10 13:36:04 -07001122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 if (imWin != null) {
1124 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
1125 tmpRemoveWindowLocked(0, imWin);
1126 imWin.mTargetAppToken = null;
1127 reAddWindowToListInOrderLocked(imWin);
1128 if (DEBUG_INPUT_METHOD) {
1129 Log.v(TAG, "List with no IM target:");
1130 logWindowList(" ");
1131 }
1132 if (DN > 0) moveInputMethodDialogsLocked(-1);;
1133 } else {
1134 moveInputMethodDialogsLocked(-1);;
1135 }
Romain Guy06882f82009-06-10 13:36:04 -07001136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 }
Romain Guy06882f82009-06-10 13:36:04 -07001138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 if (needAssignLayers) {
1140 assignLayersLocked();
1141 }
Romain Guy06882f82009-06-10 13:36:04 -07001142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 return true;
1144 }
Romain Guy06882f82009-06-10 13:36:04 -07001145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 void adjustInputMethodDialogsLocked() {
1147 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
1148 }
Romain Guy06882f82009-06-10 13:36:04 -07001149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 public int addWindow(Session session, IWindow client,
1151 WindowManager.LayoutParams attrs, int viewVisibility,
1152 Rect outContentInsets) {
1153 int res = mPolicy.checkAddPermission(attrs);
1154 if (res != WindowManagerImpl.ADD_OKAY) {
1155 return res;
1156 }
Romain Guy06882f82009-06-10 13:36:04 -07001157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 boolean reportNewConfig = false;
1159 WindowState attachedWindow = null;
1160 WindowState win = null;
Romain Guy06882f82009-06-10 13:36:04 -07001161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 synchronized(mWindowMap) {
1163 // Instantiating a Display requires talking with the simulator,
1164 // so don't do it until we know the system is mostly up and
1165 // running.
1166 if (mDisplay == null) {
1167 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1168 mDisplay = wm.getDefaultDisplay();
1169 mQueue.setDisplay(mDisplay);
1170 reportNewConfig = true;
1171 }
Romain Guy06882f82009-06-10 13:36:04 -07001172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 if (mWindowMap.containsKey(client.asBinder())) {
1174 Log.w(TAG, "Window " + client + " is already added");
1175 return WindowManagerImpl.ADD_DUPLICATE_ADD;
1176 }
1177
1178 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
Romain Guy06882f82009-06-10 13:36:04 -07001179 attachedWindow = windowForClientLocked(null, attrs.token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 if (attachedWindow == null) {
1181 Log.w(TAG, "Attempted to add window with token that is not a window: "
1182 + attrs.token + ". Aborting.");
1183 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1184 }
1185 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
1186 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1187 Log.w(TAG, "Attempted to add window with token that is a sub-window: "
1188 + attrs.token + ". Aborting.");
1189 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1190 }
1191 }
1192
1193 boolean addToken = false;
1194 WindowToken token = mTokenMap.get(attrs.token);
1195 if (token == null) {
1196 if (attrs.type >= FIRST_APPLICATION_WINDOW
1197 && attrs.type <= LAST_APPLICATION_WINDOW) {
1198 Log.w(TAG, "Attempted to add application window with unknown token "
1199 + attrs.token + ". Aborting.");
1200 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1201 }
1202 if (attrs.type == TYPE_INPUT_METHOD) {
1203 Log.w(TAG, "Attempted to add input method window with unknown token "
1204 + attrs.token + ". Aborting.");
1205 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1206 }
1207 token = new WindowToken(attrs.token, -1, false);
1208 addToken = true;
1209 } else if (attrs.type >= FIRST_APPLICATION_WINDOW
1210 && attrs.type <= LAST_APPLICATION_WINDOW) {
1211 AppWindowToken atoken = token.appWindowToken;
1212 if (atoken == null) {
1213 Log.w(TAG, "Attempted to add window with non-application token "
1214 + token + ". Aborting.");
1215 return WindowManagerImpl.ADD_NOT_APP_TOKEN;
1216 } else if (atoken.removed) {
1217 Log.w(TAG, "Attempted to add window with exiting application token "
1218 + token + ". Aborting.");
1219 return WindowManagerImpl.ADD_APP_EXITING;
1220 }
1221 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
1222 // No need for this guy!
1223 if (localLOGV) Log.v(
1224 TAG, "**** NO NEED TO START: " + attrs.getTitle());
1225 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
1226 }
1227 } else if (attrs.type == TYPE_INPUT_METHOD) {
1228 if (token.windowType != TYPE_INPUT_METHOD) {
1229 Log.w(TAG, "Attempted to add input method window with bad token "
1230 + attrs.token + ". Aborting.");
1231 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1232 }
1233 }
1234
1235 win = new WindowState(session, client, token,
1236 attachedWindow, attrs, viewVisibility);
1237 if (win.mDeathRecipient == null) {
1238 // Client has apparently died, so there is no reason to
1239 // continue.
1240 Log.w(TAG, "Adding window client " + client.asBinder()
1241 + " that is dead, aborting.");
1242 return WindowManagerImpl.ADD_APP_EXITING;
1243 }
1244
1245 mPolicy.adjustWindowParamsLw(win.mAttrs);
Romain Guy06882f82009-06-10 13:36:04 -07001246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 res = mPolicy.prepareAddWindowLw(win, attrs);
1248 if (res != WindowManagerImpl.ADD_OKAY) {
1249 return res;
1250 }
1251
1252 // From now on, no exceptions or errors allowed!
1253
1254 res = WindowManagerImpl.ADD_OKAY;
Romain Guy06882f82009-06-10 13:36:04 -07001255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 if (addToken) {
1259 mTokenMap.put(attrs.token, token);
1260 mTokenList.add(token);
1261 }
1262 win.attach();
1263 mWindowMap.put(client.asBinder(), win);
1264
1265 if (attrs.type == TYPE_APPLICATION_STARTING &&
1266 token.appWindowToken != null) {
1267 token.appWindowToken.startingWindow = win;
1268 }
1269
1270 boolean imMayMove = true;
Romain Guy06882f82009-06-10 13:36:04 -07001271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 if (attrs.type == TYPE_INPUT_METHOD) {
1273 mInputMethodWindow = win;
1274 addInputMethodWindowToListLocked(win);
1275 imMayMove = false;
1276 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
1277 mInputMethodDialogs.add(win);
1278 addWindowToListInOrderLocked(win, true);
1279 adjustInputMethodDialogsLocked();
1280 imMayMove = false;
1281 } else {
1282 addWindowToListInOrderLocked(win, true);
1283 }
Romain Guy06882f82009-06-10 13:36:04 -07001284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 win.mEnterAnimationPending = true;
Romain Guy06882f82009-06-10 13:36:04 -07001286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
Romain Guy06882f82009-06-10 13:36:04 -07001288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 if (mInTouchMode) {
1290 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
1291 }
1292 if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
1293 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
1294 }
Romain Guy06882f82009-06-10 13:36:04 -07001295
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001296 boolean focusChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 if (win.canReceiveKeys()) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001298 if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
1299 == true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 imMayMove = false;
1301 }
1302 }
Romain Guy06882f82009-06-10 13:36:04 -07001303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 if (imMayMove) {
Romain Guy06882f82009-06-10 13:36:04 -07001305 moveInputMethodWindowsIfNeededLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 }
Romain Guy06882f82009-06-10 13:36:04 -07001307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 assignLayersLocked();
1309 // Don't do layout here, the window must call
1310 // relayout to be displayed, so we'll do it there.
Romain Guy06882f82009-06-10 13:36:04 -07001311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 //dump();
1313
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001314 if (focusChanged) {
1315 if (mCurrentFocus != null) {
1316 mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
1317 }
1318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 if (localLOGV) Log.v(
1320 TAG, "New client " + client.asBinder()
1321 + ": window=" + win);
1322 }
1323
1324 // sendNewConfiguration() checks caller permissions so we must call it with
1325 // privilege. updateOrientationFromAppTokens() clears and resets the caller
1326 // identity anyway, so it's safe to just clear & restore around this whole
1327 // block.
1328 final long origId = Binder.clearCallingIdentity();
1329 if (reportNewConfig) {
1330 sendNewConfiguration();
1331 } else {
1332 // Update Orientation after adding a window, only if the window needs to be
1333 // displayed right away
1334 if (win.isVisibleOrAdding()) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001335 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 sendNewConfiguration();
1337 }
1338 }
1339 }
1340 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 return res;
1343 }
Romain Guy06882f82009-06-10 13:36:04 -07001344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 public void removeWindow(Session session, IWindow client) {
1346 synchronized(mWindowMap) {
1347 WindowState win = windowForClientLocked(session, client);
1348 if (win == null) {
1349 return;
1350 }
1351 removeWindowLocked(session, win);
1352 }
1353 }
Romain Guy06882f82009-06-10 13:36:04 -07001354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 public void removeWindowLocked(Session session, WindowState win) {
1356
1357 if (localLOGV || DEBUG_FOCUS) Log.v(
1358 TAG, "Remove " + win + " client="
1359 + Integer.toHexString(System.identityHashCode(
1360 win.mClient.asBinder()))
1361 + ", surface=" + win.mSurface);
1362
1363 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 if (DEBUG_APP_TRANSITIONS) Log.v(
1366 TAG, "Remove " + win + ": mSurface=" + win.mSurface
1367 + " mExiting=" + win.mExiting
1368 + " isAnimating=" + win.isAnimating()
1369 + " app-animation="
1370 + (win.mAppToken != null ? win.mAppToken.animation : null)
1371 + " inPendingTransaction="
1372 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
1373 + " mDisplayFrozen=" + mDisplayFrozen);
1374 // Visibility of the removed window. Will be used later to update orientation later on.
1375 boolean wasVisible = false;
1376 // First, see if we need to run an animation. If we do, we have
1377 // to hold off on removing the window until the animation is done.
1378 // If the display is frozen, just remove immediately, since the
1379 // animation wouldn't be seen.
1380 if (win.mSurface != null && !mDisplayFrozen) {
1381 // If we are not currently running the exit animation, we
1382 // need to see about starting one.
1383 if (wasVisible=win.isWinVisibleLw()) {
Romain Guy06882f82009-06-10 13:36:04 -07001384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1386 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1387 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1388 }
1389 // Try starting an animation.
1390 if (applyAnimationLocked(win, transit, false)) {
1391 win.mExiting = true;
1392 }
1393 }
1394 if (win.mExiting || win.isAnimating()) {
1395 // The exit animation is running... wait for it!
1396 //Log.i(TAG, "*** Running exit animation...");
1397 win.mExiting = true;
1398 win.mRemoveOnExit = true;
1399 mLayoutNeeded = true;
1400 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
1401 performLayoutAndPlaceSurfacesLocked();
1402 if (win.mAppToken != null) {
1403 win.mAppToken.updateReportedVisibilityLocked();
1404 }
1405 //dump();
1406 Binder.restoreCallingIdentity(origId);
1407 return;
1408 }
1409 }
1410
1411 removeWindowInnerLocked(session, win);
1412 // Removing a visible window will effect the computed orientation
1413 // So just update orientation if needed.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001414 if (wasVisible && computeForcedAppOrientationLocked()
1415 != mForcedAppOrientation) {
1416 mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 }
1418 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1419 Binder.restoreCallingIdentity(origId);
1420 }
Romain Guy06882f82009-06-10 13:36:04 -07001421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 private void removeWindowInnerLocked(Session session, WindowState win) {
1423 mKeyWaiter.releasePendingPointerLocked(win.mSession);
1424 mKeyWaiter.releasePendingTrackballLocked(win.mSession);
Romain Guy06882f82009-06-10 13:36:04 -07001425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 win.mRemoved = true;
Romain Guy06882f82009-06-10 13:36:04 -07001427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 if (mInputMethodTarget == win) {
1429 moveInputMethodWindowsIfNeededLocked(false);
1430 }
Romain Guy06882f82009-06-10 13:36:04 -07001431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 mPolicy.removeWindowLw(win);
1433 win.removeLocked();
1434
1435 mWindowMap.remove(win.mClient.asBinder());
1436 mWindows.remove(win);
1437
1438 if (mInputMethodWindow == win) {
1439 mInputMethodWindow = null;
1440 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
1441 mInputMethodDialogs.remove(win);
1442 }
Romain Guy06882f82009-06-10 13:36:04 -07001443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 final WindowToken token = win.mToken;
1445 final AppWindowToken atoken = win.mAppToken;
1446 token.windows.remove(win);
1447 if (atoken != null) {
1448 atoken.allAppWindows.remove(win);
1449 }
1450 if (localLOGV) Log.v(
1451 TAG, "**** Removing window " + win + ": count="
1452 + token.windows.size());
1453 if (token.windows.size() == 0) {
1454 if (!token.explicit) {
1455 mTokenMap.remove(token.token);
1456 mTokenList.remove(token);
1457 } else if (atoken != null) {
1458 atoken.firstWindowDrawn = false;
1459 }
1460 }
1461
1462 if (atoken != null) {
1463 if (atoken.startingWindow == win) {
1464 atoken.startingWindow = null;
1465 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
1466 // If this is the last window and we had requested a starting
1467 // transition window, well there is no point now.
1468 atoken.startingData = null;
1469 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
1470 // If this is the last window except for a starting transition
1471 // window, we need to get rid of the starting transition.
1472 if (DEBUG_STARTING_WINDOW) {
1473 Log.v(TAG, "Schedule remove starting " + token
1474 + ": no more real windows");
1475 }
1476 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
1477 mH.sendMessage(m);
1478 }
1479 }
Romain Guy06882f82009-06-10 13:36:04 -07001480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 if (!mInLayout) {
1482 assignLayersLocked();
1483 mLayoutNeeded = true;
1484 performLayoutAndPlaceSurfacesLocked();
1485 if (win.mAppToken != null) {
1486 win.mAppToken.updateReportedVisibilityLocked();
1487 }
1488 }
1489 }
1490
1491 private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
1492 long origId = Binder.clearCallingIdentity();
1493 try {
1494 synchronized (mWindowMap) {
1495 WindowState w = windowForClientLocked(session, client);
1496 if ((w != null) && (w.mSurface != null)) {
1497 Surface.openTransaction();
1498 try {
1499 w.mSurface.setTransparentRegionHint(region);
1500 } finally {
1501 Surface.closeTransaction();
1502 }
1503 }
1504 }
1505 } finally {
1506 Binder.restoreCallingIdentity(origId);
1507 }
1508 }
1509
1510 void setInsetsWindow(Session session, IWindow client,
Romain Guy06882f82009-06-10 13:36:04 -07001511 int touchableInsets, Rect contentInsets,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 Rect visibleInsets) {
1513 long origId = Binder.clearCallingIdentity();
1514 try {
1515 synchronized (mWindowMap) {
1516 WindowState w = windowForClientLocked(session, client);
1517 if (w != null) {
1518 w.mGivenInsetsPending = false;
1519 w.mGivenContentInsets.set(contentInsets);
1520 w.mGivenVisibleInsets.set(visibleInsets);
1521 w.mTouchableInsets = touchableInsets;
1522 mLayoutNeeded = true;
1523 performLayoutAndPlaceSurfacesLocked();
1524 }
1525 }
1526 } finally {
1527 Binder.restoreCallingIdentity(origId);
1528 }
1529 }
Romain Guy06882f82009-06-10 13:36:04 -07001530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 public void getWindowDisplayFrame(Session session, IWindow client,
1532 Rect outDisplayFrame) {
1533 synchronized(mWindowMap) {
1534 WindowState win = windowForClientLocked(session, client);
1535 if (win == null) {
1536 outDisplayFrame.setEmpty();
1537 return;
1538 }
1539 outDisplayFrame.set(win.mDisplayFrame);
1540 }
1541 }
1542
1543 public int relayoutWindow(Session session, IWindow client,
1544 WindowManager.LayoutParams attrs, int requestedWidth,
1545 int requestedHeight, int viewVisibility, boolean insetsPending,
1546 Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
1547 Surface outSurface) {
1548 boolean displayed = false;
1549 boolean inTouchMode;
1550 Configuration newConfig = null;
1551 long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 synchronized(mWindowMap) {
1554 WindowState win = windowForClientLocked(session, client);
1555 if (win == null) {
1556 return 0;
1557 }
1558 win.mRequestedWidth = requestedWidth;
1559 win.mRequestedHeight = requestedHeight;
1560
1561 if (attrs != null) {
1562 mPolicy.adjustWindowParamsLw(attrs);
1563 }
Romain Guy06882f82009-06-10 13:36:04 -07001564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 int attrChanges = 0;
1566 int flagChanges = 0;
1567 if (attrs != null) {
1568 flagChanges = win.mAttrs.flags ^= attrs.flags;
1569 attrChanges = win.mAttrs.copyFrom(attrs);
1570 }
1571
1572 if (localLOGV) Log.v(
1573 TAG, "Relayout given client " + client.asBinder()
1574 + " (" + win.mAttrs.getTitle() + ")");
1575
1576
1577 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
1578 win.mAlpha = attrs.alpha;
1579 }
1580
1581 final boolean scaledWindow =
1582 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
1583
1584 if (scaledWindow) {
1585 // requested{Width|Height} Surface's physical size
1586 // attrs.{width|height} Size on screen
1587 win.mHScale = (attrs.width != requestedWidth) ?
1588 (attrs.width / (float)requestedWidth) : 1.0f;
1589 win.mVScale = (attrs.height != requestedHeight) ?
1590 (attrs.height / (float)requestedHeight) : 1.0f;
1591 }
1592
1593 boolean imMayMove = (flagChanges&(
1594 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
1595 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07001596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 boolean focusMayChange = win.mViewVisibility != viewVisibility
1598 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
1599 || (!win.mRelayoutCalled);
Romain Guy06882f82009-06-10 13:36:04 -07001600
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 win.mRelayoutCalled = true;
1602 final int oldVisibility = win.mViewVisibility;
1603 win.mViewVisibility = viewVisibility;
1604 if (viewVisibility == View.VISIBLE &&
1605 (win.mAppToken == null || !win.mAppToken.clientHidden)) {
1606 displayed = !win.isVisibleLw();
1607 if (win.mExiting) {
1608 win.mExiting = false;
1609 win.mAnimation = null;
1610 }
1611 if (win.mDestroying) {
1612 win.mDestroying = false;
1613 mDestroySurface.remove(win);
1614 }
1615 if (oldVisibility == View.GONE) {
1616 win.mEnterAnimationPending = true;
1617 }
1618 if (displayed && win.mSurface != null && !win.mDrawPending
1619 && !win.mCommitDrawPending && !mDisplayFrozen) {
1620 applyEnterAnimationLocked(win);
1621 }
1622 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
1623 // To change the format, we need to re-build the surface.
1624 win.destroySurfaceLocked();
1625 displayed = true;
1626 }
1627 try {
1628 Surface surface = win.createSurfaceLocked();
1629 if (surface != null) {
1630 outSurface.copyFrom(surface);
1631 } else {
1632 outSurface.clear();
1633 }
1634 } catch (Exception e) {
1635 Log.w(TAG, "Exception thrown when creating surface for client "
1636 + client + " (" + win.mAttrs.getTitle() + ")",
1637 e);
1638 Binder.restoreCallingIdentity(origId);
1639 return 0;
1640 }
1641 if (displayed) {
1642 focusMayChange = true;
1643 }
1644 if (win.mAttrs.type == TYPE_INPUT_METHOD
1645 && mInputMethodWindow == null) {
1646 mInputMethodWindow = win;
1647 imMayMove = true;
1648 }
1649 } else {
1650 win.mEnterAnimationPending = false;
1651 if (win.mSurface != null) {
1652 // If we are not currently running the exit animation, we
1653 // need to see about starting one.
1654 if (!win.mExiting) {
1655 // Try starting an animation; if there isn't one, we
1656 // can destroy the surface right away.
1657 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1658 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1659 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1660 }
1661 if (win.isWinVisibleLw() &&
1662 applyAnimationLocked(win, transit, false)) {
1663 win.mExiting = true;
1664 mKeyWaiter.finishedKey(session, client, true,
1665 KeyWaiter.RETURN_NOTHING);
1666 } else if (win.isAnimating()) {
1667 // Currently in a hide animation... turn this into
1668 // an exit.
1669 win.mExiting = true;
1670 } else {
1671 if (mInputMethodWindow == win) {
1672 mInputMethodWindow = null;
1673 }
1674 win.destroySurfaceLocked();
1675 }
1676 }
1677 }
1678 outSurface.clear();
1679 }
1680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 if (focusMayChange) {
1682 //System.out.println("Focus may change: " + win.mAttrs.getTitle());
1683 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 imMayMove = false;
1685 }
1686 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
1687 }
Romain Guy06882f82009-06-10 13:36:04 -07001688
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001689 // updateFocusedWindowLocked() already assigned layers so we only need to
1690 // reassign them at this point if the IM window state gets shuffled
1691 boolean assignLayers = false;
Romain Guy06882f82009-06-10 13:36:04 -07001692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 if (imMayMove) {
1694 if (moveInputMethodWindowsIfNeededLocked(false)) {
1695 assignLayers = true;
1696 }
1697 }
Romain Guy06882f82009-06-10 13:36:04 -07001698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 mLayoutNeeded = true;
1700 win.mGivenInsetsPending = insetsPending;
1701 if (assignLayers) {
1702 assignLayersLocked();
1703 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001704 newConfig = updateOrientationFromAppTokensLocked(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 performLayoutAndPlaceSurfacesLocked();
1706 if (win.mAppToken != null) {
1707 win.mAppToken.updateReportedVisibilityLocked();
1708 }
1709 outFrame.set(win.mFrame);
1710 outContentInsets.set(win.mContentInsets);
1711 outVisibleInsets.set(win.mVisibleInsets);
1712 if (localLOGV) Log.v(
1713 TAG, "Relayout given client " + client.asBinder()
Romain Guy06882f82009-06-10 13:36:04 -07001714 + ", requestedWidth=" + requestedWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 + ", requestedHeight=" + requestedHeight
1716 + ", viewVisibility=" + viewVisibility
1717 + "\nRelayout returning frame=" + outFrame
1718 + ", surface=" + outSurface);
1719
1720 if (localLOGV || DEBUG_FOCUS) Log.v(
1721 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
1722
1723 inTouchMode = mInTouchMode;
1724 }
1725
1726 if (newConfig != null) {
1727 sendNewConfiguration();
1728 }
Romain Guy06882f82009-06-10 13:36:04 -07001729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
1733 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
1734 }
1735
1736 public void finishDrawingWindow(Session session, IWindow client) {
1737 final long origId = Binder.clearCallingIdentity();
1738 synchronized(mWindowMap) {
1739 WindowState win = windowForClientLocked(session, client);
1740 if (win != null && win.finishDrawingLocked()) {
1741 mLayoutNeeded = true;
1742 performLayoutAndPlaceSurfacesLocked();
1743 }
1744 }
1745 Binder.restoreCallingIdentity(origId);
1746 }
1747
1748 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
1749 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
1750 + (lp != null ? lp.packageName : null)
1751 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
1752 if (lp != null && lp.windowAnimations != 0) {
1753 // If this is a system resource, don't try to load it from the
1754 // application resources. It is nice to avoid loading application
1755 // resources if we can.
1756 String packageName = lp.packageName != null ? lp.packageName : "android";
1757 int resId = lp.windowAnimations;
1758 if ((resId&0xFF000000) == 0x01000000) {
1759 packageName = "android";
1760 }
1761 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
1762 + packageName);
1763 return AttributeCache.instance().get(packageName, resId,
1764 com.android.internal.R.styleable.WindowAnimation);
1765 }
1766 return null;
1767 }
Romain Guy06882f82009-06-10 13:36:04 -07001768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 private void applyEnterAnimationLocked(WindowState win) {
1770 int transit = WindowManagerPolicy.TRANSIT_SHOW;
1771 if (win.mEnterAnimationPending) {
1772 win.mEnterAnimationPending = false;
1773 transit = WindowManagerPolicy.TRANSIT_ENTER;
1774 }
1775
1776 applyAnimationLocked(win, transit, true);
1777 }
1778
1779 private boolean applyAnimationLocked(WindowState win,
1780 int transit, boolean isEntrance) {
1781 if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
1782 // If we are trying to apply an animation, but already running
1783 // an animation of the same type, then just leave that one alone.
1784 return true;
1785 }
Romain Guy06882f82009-06-10 13:36:04 -07001786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 // Only apply an animation if the display isn't frozen. If it is
1788 // frozen, there is no reason to animate and it can cause strange
1789 // artifacts when we unfreeze the display if some different animation
1790 // is running.
1791 if (!mDisplayFrozen) {
1792 int anim = mPolicy.selectAnimationLw(win, transit);
1793 int attr = -1;
1794 Animation a = null;
1795 if (anim != 0) {
1796 a = AnimationUtils.loadAnimation(mContext, anim);
1797 } else {
1798 switch (transit) {
1799 case WindowManagerPolicy.TRANSIT_ENTER:
1800 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
1801 break;
1802 case WindowManagerPolicy.TRANSIT_EXIT:
1803 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
1804 break;
1805 case WindowManagerPolicy.TRANSIT_SHOW:
1806 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
1807 break;
1808 case WindowManagerPolicy.TRANSIT_HIDE:
1809 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
1810 break;
1811 }
1812 if (attr >= 0) {
1813 a = loadAnimation(win.mAttrs, attr);
1814 }
1815 }
1816 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
1817 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
1818 + " mAnimation=" + win.mAnimation
1819 + " isEntrance=" + isEntrance);
1820 if (a != null) {
1821 if (DEBUG_ANIM) {
1822 RuntimeException e = new RuntimeException();
1823 e.fillInStackTrace();
1824 Log.v(TAG, "Loaded animation " + a + " for " + win, e);
1825 }
1826 win.setAnimation(a);
1827 win.mAnimationIsEntrance = isEntrance;
1828 }
1829 } else {
1830 win.clearAnimation();
1831 }
1832
1833 return win.mAnimation != null;
1834 }
1835
1836 private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
1837 int anim = 0;
1838 Context context = mContext;
1839 if (animAttr >= 0) {
1840 AttributeCache.Entry ent = getCachedAnimations(lp);
1841 if (ent != null) {
1842 context = ent.context;
1843 anim = ent.array.getResourceId(animAttr, 0);
1844 }
1845 }
1846 if (anim != 0) {
1847 return AnimationUtils.loadAnimation(context, anim);
1848 }
1849 return null;
1850 }
Romain Guy06882f82009-06-10 13:36:04 -07001851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 private boolean applyAnimationLocked(AppWindowToken wtoken,
1853 WindowManager.LayoutParams lp, int transit, boolean enter) {
1854 // Only apply an animation if the display isn't frozen. If it is
1855 // frozen, there is no reason to animate and it can cause strange
1856 // artifacts when we unfreeze the display if some different animation
1857 // is running.
1858 if (!mDisplayFrozen) {
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07001859 Animation a;
1860 if ((lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
1861 a = new FadeInOutAnimation(enter);
1862 if (DEBUG_ANIM) Log.v(TAG,
1863 "applying FadeInOutAnimation for a window in compatibility mode");
1864 } else {
1865 int animAttr = 0;
1866 switch (transit) {
1867 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
1868 animAttr = enter
1869 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
1870 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
1871 break;
1872 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
1873 animAttr = enter
1874 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
1875 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
1876 break;
1877 case WindowManagerPolicy.TRANSIT_TASK_OPEN:
1878 animAttr = enter
1879 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
1880 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
1881 break;
1882 case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
1883 animAttr = enter
1884 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
1885 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
1886 break;
1887 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
1888 animAttr = enter
1889 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
1890 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
1891 break;
1892 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
1893 animAttr = enter
1894 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
1895 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
1896 break;
1897 }
1898 a = loadAnimation(lp, animAttr);
1899 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
1900 + " anim=" + a
1901 + " animAttr=0x" + Integer.toHexString(animAttr)
1902 + " transit=" + transit);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 if (a != null) {
1905 if (DEBUG_ANIM) {
1906 RuntimeException e = new RuntimeException();
1907 e.fillInStackTrace();
1908 Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
1909 }
1910 wtoken.setAnimation(a);
1911 }
1912 } else {
1913 wtoken.clearAnimation();
1914 }
1915
1916 return wtoken.animation != null;
1917 }
1918
1919 // -------------------------------------------------------------
1920 // Application Window Tokens
1921 // -------------------------------------------------------------
1922
1923 public void validateAppTokens(List tokens) {
1924 int v = tokens.size()-1;
1925 int m = mAppTokens.size()-1;
1926 while (v >= 0 && m >= 0) {
1927 AppWindowToken wtoken = mAppTokens.get(m);
1928 if (wtoken.removed) {
1929 m--;
1930 continue;
1931 }
1932 if (tokens.get(v) != wtoken.token) {
1933 Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
1934 + " @ " + v + ", internal is " + wtoken.token + " @ " + m);
1935 }
1936 v--;
1937 m--;
1938 }
1939 while (v >= 0) {
1940 Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
1941 v--;
1942 }
1943 while (m >= 0) {
1944 AppWindowToken wtoken = mAppTokens.get(m);
1945 if (!wtoken.removed) {
1946 Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
1947 }
1948 m--;
1949 }
1950 }
1951
1952 boolean checkCallingPermission(String permission, String func) {
1953 // Quick check: if the calling permission is me, it's all okay.
1954 if (Binder.getCallingPid() == Process.myPid()) {
1955 return true;
1956 }
Romain Guy06882f82009-06-10 13:36:04 -07001957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 if (mContext.checkCallingPermission(permission)
1959 == PackageManager.PERMISSION_GRANTED) {
1960 return true;
1961 }
1962 String msg = "Permission Denial: " + func + " from pid="
1963 + Binder.getCallingPid()
1964 + ", uid=" + Binder.getCallingUid()
1965 + " requires " + permission;
1966 Log.w(TAG, msg);
1967 return false;
1968 }
Romain Guy06882f82009-06-10 13:36:04 -07001969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 AppWindowToken findAppWindowToken(IBinder token) {
1971 WindowToken wtoken = mTokenMap.get(token);
1972 if (wtoken == null) {
1973 return null;
1974 }
1975 return wtoken.appWindowToken;
1976 }
Romain Guy06882f82009-06-10 13:36:04 -07001977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 public void addWindowToken(IBinder token, int type) {
1979 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1980 "addWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001981 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 }
Romain Guy06882f82009-06-10 13:36:04 -07001983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 synchronized(mWindowMap) {
1985 WindowToken wtoken = mTokenMap.get(token);
1986 if (wtoken != null) {
1987 Log.w(TAG, "Attempted to add existing input method token: " + token);
1988 return;
1989 }
1990 wtoken = new WindowToken(token, type, true);
1991 mTokenMap.put(token, wtoken);
1992 mTokenList.add(wtoken);
1993 }
1994 }
Romain Guy06882f82009-06-10 13:36:04 -07001995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 public void removeWindowToken(IBinder token) {
1997 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1998 "removeWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001999 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
2002 final long origId = Binder.clearCallingIdentity();
2003 synchronized(mWindowMap) {
2004 WindowToken wtoken = mTokenMap.remove(token);
2005 mTokenList.remove(wtoken);
2006 if (wtoken != null) {
2007 boolean delayed = false;
2008 if (!wtoken.hidden) {
2009 wtoken.hidden = true;
Romain Guy06882f82009-06-10 13:36:04 -07002010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 final int N = wtoken.windows.size();
2012 boolean changed = false;
Romain Guy06882f82009-06-10 13:36:04 -07002013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 for (int i=0; i<N; i++) {
2015 WindowState win = wtoken.windows.get(i);
2016
2017 if (win.isAnimating()) {
2018 delayed = true;
2019 }
Romain Guy06882f82009-06-10 13:36:04 -07002020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 if (win.isVisibleNow()) {
2022 applyAnimationLocked(win,
2023 WindowManagerPolicy.TRANSIT_EXIT, false);
2024 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2025 KeyWaiter.RETURN_NOTHING);
2026 changed = true;
2027 }
2028 }
2029
2030 if (changed) {
2031 mLayoutNeeded = true;
2032 performLayoutAndPlaceSurfacesLocked();
2033 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2034 }
Romain Guy06882f82009-06-10 13:36:04 -07002035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 if (delayed) {
2037 mExitingTokens.add(wtoken);
2038 }
2039 }
Romain Guy06882f82009-06-10 13:36:04 -07002040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 } else {
2042 Log.w(TAG, "Attempted to remove non-existing token: " + token);
2043 }
2044 }
2045 Binder.restoreCallingIdentity(origId);
2046 }
2047
2048 public void addAppToken(int addPos, IApplicationToken token,
2049 int groupId, int requestedOrientation, boolean fullscreen) {
2050 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2051 "addAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002052 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 }
Romain Guy06882f82009-06-10 13:36:04 -07002054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 synchronized(mWindowMap) {
2056 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2057 if (wtoken != null) {
2058 Log.w(TAG, "Attempted to add existing app token: " + token);
2059 return;
2060 }
2061 wtoken = new AppWindowToken(token);
2062 wtoken.groupId = groupId;
2063 wtoken.appFullscreen = fullscreen;
2064 wtoken.requestedOrientation = requestedOrientation;
2065 mAppTokens.add(addPos, wtoken);
Dave Bortcfe65242009-04-09 14:51:04 -07002066 if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 mTokenMap.put(token.asBinder(), wtoken);
2068 mTokenList.add(wtoken);
Romain Guy06882f82009-06-10 13:36:04 -07002069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 // Application tokens start out hidden.
2071 wtoken.hidden = true;
2072 wtoken.hiddenRequested = true;
Romain Guy06882f82009-06-10 13:36:04 -07002073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002074 //dump();
2075 }
2076 }
Romain Guy06882f82009-06-10 13:36:04 -07002077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 public void setAppGroupId(IBinder token, int groupId) {
2079 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2080 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002081 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002082 }
2083
2084 synchronized(mWindowMap) {
2085 AppWindowToken wtoken = findAppWindowToken(token);
2086 if (wtoken == null) {
2087 Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
2088 return;
2089 }
2090 wtoken.groupId = groupId;
2091 }
2092 }
Romain Guy06882f82009-06-10 13:36:04 -07002093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002094 public int getOrientationFromWindowsLocked() {
2095 int pos = mWindows.size() - 1;
2096 while (pos >= 0) {
2097 WindowState wtoken = (WindowState) mWindows.get(pos);
2098 pos--;
2099 if (wtoken.mAppToken != null) {
2100 // We hit an application window. so the orientation will be determined by the
2101 // app window. No point in continuing further.
2102 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2103 }
2104 if (!wtoken.isVisibleLw()) {
2105 continue;
2106 }
2107 int req = wtoken.mAttrs.screenOrientation;
2108 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
2109 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
2110 continue;
2111 } else {
2112 return req;
2113 }
2114 }
2115 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2116 }
Romain Guy06882f82009-06-10 13:36:04 -07002117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 public int getOrientationFromAppTokensLocked() {
2119 int pos = mAppTokens.size() - 1;
2120 int curGroup = 0;
2121 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Owen Lin3413b892009-05-01 17:12:32 -07002122 boolean findingBehind = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 boolean haveGroup = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002124 boolean lastFullscreen = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 while (pos >= 0) {
2126 AppWindowToken wtoken = mAppTokens.get(pos);
2127 pos--;
Owen Lin3413b892009-05-01 17:12:32 -07002128 // if we're about to tear down this window and not seek for
2129 // the behind activity, don't use it for orientation
2130 if (!findingBehind
2131 && (!wtoken.hidden && wtoken.hiddenRequested)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002132 continue;
2133 }
2134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 if (!haveGroup) {
2136 // We ignore any hidden applications on the top.
2137 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
2138 continue;
2139 }
2140 haveGroup = true;
2141 curGroup = wtoken.groupId;
2142 lastOrientation = wtoken.requestedOrientation;
2143 } else if (curGroup != wtoken.groupId) {
2144 // If we have hit a new application group, and the bottom
2145 // of the previous group didn't explicitly say to use
The Android Open Source Project4df24232009-03-05 14:34:35 -08002146 // the orientation behind it, and the last app was
2147 // full screen, then we'll stick with the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 // user's orientation.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002149 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
2150 && lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 return lastOrientation;
2152 }
2153 }
2154 int or = wtoken.requestedOrientation;
Owen Lin3413b892009-05-01 17:12:32 -07002155 // If this application is fullscreen, and didn't explicitly say
2156 // to use the orientation behind it, then just take whatever
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 // orientation it has and ignores whatever is under it.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002158 lastFullscreen = wtoken.appFullscreen;
Romain Guy06882f82009-06-10 13:36:04 -07002159 if (lastFullscreen
Owen Lin3413b892009-05-01 17:12:32 -07002160 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 return or;
2162 }
2163 // If this application has requested an explicit orientation,
2164 // then use it.
2165 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
2166 or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
2167 or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
2168 or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
2169 or == ActivityInfo.SCREEN_ORIENTATION_USER) {
2170 return or;
2171 }
Owen Lin3413b892009-05-01 17:12:32 -07002172 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 }
2174 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2175 }
Romain Guy06882f82009-06-10 13:36:04 -07002176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 public Configuration updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002178 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002179 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2180 "updateOrientationFromAppTokens()")) {
2181 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
2182 }
2183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 Configuration config;
2185 long ident = Binder.clearCallingIdentity();
Dianne Hackborncfaef692009-06-15 14:24:44 -07002186 config = updateOrientationFromAppTokensUnchecked(currentConfig,
2187 freezeThisOneIfNeeded);
2188 Binder.restoreCallingIdentity(ident);
2189 return config;
2190 }
2191
2192 Configuration updateOrientationFromAppTokensUnchecked(
2193 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
2194 Configuration config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 synchronized(mWindowMap) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002196 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 }
2198 if (config != null) {
2199 mLayoutNeeded = true;
2200 performLayoutAndPlaceSurfacesLocked();
2201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 return config;
2203 }
Romain Guy06882f82009-06-10 13:36:04 -07002204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 /*
2206 * The orientation is computed from non-application windows first. If none of
2207 * the non-application windows specify orientation, the orientation is computed from
Romain Guy06882f82009-06-10 13:36:04 -07002208 * application tokens.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 * @see android.view.IWindowManager#updateOrientationFromAppTokens(
2210 * android.os.IBinder)
2211 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002212 Configuration updateOrientationFromAppTokensLocked(
The Android Open Source Project10592532009-03-18 17:39:46 -07002213 Configuration appConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 boolean changed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 long ident = Binder.clearCallingIdentity();
2216 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002217 int req = computeForcedAppOrientationLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 if (req != mForcedAppOrientation) {
2220 changed = true;
2221 mForcedAppOrientation = req;
2222 //send a message to Policy indicating orientation change to take
2223 //action like disabling/enabling sensors etc.,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002224 mPolicy.setCurrentOrientationLw(req);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 }
Romain Guy06882f82009-06-10 13:36:04 -07002226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 if (changed) {
2228 changed = setRotationUncheckedLocked(
Dianne Hackborn321ae682009-03-27 16:16:03 -07002229 WindowManagerPolicy.USE_LAST_ROTATION,
2230 mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002231 if (changed) {
2232 if (freezeThisOneIfNeeded != null) {
2233 AppWindowToken wtoken = findAppWindowToken(
2234 freezeThisOneIfNeeded);
2235 if (wtoken != null) {
2236 startAppFreezingScreenLocked(wtoken,
2237 ActivityInfo.CONFIG_ORIENTATION);
2238 }
2239 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07002240 return computeNewConfigurationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 }
2242 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002243
2244 // No obvious action we need to take, but if our current
2245 // state mismatches the activity maanager's, update it
2246 if (appConfig != null) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07002247 mTempConfiguration.setToDefaults();
2248 if (computeNewConfigurationLocked(mTempConfiguration)) {
2249 if (appConfig.diff(mTempConfiguration) != 0) {
2250 Log.i(TAG, "Config changed: " + mTempConfiguration);
2251 return new Configuration(mTempConfiguration);
2252 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002253 }
2254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 } finally {
2256 Binder.restoreCallingIdentity(ident);
2257 }
Romain Guy06882f82009-06-10 13:36:04 -07002258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 return null;
2260 }
Romain Guy06882f82009-06-10 13:36:04 -07002261
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002262 int computeForcedAppOrientationLocked() {
2263 int req = getOrientationFromWindowsLocked();
2264 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
2265 req = getOrientationFromAppTokensLocked();
2266 }
2267 return req;
2268 }
Romain Guy06882f82009-06-10 13:36:04 -07002269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
2271 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2272 "setAppOrientation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002273 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 }
Romain Guy06882f82009-06-10 13:36:04 -07002275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 synchronized(mWindowMap) {
2277 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2278 if (wtoken == null) {
2279 Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
2280 return;
2281 }
Romain Guy06882f82009-06-10 13:36:04 -07002282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 wtoken.requestedOrientation = requestedOrientation;
2284 }
2285 }
Romain Guy06882f82009-06-10 13:36:04 -07002286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002287 public int getAppOrientation(IApplicationToken token) {
2288 synchronized(mWindowMap) {
2289 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2290 if (wtoken == null) {
2291 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2292 }
Romain Guy06882f82009-06-10 13:36:04 -07002293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 return wtoken.requestedOrientation;
2295 }
2296 }
Romain Guy06882f82009-06-10 13:36:04 -07002297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 public void setFocusedApp(IBinder token, boolean moveFocusNow) {
2299 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2300 "setFocusedApp()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002301 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002302 }
2303
2304 synchronized(mWindowMap) {
2305 boolean changed = false;
2306 if (token == null) {
2307 if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
2308 changed = mFocusedApp != null;
2309 mFocusedApp = null;
2310 mKeyWaiter.tickle();
2311 } else {
2312 AppWindowToken newFocus = findAppWindowToken(token);
2313 if (newFocus == null) {
2314 Log.w(TAG, "Attempted to set focus to non-existing app token: " + token);
2315 return;
2316 }
2317 changed = mFocusedApp != newFocus;
2318 mFocusedApp = newFocus;
2319 if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp);
2320 mKeyWaiter.tickle();
2321 }
2322
2323 if (moveFocusNow && changed) {
2324 final long origId = Binder.clearCallingIdentity();
2325 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2326 Binder.restoreCallingIdentity(origId);
2327 }
2328 }
2329 }
2330
2331 public void prepareAppTransition(int transit) {
2332 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2333 "prepareAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002334 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002335 }
Romain Guy06882f82009-06-10 13:36:04 -07002336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002337 synchronized(mWindowMap) {
2338 if (DEBUG_APP_TRANSITIONS) Log.v(
2339 TAG, "Prepare app transition: transit=" + transit
2340 + " mNextAppTransition=" + mNextAppTransition);
2341 if (!mDisplayFrozen) {
2342 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
2343 mNextAppTransition = transit;
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002344 } else if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
2345 && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
2346 // Opening a new task always supersedes a close for the anim.
2347 mNextAppTransition = transit;
2348 } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2349 && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
2350 // Opening a new activity always supersedes a close for the anim.
2351 mNextAppTransition = transit;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002352 }
2353 mAppTransitionReady = false;
2354 mAppTransitionTimeout = false;
2355 mStartingIconInTransition = false;
2356 mSkipAppTransitionAnimation = false;
2357 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2358 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
2359 5000);
2360 }
2361 }
2362 }
2363
2364 public int getPendingAppTransition() {
2365 return mNextAppTransition;
2366 }
Romain Guy06882f82009-06-10 13:36:04 -07002367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002368 public void executeAppTransition() {
2369 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2370 "executeAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002371 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002372 }
Romain Guy06882f82009-06-10 13:36:04 -07002373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 synchronized(mWindowMap) {
2375 if (DEBUG_APP_TRANSITIONS) Log.v(
2376 TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
2377 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2378 mAppTransitionReady = true;
2379 final long origId = Binder.clearCallingIdentity();
2380 performLayoutAndPlaceSurfacesLocked();
2381 Binder.restoreCallingIdentity(origId);
2382 }
2383 }
2384 }
2385
2386 public void setAppStartingWindow(IBinder token, String pkg,
2387 int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
2388 IBinder transferFrom, boolean createIfNeeded) {
2389 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2390 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002391 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 }
2393
2394 synchronized(mWindowMap) {
2395 if (DEBUG_STARTING_WINDOW) Log.v(
2396 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
2397 + " transferFrom=" + transferFrom);
Romain Guy06882f82009-06-10 13:36:04 -07002398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 AppWindowToken wtoken = findAppWindowToken(token);
2400 if (wtoken == null) {
2401 Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
2402 return;
2403 }
2404
2405 // If the display is frozen, we won't do anything until the
2406 // actual window is displayed so there is no reason to put in
2407 // the starting window.
2408 if (mDisplayFrozen) {
2409 return;
2410 }
Romain Guy06882f82009-06-10 13:36:04 -07002411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 if (wtoken.startingData != null) {
2413 return;
2414 }
Romain Guy06882f82009-06-10 13:36:04 -07002415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002416 if (transferFrom != null) {
2417 AppWindowToken ttoken = findAppWindowToken(transferFrom);
2418 if (ttoken != null) {
2419 WindowState startingWindow = ttoken.startingWindow;
2420 if (startingWindow != null) {
2421 if (mStartingIconInTransition) {
2422 // In this case, the starting icon has already
2423 // been displayed, so start letting windows get
2424 // shown immediately without any more transitions.
2425 mSkipAppTransitionAnimation = true;
2426 }
2427 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2428 "Moving existing starting from " + ttoken
2429 + " to " + wtoken);
2430 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07002431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002432 // Transfer the starting window over to the new
2433 // token.
2434 wtoken.startingData = ttoken.startingData;
2435 wtoken.startingView = ttoken.startingView;
2436 wtoken.startingWindow = startingWindow;
2437 ttoken.startingData = null;
2438 ttoken.startingView = null;
2439 ttoken.startingWindow = null;
2440 ttoken.startingMoved = true;
2441 startingWindow.mToken = wtoken;
Dianne Hackbornef49c572009-03-24 19:27:32 -07002442 startingWindow.mRootToken = wtoken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 startingWindow.mAppToken = wtoken;
2444 mWindows.remove(startingWindow);
2445 ttoken.windows.remove(startingWindow);
2446 ttoken.allAppWindows.remove(startingWindow);
2447 addWindowToListInOrderLocked(startingWindow, true);
2448 wtoken.allAppWindows.add(startingWindow);
Romain Guy06882f82009-06-10 13:36:04 -07002449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450 // Propagate other interesting state between the
2451 // tokens. If the old token is displayed, we should
2452 // immediately force the new one to be displayed. If
2453 // it is animating, we need to move that animation to
2454 // the new one.
2455 if (ttoken.allDrawn) {
2456 wtoken.allDrawn = true;
2457 }
2458 if (ttoken.firstWindowDrawn) {
2459 wtoken.firstWindowDrawn = true;
2460 }
2461 if (!ttoken.hidden) {
2462 wtoken.hidden = false;
2463 wtoken.hiddenRequested = false;
2464 wtoken.willBeHidden = false;
2465 }
2466 if (wtoken.clientHidden != ttoken.clientHidden) {
2467 wtoken.clientHidden = ttoken.clientHidden;
2468 wtoken.sendAppVisibilityToClients();
2469 }
2470 if (ttoken.animation != null) {
2471 wtoken.animation = ttoken.animation;
2472 wtoken.animating = ttoken.animating;
2473 wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
2474 ttoken.animation = null;
2475 ttoken.animLayerAdjustment = 0;
2476 wtoken.updateLayers();
2477 ttoken.updateLayers();
2478 }
Romain Guy06882f82009-06-10 13:36:04 -07002479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002481 mLayoutNeeded = true;
2482 performLayoutAndPlaceSurfacesLocked();
2483 Binder.restoreCallingIdentity(origId);
2484 return;
2485 } else if (ttoken.startingData != null) {
2486 // The previous app was getting ready to show a
2487 // starting window, but hasn't yet done so. Steal it!
2488 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2489 "Moving pending starting from " + ttoken
2490 + " to " + wtoken);
2491 wtoken.startingData = ttoken.startingData;
2492 ttoken.startingData = null;
2493 ttoken.startingMoved = true;
2494 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2495 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2496 // want to process the message ASAP, before any other queued
2497 // messages.
2498 mH.sendMessageAtFrontOfQueue(m);
2499 return;
2500 }
2501 }
2502 }
2503
2504 // There is no existing starting window, and the caller doesn't
2505 // want us to create one, so that's it!
2506 if (!createIfNeeded) {
2507 return;
2508 }
Romain Guy06882f82009-06-10 13:36:04 -07002509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 mStartingIconInTransition = true;
2511 wtoken.startingData = new StartingData(
2512 pkg, theme, nonLocalizedLabel,
2513 labelRes, icon);
2514 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2515 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2516 // want to process the message ASAP, before any other queued
2517 // messages.
2518 mH.sendMessageAtFrontOfQueue(m);
2519 }
2520 }
2521
2522 public void setAppWillBeHidden(IBinder token) {
2523 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2524 "setAppWillBeHidden()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002525 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 }
2527
2528 AppWindowToken wtoken;
2529
2530 synchronized(mWindowMap) {
2531 wtoken = findAppWindowToken(token);
2532 if (wtoken == null) {
2533 Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
2534 return;
2535 }
2536 wtoken.willBeHidden = true;
2537 }
2538 }
Romain Guy06882f82009-06-10 13:36:04 -07002539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
2541 boolean visible, int transit, boolean performLayout) {
2542 boolean delayed = false;
2543
2544 if (wtoken.clientHidden == visible) {
2545 wtoken.clientHidden = !visible;
2546 wtoken.sendAppVisibilityToClients();
2547 }
Romain Guy06882f82009-06-10 13:36:04 -07002548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 wtoken.willBeHidden = false;
2550 if (wtoken.hidden == visible) {
2551 final int N = wtoken.allAppWindows.size();
2552 boolean changed = false;
2553 if (DEBUG_APP_TRANSITIONS) Log.v(
2554 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
2555 + " performLayout=" + performLayout);
Romain Guy06882f82009-06-10 13:36:04 -07002556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 boolean runningAppAnimation = false;
Romain Guy06882f82009-06-10 13:36:04 -07002558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 if (transit != WindowManagerPolicy.TRANSIT_NONE) {
2560 if (wtoken.animation == sDummyAnimation) {
2561 wtoken.animation = null;
2562 }
2563 applyAnimationLocked(wtoken, lp, transit, visible);
2564 changed = true;
2565 if (wtoken.animation != null) {
2566 delayed = runningAppAnimation = true;
2567 }
2568 }
Romain Guy06882f82009-06-10 13:36:04 -07002569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 for (int i=0; i<N; i++) {
2571 WindowState win = wtoken.allAppWindows.get(i);
2572 if (win == wtoken.startingWindow) {
2573 continue;
2574 }
2575
2576 if (win.isAnimating()) {
2577 delayed = true;
2578 }
Romain Guy06882f82009-06-10 13:36:04 -07002579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
2581 //win.dump(" ");
2582 if (visible) {
2583 if (!win.isVisibleNow()) {
2584 if (!runningAppAnimation) {
2585 applyAnimationLocked(win,
2586 WindowManagerPolicy.TRANSIT_ENTER, true);
2587 }
2588 changed = true;
2589 }
2590 } else if (win.isVisibleNow()) {
2591 if (!runningAppAnimation) {
2592 applyAnimationLocked(win,
2593 WindowManagerPolicy.TRANSIT_EXIT, false);
2594 }
2595 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2596 KeyWaiter.RETURN_NOTHING);
2597 changed = true;
2598 }
2599 }
2600
2601 wtoken.hidden = wtoken.hiddenRequested = !visible;
2602 if (!visible) {
2603 unsetAppFreezingScreenLocked(wtoken, true, true);
2604 } else {
2605 // If we are being set visible, and the starting window is
2606 // not yet displayed, then make sure it doesn't get displayed.
2607 WindowState swin = wtoken.startingWindow;
2608 if (swin != null && (swin.mDrawPending
2609 || swin.mCommitDrawPending)) {
2610 swin.mPolicyVisibility = false;
2611 swin.mPolicyVisibilityAfterAnim = false;
2612 }
2613 }
Romain Guy06882f82009-06-10 13:36:04 -07002614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002615 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
2616 + ": hidden=" + wtoken.hidden + " hiddenRequested="
2617 + wtoken.hiddenRequested);
Romain Guy06882f82009-06-10 13:36:04 -07002618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002619 if (changed && performLayout) {
2620 mLayoutNeeded = true;
2621 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002622 performLayoutAndPlaceSurfacesLocked();
2623 }
2624 }
2625
2626 if (wtoken.animation != null) {
2627 delayed = true;
2628 }
Romain Guy06882f82009-06-10 13:36:04 -07002629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002630 return delayed;
2631 }
2632
2633 public void setAppVisibility(IBinder token, boolean visible) {
2634 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2635 "setAppVisibility()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002636 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002637 }
2638
2639 AppWindowToken wtoken;
2640
2641 synchronized(mWindowMap) {
2642 wtoken = findAppWindowToken(token);
2643 if (wtoken == null) {
2644 Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
2645 return;
2646 }
2647
2648 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
2649 RuntimeException e = new RuntimeException();
2650 e.fillInStackTrace();
2651 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
2652 + "): mNextAppTransition=" + mNextAppTransition
2653 + " hidden=" + wtoken.hidden
2654 + " hiddenRequested=" + wtoken.hiddenRequested, e);
2655 }
Romain Guy06882f82009-06-10 13:36:04 -07002656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 // If we are preparing an app transition, then delay changing
2658 // the visibility of this token until we execute that transition.
2659 if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2660 // Already in requested state, don't do anything more.
2661 if (wtoken.hiddenRequested != visible) {
2662 return;
2663 }
2664 wtoken.hiddenRequested = !visible;
Romain Guy06882f82009-06-10 13:36:04 -07002665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002666 if (DEBUG_APP_TRANSITIONS) Log.v(
2667 TAG, "Setting dummy animation on: " + wtoken);
2668 wtoken.setDummyAnimation();
2669 mOpeningApps.remove(wtoken);
2670 mClosingApps.remove(wtoken);
2671 wtoken.inPendingTransaction = true;
2672 if (visible) {
2673 mOpeningApps.add(wtoken);
2674 wtoken.allDrawn = false;
2675 wtoken.startingDisplayed = false;
2676 wtoken.startingMoved = false;
Romain Guy06882f82009-06-10 13:36:04 -07002677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 if (wtoken.clientHidden) {
2679 // In the case where we are making an app visible
2680 // but holding off for a transition, we still need
2681 // to tell the client to make its windows visible so
2682 // they get drawn. Otherwise, we will wait on
2683 // performing the transition until all windows have
2684 // been drawn, they never will be, and we are sad.
2685 wtoken.clientHidden = false;
2686 wtoken.sendAppVisibilityToClients();
2687 }
2688 } else {
2689 mClosingApps.add(wtoken);
2690 }
2691 return;
2692 }
Romain Guy06882f82009-06-10 13:36:04 -07002693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 final long origId = Binder.clearCallingIdentity();
2695 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
2696 wtoken.updateReportedVisibilityLocked();
2697 Binder.restoreCallingIdentity(origId);
2698 }
2699 }
2700
2701 void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
2702 boolean unfreezeSurfaceNow, boolean force) {
2703 if (wtoken.freezingScreen) {
2704 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
2705 + " force=" + force);
2706 final int N = wtoken.allAppWindows.size();
2707 boolean unfrozeWindows = false;
2708 for (int i=0; i<N; i++) {
2709 WindowState w = wtoken.allAppWindows.get(i);
2710 if (w.mAppFreezing) {
2711 w.mAppFreezing = false;
2712 if (w.mSurface != null && !w.mOrientationChanging) {
2713 w.mOrientationChanging = true;
2714 }
2715 unfrozeWindows = true;
2716 }
2717 }
2718 if (force || unfrozeWindows) {
2719 if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
2720 wtoken.freezingScreen = false;
2721 mAppsFreezingScreen--;
2722 }
2723 if (unfreezeSurfaceNow) {
2724 if (unfrozeWindows) {
2725 mLayoutNeeded = true;
2726 performLayoutAndPlaceSurfacesLocked();
2727 }
2728 if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
2729 stopFreezingDisplayLocked();
2730 }
2731 }
2732 }
2733 }
Romain Guy06882f82009-06-10 13:36:04 -07002734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735 public void startAppFreezingScreenLocked(AppWindowToken wtoken,
2736 int configChanges) {
2737 if (DEBUG_ORIENTATION) {
2738 RuntimeException e = new RuntimeException();
2739 e.fillInStackTrace();
2740 Log.i(TAG, "Set freezing of " + wtoken.appToken
2741 + ": hidden=" + wtoken.hidden + " freezing="
2742 + wtoken.freezingScreen, e);
2743 }
2744 if (!wtoken.hiddenRequested) {
2745 if (!wtoken.freezingScreen) {
2746 wtoken.freezingScreen = true;
2747 mAppsFreezingScreen++;
2748 if (mAppsFreezingScreen == 1) {
2749 startFreezingDisplayLocked();
2750 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
2751 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
2752 5000);
2753 }
2754 }
2755 final int N = wtoken.allAppWindows.size();
2756 for (int i=0; i<N; i++) {
2757 WindowState w = wtoken.allAppWindows.get(i);
2758 w.mAppFreezing = true;
2759 }
2760 }
2761 }
Romain Guy06882f82009-06-10 13:36:04 -07002762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 public void startAppFreezingScreen(IBinder token, int configChanges) {
2764 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2765 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002766 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 }
2768
2769 synchronized(mWindowMap) {
2770 if (configChanges == 0 && !mDisplayFrozen) {
2771 if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
2772 return;
2773 }
Romain Guy06882f82009-06-10 13:36:04 -07002774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 AppWindowToken wtoken = findAppWindowToken(token);
2776 if (wtoken == null || wtoken.appToken == null) {
2777 Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
2778 return;
2779 }
2780 final long origId = Binder.clearCallingIdentity();
2781 startAppFreezingScreenLocked(wtoken, configChanges);
2782 Binder.restoreCallingIdentity(origId);
2783 }
2784 }
Romain Guy06882f82009-06-10 13:36:04 -07002785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 public void stopAppFreezingScreen(IBinder token, boolean force) {
2787 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2788 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002789 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 }
2791
2792 synchronized(mWindowMap) {
2793 AppWindowToken wtoken = findAppWindowToken(token);
2794 if (wtoken == null || wtoken.appToken == null) {
2795 return;
2796 }
2797 final long origId = Binder.clearCallingIdentity();
2798 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
2799 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
2800 unsetAppFreezingScreenLocked(wtoken, true, force);
2801 Binder.restoreCallingIdentity(origId);
2802 }
2803 }
Romain Guy06882f82009-06-10 13:36:04 -07002804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002805 public void removeAppToken(IBinder token) {
2806 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2807 "removeAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002808 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002809 }
2810
2811 AppWindowToken wtoken = null;
2812 AppWindowToken startingToken = null;
2813 boolean delayed = false;
2814
2815 final long origId = Binder.clearCallingIdentity();
2816 synchronized(mWindowMap) {
2817 WindowToken basewtoken = mTokenMap.remove(token);
2818 mTokenList.remove(basewtoken);
2819 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
2820 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
2821 delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
2822 wtoken.inPendingTransaction = false;
2823 mOpeningApps.remove(wtoken);
2824 if (mClosingApps.contains(wtoken)) {
2825 delayed = true;
2826 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2827 mClosingApps.add(wtoken);
2828 delayed = true;
2829 }
2830 if (DEBUG_APP_TRANSITIONS) Log.v(
2831 TAG, "Removing app " + wtoken + " delayed=" + delayed
2832 + " animation=" + wtoken.animation
2833 + " animating=" + wtoken.animating);
2834 if (delayed) {
2835 // set the token aside because it has an active animation to be finished
2836 mExitingAppTokens.add(wtoken);
2837 }
2838 mAppTokens.remove(wtoken);
2839 wtoken.removed = true;
2840 if (wtoken.startingData != null) {
2841 startingToken = wtoken;
2842 }
2843 unsetAppFreezingScreenLocked(wtoken, true, true);
2844 if (mFocusedApp == wtoken) {
2845 if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
2846 mFocusedApp = null;
2847 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2848 mKeyWaiter.tickle();
2849 }
2850 } else {
2851 Log.w(TAG, "Attempted to remove non-existing app token: " + token);
2852 }
Romain Guy06882f82009-06-10 13:36:04 -07002853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 if (!delayed && wtoken != null) {
2855 wtoken.updateReportedVisibilityLocked();
2856 }
2857 }
2858 Binder.restoreCallingIdentity(origId);
2859
2860 if (startingToken != null) {
2861 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
2862 + startingToken + ": app token removed");
2863 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
2864 mH.sendMessage(m);
2865 }
2866 }
2867
2868 private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
2869 final int NW = token.windows.size();
2870 for (int i=0; i<NW; i++) {
2871 WindowState win = token.windows.get(i);
2872 mWindows.remove(win);
2873 int j = win.mChildWindows.size();
2874 while (j > 0) {
2875 j--;
2876 mWindows.remove(win.mChildWindows.get(j));
2877 }
2878 }
2879 return NW > 0;
2880 }
2881
2882 void dumpAppTokensLocked() {
2883 for (int i=mAppTokens.size()-1; i>=0; i--) {
2884 Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
2885 }
2886 }
Romain Guy06882f82009-06-10 13:36:04 -07002887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002888 void dumpWindowsLocked() {
2889 for (int i=mWindows.size()-1; i>=0; i--) {
2890 Log.v(TAG, " #" + i + ": " + mWindows.get(i));
2891 }
2892 }
Romain Guy06882f82009-06-10 13:36:04 -07002893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002894 private int findWindowOffsetLocked(int tokenPos) {
2895 final int NW = mWindows.size();
2896
2897 if (tokenPos >= mAppTokens.size()) {
2898 int i = NW;
2899 while (i > 0) {
2900 i--;
2901 WindowState win = (WindowState)mWindows.get(i);
2902 if (win.getAppToken() != null) {
2903 return i+1;
2904 }
2905 }
2906 }
2907
2908 while (tokenPos > 0) {
2909 // Find the first app token below the new position that has
2910 // a window displayed.
2911 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
2912 if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
2913 + tokenPos + " -- " + wtoken.token);
2914 int i = wtoken.windows.size();
2915 while (i > 0) {
2916 i--;
2917 WindowState win = wtoken.windows.get(i);
2918 int j = win.mChildWindows.size();
2919 while (j > 0) {
2920 j--;
2921 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2922 if (cwin.mSubLayer >= 0 ) {
2923 for (int pos=NW-1; pos>=0; pos--) {
2924 if (mWindows.get(pos) == cwin) {
2925 if (DEBUG_REORDER) Log.v(TAG,
2926 "Found child win @" + (pos+1));
2927 return pos+1;
2928 }
2929 }
2930 }
2931 }
2932 for (int pos=NW-1; pos>=0; pos--) {
2933 if (mWindows.get(pos) == win) {
2934 if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
2935 return pos+1;
2936 }
2937 }
2938 }
2939 tokenPos--;
2940 }
2941
2942 return 0;
2943 }
2944
2945 private final int reAddWindowLocked(int index, WindowState win) {
2946 final int NCW = win.mChildWindows.size();
2947 boolean added = false;
2948 for (int j=0; j<NCW; j++) {
2949 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2950 if (!added && cwin.mSubLayer >= 0) {
2951 mWindows.add(index, win);
2952 index++;
2953 added = true;
2954 }
2955 mWindows.add(index, cwin);
2956 index++;
2957 }
2958 if (!added) {
2959 mWindows.add(index, win);
2960 index++;
2961 }
2962 return index;
2963 }
Romain Guy06882f82009-06-10 13:36:04 -07002964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002965 private final int reAddAppWindowsLocked(int index, WindowToken token) {
2966 final int NW = token.windows.size();
2967 for (int i=0; i<NW; i++) {
2968 index = reAddWindowLocked(index, token.windows.get(i));
2969 }
2970 return index;
2971 }
2972
2973 public void moveAppToken(int index, IBinder token) {
2974 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2975 "moveAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002976 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 }
2978
2979 synchronized(mWindowMap) {
2980 if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
2981 if (DEBUG_REORDER) dumpAppTokensLocked();
2982 final AppWindowToken wtoken = findAppWindowToken(token);
2983 if (wtoken == null || !mAppTokens.remove(wtoken)) {
2984 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
2985 + token + " (" + wtoken + ")");
2986 return;
2987 }
2988 mAppTokens.add(index, wtoken);
2989 if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
2990 if (DEBUG_REORDER) dumpAppTokensLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002992 final long origId = Binder.clearCallingIdentity();
2993 if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
2994 if (DEBUG_REORDER) dumpWindowsLocked();
2995 if (tmpRemoveAppWindowsLocked(wtoken)) {
2996 if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:");
2997 if (DEBUG_REORDER) dumpWindowsLocked();
2998 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
2999 if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
3000 if (DEBUG_REORDER) dumpWindowsLocked();
3001 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 mLayoutNeeded = true;
3003 performLayoutAndPlaceSurfacesLocked();
3004 }
3005 Binder.restoreCallingIdentity(origId);
3006 }
3007 }
3008
3009 private void removeAppTokensLocked(List<IBinder> tokens) {
3010 // XXX This should be done more efficiently!
3011 // (take advantage of the fact that both lists should be
3012 // ordered in the same way.)
3013 int N = tokens.size();
3014 for (int i=0; i<N; i++) {
3015 IBinder token = tokens.get(i);
3016 final AppWindowToken wtoken = findAppWindowToken(token);
3017 if (!mAppTokens.remove(wtoken)) {
3018 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
3019 + token + " (" + wtoken + ")");
3020 i--;
3021 N--;
3022 }
3023 }
3024 }
3025
3026 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
3027 // First remove all of the windows from the list.
3028 final int N = tokens.size();
3029 int i;
3030 for (i=0; i<N; i++) {
3031 WindowToken token = mTokenMap.get(tokens.get(i));
3032 if (token != null) {
3033 tmpRemoveAppWindowsLocked(token);
3034 }
3035 }
3036
3037 // Where to start adding?
3038 int pos = findWindowOffsetLocked(tokenPos);
3039
3040 // And now add them back at the correct place.
3041 for (i=0; i<N; i++) {
3042 WindowToken token = mTokenMap.get(tokens.get(i));
3043 if (token != null) {
3044 pos = reAddAppWindowsLocked(pos, token);
3045 }
3046 }
3047
3048 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003049 mLayoutNeeded = true;
3050 performLayoutAndPlaceSurfacesLocked();
3051
3052 //dump();
3053 }
3054
3055 public void moveAppTokensToTop(List<IBinder> tokens) {
3056 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3057 "moveAppTokensToTop()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003058 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 }
3060
3061 final long origId = Binder.clearCallingIdentity();
3062 synchronized(mWindowMap) {
3063 removeAppTokensLocked(tokens);
3064 final int N = tokens.size();
3065 for (int i=0; i<N; i++) {
3066 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3067 if (wt != null) {
3068 mAppTokens.add(wt);
3069 }
3070 }
3071 moveAppWindowsLocked(tokens, mAppTokens.size());
3072 }
3073 Binder.restoreCallingIdentity(origId);
3074 }
3075
3076 public void moveAppTokensToBottom(List<IBinder> tokens) {
3077 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3078 "moveAppTokensToBottom()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003079 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003080 }
3081
3082 final long origId = Binder.clearCallingIdentity();
3083 synchronized(mWindowMap) {
3084 removeAppTokensLocked(tokens);
3085 final int N = tokens.size();
3086 int pos = 0;
3087 for (int i=0; i<N; i++) {
3088 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3089 if (wt != null) {
3090 mAppTokens.add(pos, wt);
3091 pos++;
3092 }
3093 }
3094 moveAppWindowsLocked(tokens, 0);
3095 }
3096 Binder.restoreCallingIdentity(origId);
3097 }
3098
3099 // -------------------------------------------------------------
3100 // Misc IWindowSession methods
3101 // -------------------------------------------------------------
Romain Guy06882f82009-06-10 13:36:04 -07003102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 public void disableKeyguard(IBinder token, String tag) {
3104 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3105 != PackageManager.PERMISSION_GRANTED) {
3106 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3107 }
3108 mKeyguardDisabled.acquire(token, tag);
3109 }
3110
3111 public void reenableKeyguard(IBinder token) {
3112 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3113 != PackageManager.PERMISSION_GRANTED) {
3114 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3115 }
3116 synchronized (mKeyguardDisabled) {
3117 mKeyguardDisabled.release(token);
3118
3119 if (!mKeyguardDisabled.isAcquired()) {
3120 // if we are the last one to reenable the keyguard wait until
3121 // we have actaully finished reenabling until returning
3122 mWaitingUntilKeyguardReenabled = true;
3123 while (mWaitingUntilKeyguardReenabled) {
3124 try {
3125 mKeyguardDisabled.wait();
3126 } catch (InterruptedException e) {
3127 Thread.currentThread().interrupt();
3128 }
3129 }
3130 }
3131 }
3132 }
3133
3134 /**
3135 * @see android.app.KeyguardManager#exitKeyguardSecurely
3136 */
3137 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
3138 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3139 != PackageManager.PERMISSION_GRANTED) {
3140 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3141 }
3142 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
3143 public void onKeyguardExitResult(boolean success) {
3144 try {
3145 callback.onKeyguardExitResult(success);
3146 } catch (RemoteException e) {
3147 // Client has died, we don't care.
3148 }
3149 }
3150 });
3151 }
3152
3153 public boolean inKeyguardRestrictedInputMode() {
3154 return mPolicy.inKeyguardRestrictedKeyInputMode();
3155 }
Romain Guy06882f82009-06-10 13:36:04 -07003156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 static float fixScale(float scale) {
3158 if (scale < 0) scale = 0;
3159 else if (scale > 20) scale = 20;
3160 return Math.abs(scale);
3161 }
Romain Guy06882f82009-06-10 13:36:04 -07003162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 public void setAnimationScale(int which, float scale) {
3164 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3165 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003166 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 }
3168
3169 if (scale < 0) scale = 0;
3170 else if (scale > 20) scale = 20;
3171 scale = Math.abs(scale);
3172 switch (which) {
3173 case 0: mWindowAnimationScale = fixScale(scale); break;
3174 case 1: mTransitionAnimationScale = fixScale(scale); break;
3175 }
Romain Guy06882f82009-06-10 13:36:04 -07003176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 // Persist setting
3178 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3179 }
Romain Guy06882f82009-06-10 13:36:04 -07003180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 public void setAnimationScales(float[] scales) {
3182 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3183 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003184 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 }
3186
3187 if (scales != null) {
3188 if (scales.length >= 1) {
3189 mWindowAnimationScale = fixScale(scales[0]);
3190 }
3191 if (scales.length >= 2) {
3192 mTransitionAnimationScale = fixScale(scales[1]);
3193 }
3194 }
Romain Guy06882f82009-06-10 13:36:04 -07003195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 // Persist setting
3197 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3198 }
Romain Guy06882f82009-06-10 13:36:04 -07003199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 public float getAnimationScale(int which) {
3201 switch (which) {
3202 case 0: return mWindowAnimationScale;
3203 case 1: return mTransitionAnimationScale;
3204 }
3205 return 0;
3206 }
Romain Guy06882f82009-06-10 13:36:04 -07003207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 public float[] getAnimationScales() {
3209 return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
3210 }
Romain Guy06882f82009-06-10 13:36:04 -07003211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 public int getSwitchState(int sw) {
3213 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3214 "getSwitchState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003215 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
3217 return KeyInputQueue.getSwitchState(sw);
3218 }
Romain Guy06882f82009-06-10 13:36:04 -07003219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 public int getSwitchStateForDevice(int devid, int sw) {
3221 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3222 "getSwitchStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003223 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 }
3225 return KeyInputQueue.getSwitchState(devid, sw);
3226 }
Romain Guy06882f82009-06-10 13:36:04 -07003227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 public int getScancodeState(int sw) {
3229 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3230 "getScancodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003231 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 }
3233 return KeyInputQueue.getScancodeState(sw);
3234 }
Romain Guy06882f82009-06-10 13:36:04 -07003235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 public int getScancodeStateForDevice(int devid, int sw) {
3237 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3238 "getScancodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003239 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 }
3241 return KeyInputQueue.getScancodeState(devid, sw);
3242 }
Romain Guy06882f82009-06-10 13:36:04 -07003243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 public int getKeycodeState(int sw) {
3245 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3246 "getKeycodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003247 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 }
3249 return KeyInputQueue.getKeycodeState(sw);
3250 }
Romain Guy06882f82009-06-10 13:36:04 -07003251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 public int getKeycodeStateForDevice(int devid, int sw) {
3253 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3254 "getKeycodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003255 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 }
3257 return KeyInputQueue.getKeycodeState(devid, sw);
3258 }
Romain Guy06882f82009-06-10 13:36:04 -07003259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
3261 return KeyInputQueue.hasKeys(keycodes, keyExists);
3262 }
Romain Guy06882f82009-06-10 13:36:04 -07003263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 public void enableScreenAfterBoot() {
3265 synchronized(mWindowMap) {
3266 if (mSystemBooted) {
3267 return;
3268 }
3269 mSystemBooted = true;
3270 }
Romain Guy06882f82009-06-10 13:36:04 -07003271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 performEnableScreen();
3273 }
Romain Guy06882f82009-06-10 13:36:04 -07003274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 public void enableScreenIfNeededLocked() {
3276 if (mDisplayEnabled) {
3277 return;
3278 }
3279 if (!mSystemBooted) {
3280 return;
3281 }
3282 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
3283 }
Romain Guy06882f82009-06-10 13:36:04 -07003284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 public void performEnableScreen() {
3286 synchronized(mWindowMap) {
3287 if (mDisplayEnabled) {
3288 return;
3289 }
3290 if (!mSystemBooted) {
3291 return;
3292 }
Romain Guy06882f82009-06-10 13:36:04 -07003293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 // Don't enable the screen until all existing windows
3295 // have been drawn.
3296 final int N = mWindows.size();
3297 for (int i=0; i<N; i++) {
3298 WindowState w = (WindowState)mWindows.get(i);
3299 if (w.isVisibleLw() && !w.isDisplayedLw()) {
3300 return;
3301 }
3302 }
Romain Guy06882f82009-06-10 13:36:04 -07003303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 mDisplayEnabled = true;
3305 if (false) {
3306 Log.i(TAG, "ENABLING SCREEN!");
3307 StringWriter sw = new StringWriter();
3308 PrintWriter pw = new PrintWriter(sw);
3309 this.dump(null, pw, null);
3310 Log.i(TAG, sw.toString());
3311 }
3312 try {
3313 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
3314 if (surfaceFlinger != null) {
3315 //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
3316 Parcel data = Parcel.obtain();
3317 data.writeInterfaceToken("android.ui.ISurfaceComposer");
3318 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
3319 data, null, 0);
3320 data.recycle();
3321 }
3322 } catch (RemoteException ex) {
3323 Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
3324 }
3325 }
Romain Guy06882f82009-06-10 13:36:04 -07003326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 mPolicy.enableScreenAfterBoot();
Romain Guy06882f82009-06-10 13:36:04 -07003328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 // Make sure the last requested orientation has been applied.
Dianne Hackborn321ae682009-03-27 16:16:03 -07003330 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
3331 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003332 }
Romain Guy06882f82009-06-10 13:36:04 -07003333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 public void setInTouchMode(boolean mode) {
3335 synchronized(mWindowMap) {
3336 mInTouchMode = mode;
3337 }
3338 }
3339
Romain Guy06882f82009-06-10 13:36:04 -07003340 public void setRotation(int rotation,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003341 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003343 "setRotation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003344 throw new SecurityException("Requires SET_ORIENTATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345 }
3346
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003347 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003348 }
Romain Guy06882f82009-06-10 13:36:04 -07003349
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003350 public void setRotationUnchecked(int rotation,
3351 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 if(DEBUG_ORIENTATION) Log.v(TAG,
3353 "alwaysSendConfiguration set to "+alwaysSendConfiguration);
Romain Guy06882f82009-06-10 13:36:04 -07003354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 long origId = Binder.clearCallingIdentity();
3356 boolean changed;
3357 synchronized(mWindowMap) {
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003358 changed = setRotationUncheckedLocked(rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 }
Romain Guy06882f82009-06-10 13:36:04 -07003360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 if (changed) {
3362 sendNewConfiguration();
3363 synchronized(mWindowMap) {
3364 mLayoutNeeded = true;
3365 performLayoutAndPlaceSurfacesLocked();
3366 }
3367 } else if (alwaysSendConfiguration) {
3368 //update configuration ignoring orientation change
3369 sendNewConfiguration();
3370 }
Romain Guy06882f82009-06-10 13:36:04 -07003371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 Binder.restoreCallingIdentity(origId);
3373 }
Romain Guy06882f82009-06-10 13:36:04 -07003374
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003375 public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 boolean changed;
3377 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
3378 rotation = mRequestedRotation;
3379 } else {
3380 mRequestedRotation = rotation;
Dianne Hackborn321ae682009-03-27 16:16:03 -07003381 mLastRotationFlags = animFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 }
3383 if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07003384 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 mRotation, mDisplayEnabled);
3386 if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
3387 changed = mDisplayEnabled && mRotation != rotation;
Romain Guy06882f82009-06-10 13:36:04 -07003388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 if (changed) {
Romain Guy06882f82009-06-10 13:36:04 -07003390 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003391 "Rotation changed to " + rotation
3392 + " from " + mRotation
3393 + " (forceApp=" + mForcedAppOrientation
3394 + ", req=" + mRequestedRotation + ")");
3395 mRotation = rotation;
3396 mWindowsFreezingScreen = true;
3397 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
3398 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
3399 2000);
3400 startFreezingDisplayLocked();
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003401 Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 mQueue.setOrientation(rotation);
3403 if (mDisplayEnabled) {
Dianne Hackborn321ae682009-03-27 16:16:03 -07003404 Surface.setOrientation(0, rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 }
3406 for (int i=mWindows.size()-1; i>=0; i--) {
3407 WindowState w = (WindowState)mWindows.get(i);
3408 if (w.mSurface != null) {
3409 w.mOrientationChanging = true;
3410 }
3411 }
3412 for (int i=mRotationWatchers.size()-1; i>=0; i--) {
3413 try {
3414 mRotationWatchers.get(i).onRotationChanged(rotation);
3415 } catch (RemoteException e) {
3416 }
3417 }
3418 } //end if changed
Romain Guy06882f82009-06-10 13:36:04 -07003419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 return changed;
3421 }
Romain Guy06882f82009-06-10 13:36:04 -07003422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 public int getRotation() {
3424 return mRotation;
3425 }
3426
3427 public int watchRotation(IRotationWatcher watcher) {
3428 final IBinder watcherBinder = watcher.asBinder();
3429 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
3430 public void binderDied() {
3431 synchronized (mWindowMap) {
3432 for (int i=0; i<mRotationWatchers.size(); i++) {
3433 if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07003434 IRotationWatcher removed = mRotationWatchers.remove(i);
3435 if (removed != null) {
3436 removed.asBinder().unlinkToDeath(this, 0);
3437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 i--;
3439 }
3440 }
3441 }
3442 }
3443 };
Romain Guy06882f82009-06-10 13:36:04 -07003444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003445 synchronized (mWindowMap) {
3446 try {
3447 watcher.asBinder().linkToDeath(dr, 0);
3448 mRotationWatchers.add(watcher);
3449 } catch (RemoteException e) {
3450 // Client died, no cleanup needed.
3451 }
Romain Guy06882f82009-06-10 13:36:04 -07003452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453 return mRotation;
3454 }
3455 }
3456
3457 /**
3458 * Starts the view server on the specified port.
3459 *
3460 * @param port The port to listener to.
3461 *
3462 * @return True if the server was successfully started, false otherwise.
3463 *
3464 * @see com.android.server.ViewServer
3465 * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
3466 */
3467 public boolean startViewServer(int port) {
Romain Guy06882f82009-06-10 13:36:04 -07003468 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 return false;
3470 }
3471
3472 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
3473 return false;
3474 }
3475
3476 if (port < 1024) {
3477 return false;
3478 }
3479
3480 if (mViewServer != null) {
3481 if (!mViewServer.isRunning()) {
3482 try {
3483 return mViewServer.start();
3484 } catch (IOException e) {
Romain Guy06882f82009-06-10 13:36:04 -07003485 Log.w(TAG, "View server did not start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 }
3487 }
3488 return false;
3489 }
3490
3491 try {
3492 mViewServer = new ViewServer(this, port);
3493 return mViewServer.start();
3494 } catch (IOException e) {
3495 Log.w(TAG, "View server did not start");
3496 }
3497 return false;
3498 }
3499
Romain Guy06882f82009-06-10 13:36:04 -07003500 private boolean isSystemSecure() {
3501 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
3502 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
3503 }
3504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 /**
3506 * Stops the view server if it exists.
3507 *
3508 * @return True if the server stopped, false if it wasn't started or
3509 * couldn't be stopped.
3510 *
3511 * @see com.android.server.ViewServer
3512 */
3513 public boolean stopViewServer() {
Romain Guy06882f82009-06-10 13:36:04 -07003514 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 return false;
3516 }
3517
3518 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
3519 return false;
3520 }
3521
3522 if (mViewServer != null) {
3523 return mViewServer.stop();
3524 }
3525 return false;
3526 }
3527
3528 /**
3529 * Indicates whether the view server is running.
3530 *
3531 * @return True if the server is running, false otherwise.
3532 *
3533 * @see com.android.server.ViewServer
3534 */
3535 public boolean isViewServerRunning() {
Romain Guy06882f82009-06-10 13:36:04 -07003536 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 return false;
3538 }
3539
3540 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
3541 return false;
3542 }
3543
3544 return mViewServer != null && mViewServer.isRunning();
3545 }
3546
3547 /**
3548 * Lists all availble windows in the system. The listing is written in the
3549 * specified Socket's output stream with the following syntax:
3550 * windowHashCodeInHexadecimal windowName
3551 * Each line of the ouput represents a different window.
3552 *
3553 * @param client The remote client to send the listing to.
3554 * @return False if an error occured, true otherwise.
3555 */
3556 boolean viewServerListWindows(Socket client) {
Romain Guy06882f82009-06-10 13:36:04 -07003557 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 return false;
3559 }
3560
3561 boolean result = true;
3562
3563 Object[] windows;
3564 synchronized (mWindowMap) {
3565 windows = new Object[mWindows.size()];
3566 //noinspection unchecked
3567 windows = mWindows.toArray(windows);
3568 }
3569
3570 BufferedWriter out = null;
3571
3572 // Any uncaught exception will crash the system process
3573 try {
3574 OutputStream clientStream = client.getOutputStream();
3575 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
3576
3577 final int count = windows.length;
3578 for (int i = 0; i < count; i++) {
3579 final WindowState w = (WindowState) windows[i];
3580 out.write(Integer.toHexString(System.identityHashCode(w)));
3581 out.write(' ');
3582 out.append(w.mAttrs.getTitle());
3583 out.write('\n');
3584 }
3585
3586 out.write("DONE.\n");
3587 out.flush();
3588 } catch (Exception e) {
3589 result = false;
3590 } finally {
3591 if (out != null) {
3592 try {
3593 out.close();
3594 } catch (IOException e) {
3595 result = false;
3596 }
3597 }
3598 }
3599
3600 return result;
3601 }
3602
3603 /**
3604 * Sends a command to a target window. The result of the command, if any, will be
3605 * written in the output stream of the specified socket.
3606 *
3607 * The parameters must follow this syntax:
3608 * windowHashcode extra
3609 *
3610 * Where XX is the length in characeters of the windowTitle.
3611 *
3612 * The first parameter is the target window. The window with the specified hashcode
3613 * will be the target. If no target can be found, nothing happens. The extra parameters
3614 * will be delivered to the target window and as parameters to the command itself.
3615 *
3616 * @param client The remote client to sent the result, if any, to.
3617 * @param command The command to execute.
3618 * @param parameters The command parameters.
3619 *
3620 * @return True if the command was successfully delivered, false otherwise. This does
3621 * not indicate whether the command itself was successful.
3622 */
3623 boolean viewServerWindowCommand(Socket client, String command, String parameters) {
Romain Guy06882f82009-06-10 13:36:04 -07003624 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 return false;
3626 }
3627
3628 boolean success = true;
3629 Parcel data = null;
3630 Parcel reply = null;
3631
3632 // Any uncaught exception will crash the system process
3633 try {
3634 // Find the hashcode of the window
3635 int index = parameters.indexOf(' ');
3636 if (index == -1) {
3637 index = parameters.length();
3638 }
3639 final String code = parameters.substring(0, index);
3640 int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
3641
3642 // Extract the command's parameter after the window description
3643 if (index < parameters.length()) {
3644 parameters = parameters.substring(index + 1);
3645 } else {
3646 parameters = "";
3647 }
3648
3649 final WindowManagerService.WindowState window = findWindow(hashCode);
3650 if (window == null) {
3651 return false;
3652 }
3653
3654 data = Parcel.obtain();
3655 data.writeInterfaceToken("android.view.IWindow");
3656 data.writeString(command);
3657 data.writeString(parameters);
3658 data.writeInt(1);
3659 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
3660
3661 reply = Parcel.obtain();
3662
3663 final IBinder binder = window.mClient.asBinder();
3664 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
3665 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
3666
3667 reply.readException();
3668
3669 } catch (Exception e) {
3670 Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
3671 success = false;
3672 } finally {
3673 if (data != null) {
3674 data.recycle();
3675 }
3676 if (reply != null) {
3677 reply.recycle();
3678 }
3679 }
3680
3681 return success;
3682 }
3683
3684 private WindowState findWindow(int hashCode) {
3685 if (hashCode == -1) {
3686 return getFocusedWindow();
3687 }
3688
3689 synchronized (mWindowMap) {
3690 final ArrayList windows = mWindows;
3691 final int count = windows.size();
3692
3693 for (int i = 0; i < count; i++) {
3694 WindowState w = (WindowState) windows.get(i);
3695 if (System.identityHashCode(w) == hashCode) {
3696 return w;
3697 }
3698 }
3699 }
3700
3701 return null;
3702 }
3703
3704 /*
3705 * Instruct the Activity Manager to fetch the current configuration and broadcast
3706 * that to config-changed listeners if appropriate.
3707 */
3708 void sendNewConfiguration() {
3709 try {
3710 mActivityManager.updateConfiguration(null);
3711 } catch (RemoteException e) {
3712 }
3713 }
Romain Guy06882f82009-06-10 13:36:04 -07003714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715 public Configuration computeNewConfiguration() {
3716 synchronized (mWindowMap) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07003717 return computeNewConfigurationLocked();
3718 }
3719 }
Romain Guy06882f82009-06-10 13:36:04 -07003720
Dianne Hackbornc485a602009-03-24 22:39:49 -07003721 Configuration computeNewConfigurationLocked() {
3722 Configuration config = new Configuration();
3723 if (!computeNewConfigurationLocked(config)) {
3724 return null;
3725 }
3726 Log.i(TAG, "Config changed: " + config);
3727 long now = SystemClock.uptimeMillis();
3728 //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
3729 if (mFreezeGcPending != 0) {
3730 if (now > (mFreezeGcPending+1000)) {
3731 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
3732 mH.removeMessages(H.FORCE_GC);
3733 Runtime.getRuntime().gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 mFreezeGcPending = now;
3735 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003736 } else {
3737 mFreezeGcPending = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003738 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003739 return config;
3740 }
Romain Guy06882f82009-06-10 13:36:04 -07003741
Dianne Hackbornc485a602009-03-24 22:39:49 -07003742 boolean computeNewConfigurationLocked(Configuration config) {
3743 if (mDisplay == null) {
3744 return false;
3745 }
3746 mQueue.getInputConfiguration(config);
3747 final int dw = mDisplay.getWidth();
3748 final int dh = mDisplay.getHeight();
3749 int orientation = Configuration.ORIENTATION_SQUARE;
3750 if (dw < dh) {
3751 orientation = Configuration.ORIENTATION_PORTRAIT;
3752 } else if (dw > dh) {
3753 orientation = Configuration.ORIENTATION_LANDSCAPE;
3754 }
3755 config.orientation = orientation;
Dianne Hackborn723738c2009-06-25 19:48:04 -07003756
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07003757 DisplayMetrics dm = new DisplayMetrics();
3758 mDisplay.getMetrics(dm);
3759 CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
3760
Dianne Hackborn723738c2009-06-25 19:48:04 -07003761 if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
3762 // Note we only do this once because at this point we don't
3763 // expect the screen to change in this way at runtime, and want
3764 // to avoid all of this computation for every config change.
Dianne Hackborn723738c2009-06-25 19:48:04 -07003765 int longSize = dw;
3766 int shortSize = dh;
3767 if (longSize < shortSize) {
3768 int tmp = longSize;
3769 longSize = shortSize;
3770 shortSize = tmp;
3771 }
3772 longSize = (int)(longSize/dm.density);
3773 shortSize = (int)(shortSize/dm.density);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07003774
Dianne Hackborn723738c2009-06-25 19:48:04 -07003775 // These semi-magic numbers define our compatibility modes for
3776 // applications with different screens. Don't change unless you
3777 // make sure to test lots and lots of apps!
3778 if (longSize < 470) {
3779 // This is shorter than an HVGA normal density screen (which
3780 // is 480 pixels on its long side).
3781 screenLayout = Configuration.SCREENLAYOUT_SMALL;
3782 } else if (longSize > 490 && shortSize > 330) {
3783 // This is larger than an HVGA normal density screen (which
3784 // is 480x320 pixels).
3785 screenLayout = Configuration.SCREENLAYOUT_LARGE;
3786 } else {
3787 screenLayout = Configuration.SCREENLAYOUT_NORMAL;
3788 }
3789 }
3790 config.screenLayout = screenLayout;
3791
Dianne Hackbornc485a602009-03-24 22:39:49 -07003792 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
3793 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
3794 mPolicy.adjustConfigurationLw(config);
3795 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 }
Romain Guy06882f82009-06-10 13:36:04 -07003797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 // -------------------------------------------------------------
3799 // Input Events and Focus Management
3800 // -------------------------------------------------------------
3801
3802 private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
Michael Chane96440f2009-05-06 10:27:36 -07003803 long curTime = SystemClock.uptimeMillis();
3804
3805 if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
3806 if (mLastTouchEventType == eventType &&
3807 (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
3808 return;
3809 }
3810 mLastUserActivityCallTime = curTime;
3811 mLastTouchEventType = eventType;
3812 }
3813
3814 if (targetWin == null
3815 || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
3816 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003817 }
3818 }
3819
3820 // tells if it's a cheek event or not -- this function is stateful
3821 private static final int EVENT_NONE = 0;
3822 private static final int EVENT_UNKNOWN = 0;
3823 private static final int EVENT_CHEEK = 0;
3824 private static final int EVENT_IGNORE_DURATION = 300; // ms
3825 private static final float CHEEK_THRESHOLD = 0.6f;
3826 private int mEventState = EVENT_NONE;
3827 private float mEventSize;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 private int eventType(MotionEvent ev) {
3830 float size = ev.getSize();
3831 switch (ev.getAction()) {
3832 case MotionEvent.ACTION_DOWN:
3833 mEventSize = size;
3834 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
3835 case MotionEvent.ACTION_UP:
3836 if (size > mEventSize) mEventSize = size;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003837 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003838 case MotionEvent.ACTION_MOVE:
3839 final int N = ev.getHistorySize();
3840 if (size > mEventSize) mEventSize = size;
3841 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3842 for (int i=0; i<N; i++) {
3843 size = ev.getHistoricalSize(i);
3844 if (size > mEventSize) mEventSize = size;
3845 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3846 }
3847 if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
3848 return TOUCH_EVENT;
3849 } else {
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003850 return LONG_TOUCH_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003851 }
3852 default:
3853 // not good
3854 return OTHER_EVENT;
3855 }
3856 }
3857
3858 /**
3859 * @return Returns true if event was dispatched, false if it was dropped for any reason
3860 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07003861 private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003862 if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
3863 "dispatchPointer " + ev);
3864
3865 Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07003866 ev, true, false, pid, uid);
Romain Guy06882f82009-06-10 13:36:04 -07003867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003868 int action = ev.getAction();
Romain Guy06882f82009-06-10 13:36:04 -07003869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870 if (action == MotionEvent.ACTION_UP) {
3871 // let go of our target
3872 mKeyWaiter.mMotionTarget = null;
3873 mPowerManager.logPointerUpEvent();
3874 } else if (action == MotionEvent.ACTION_DOWN) {
3875 mPowerManager.logPointerDownEvent();
3876 }
3877
3878 if (targetObj == null) {
3879 // In this case we are either dropping the event, or have received
3880 // a move or up without a down. It is common to receive move
3881 // events in such a way, since this means the user is moving the
3882 // pointer without actually pressing down. All other cases should
3883 // be atypical, so let's log them.
Michael Chane96440f2009-05-06 10:27:36 -07003884 if (action != MotionEvent.ACTION_MOVE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
3886 }
3887 if (qev != null) {
3888 mQueue.recycleEvent(qev);
3889 }
3890 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003891 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003892 }
3893 if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3894 if (qev != null) {
3895 mQueue.recycleEvent(qev);
3896 }
3897 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003898 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 }
Romain Guy06882f82009-06-10 13:36:04 -07003900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901 WindowState target = (WindowState)targetObj;
Romain Guy06882f82009-06-10 13:36:04 -07003902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07003904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003905 //Log.i(TAG, "Sending " + ev + " to " + target);
3906
3907 if (uid != 0 && uid != target.mSession.mUid) {
3908 if (mContext.checkPermission(
3909 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3910 != PackageManager.PERMISSION_GRANTED) {
3911 Log.w(TAG, "Permission denied: injecting pointer event from pid "
3912 + pid + " uid " + uid + " to window " + target
3913 + " owned by uid " + target.mSession.mUid);
3914 if (qev != null) {
3915 mQueue.recycleEvent(qev);
3916 }
3917 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003918 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 }
3920 }
Romain Guy06882f82009-06-10 13:36:04 -07003921
3922 if ((target.mAttrs.flags &
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003923 WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
3924 //target wants to ignore fat touch events
3925 boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
3926 //explicit flag to return without processing event further
3927 boolean returnFlag = false;
3928 if((action == MotionEvent.ACTION_DOWN)) {
3929 mFatTouch = false;
3930 if(cheekPress) {
3931 mFatTouch = true;
3932 returnFlag = true;
3933 }
3934 } else {
3935 if(action == MotionEvent.ACTION_UP) {
3936 if(mFatTouch) {
3937 //earlier even was invalid doesnt matter if current up is cheekpress or not
3938 mFatTouch = false;
3939 returnFlag = true;
3940 } else if(cheekPress) {
3941 //cancel the earlier event
3942 ev.setAction(MotionEvent.ACTION_CANCEL);
3943 action = MotionEvent.ACTION_CANCEL;
3944 }
3945 } else if(action == MotionEvent.ACTION_MOVE) {
3946 if(mFatTouch) {
3947 //two cases here
3948 //an invalid down followed by 0 or moves(valid or invalid)
Romain Guy06882f82009-06-10 13:36:04 -07003949 //a valid down, invalid move, more moves. want to ignore till up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003950 returnFlag = true;
3951 } else if(cheekPress) {
3952 //valid down followed by invalid moves
3953 //an invalid move have to cancel earlier action
3954 ev.setAction(MotionEvent.ACTION_CANCEL);
3955 action = MotionEvent.ACTION_CANCEL;
3956 if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE");
3957 //note that the subsequent invalid moves will not get here
3958 mFatTouch = true;
3959 }
3960 }
3961 } //else if action
3962 if(returnFlag) {
3963 //recycle que, ev
3964 if (qev != null) {
3965 mQueue.recycleEvent(qev);
3966 }
3967 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003968 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003969 }
3970 } //end if target
Michael Chane96440f2009-05-06 10:27:36 -07003971
3972 // TODO remove once we settle on a value or make it app specific
3973 if (action == MotionEvent.ACTION_DOWN) {
3974 int max_events_per_sec = 35;
3975 try {
3976 max_events_per_sec = Integer.parseInt(SystemProperties
3977 .get("windowsmgr.max_events_per_sec"));
3978 if (max_events_per_sec < 1) {
3979 max_events_per_sec = 35;
3980 }
3981 } catch (NumberFormatException e) {
3982 }
3983 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
3984 }
3985
3986 /*
3987 * Throttle events to minimize CPU usage when there's a flood of events
3988 * e.g. constant contact with the screen
3989 */
3990 if (action == MotionEvent.ACTION_MOVE) {
3991 long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
3992 long now = SystemClock.uptimeMillis();
3993 if (now < nextEventTime) {
3994 try {
3995 Thread.sleep(nextEventTime - now);
3996 } catch (InterruptedException e) {
3997 }
3998 mLastTouchEventTime = nextEventTime;
3999 } else {
4000 mLastTouchEventTime = now;
4001 }
4002 }
4003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004004 synchronized(mWindowMap) {
4005 if (qev != null && action == MotionEvent.ACTION_MOVE) {
4006 mKeyWaiter.bindTargetWindowLocked(target,
4007 KeyWaiter.RETURN_PENDING_POINTER, qev);
4008 ev = null;
4009 } else {
4010 if (action == MotionEvent.ACTION_DOWN) {
4011 WindowState out = mKeyWaiter.mOutsideTouchTargets;
4012 if (out != null) {
4013 MotionEvent oev = MotionEvent.obtain(ev);
4014 oev.setAction(MotionEvent.ACTION_OUTSIDE);
4015 do {
4016 final Rect frame = out.mFrame;
4017 oev.offsetLocation(-(float)frame.left, -(float)frame.top);
4018 try {
4019 out.mClient.dispatchPointer(oev, eventTime);
4020 } catch (android.os.RemoteException e) {
4021 Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
4022 }
4023 oev.offsetLocation((float)frame.left, (float)frame.top);
4024 out = out.mNextOutsideTouch;
4025 } while (out != null);
4026 mKeyWaiter.mOutsideTouchTargets = null;
4027 }
4028 }
4029 final Rect frame = target.mFrame;
4030 ev.offsetLocation(-(float)frame.left, -(float)frame.top);
4031 mKeyWaiter.bindTargetWindowLocked(target);
4032 }
4033 }
Romain Guy06882f82009-06-10 13:36:04 -07004034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004035 // finally offset the event to the target's coordinate system and
4036 // dispatch the event.
4037 try {
4038 if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
4039 Log.v(TAG, "Delivering pointer " + qev + " to " + target);
4040 }
4041 target.mClient.dispatchPointer(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004042 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 } catch (android.os.RemoteException e) {
4044 Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
4045 mKeyWaiter.mMotionTarget = null;
4046 try {
4047 removeWindow(target.mSession, target.mClient);
4048 } catch (java.util.NoSuchElementException ex) {
4049 // This will happen if the window has already been
4050 // removed.
4051 }
4052 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004053 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 }
Romain Guy06882f82009-06-10 13:36:04 -07004055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004056 /**
4057 * @return Returns true if event was dispatched, false if it was dropped for any reason
4058 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004059 private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004060 if (DEBUG_INPUT) Log.v(
4061 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
Romain Guy06882f82009-06-10 13:36:04 -07004062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063 Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004064 ev, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004065 if (focusObj == null) {
4066 Log.w(TAG, "No focus window, dropping trackball: " + ev);
4067 if (qev != null) {
4068 mQueue.recycleEvent(qev);
4069 }
4070 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004071 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004072 }
4073 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
4074 if (qev != null) {
4075 mQueue.recycleEvent(qev);
4076 }
4077 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004078 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004079 }
Romain Guy06882f82009-06-10 13:36:04 -07004080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004081 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004083 if (uid != 0 && uid != focus.mSession.mUid) {
4084 if (mContext.checkPermission(
4085 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4086 != PackageManager.PERMISSION_GRANTED) {
4087 Log.w(TAG, "Permission denied: injecting key event from pid "
4088 + pid + " uid " + uid + " to window " + focus
4089 + " owned by uid " + focus.mSession.mUid);
4090 if (qev != null) {
4091 mQueue.recycleEvent(qev);
4092 }
4093 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004094 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004095 }
4096 }
Romain Guy06882f82009-06-10 13:36:04 -07004097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004100 synchronized(mWindowMap) {
4101 if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
4102 mKeyWaiter.bindTargetWindowLocked(focus,
4103 KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
4104 // We don't deliver movement events to the client, we hold
4105 // them and wait for them to call back.
4106 ev = null;
4107 } else {
4108 mKeyWaiter.bindTargetWindowLocked(focus);
4109 }
4110 }
Romain Guy06882f82009-06-10 13:36:04 -07004111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004112 try {
4113 focus.mClient.dispatchTrackball(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004114 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004115 } catch (android.os.RemoteException e) {
4116 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4117 try {
4118 removeWindow(focus.mSession, focus.mClient);
4119 } catch (java.util.NoSuchElementException ex) {
4120 // This will happen if the window has already been
4121 // removed.
4122 }
4123 }
Romain Guy06882f82009-06-10 13:36:04 -07004124
Dianne Hackborncfaef692009-06-15 14:24:44 -07004125 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004126 }
Romain Guy06882f82009-06-10 13:36:04 -07004127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128 /**
4129 * @return Returns true if event was dispatched, false if it was dropped for any reason
4130 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004131 private int dispatchKey(KeyEvent event, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
4133
4134 Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004135 null, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004136 if (focusObj == null) {
4137 Log.w(TAG, "No focus window, dropping: " + event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004138 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 }
4140 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004141 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004142 }
Romain Guy06882f82009-06-10 13:36:04 -07004143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004144 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004146 if (DEBUG_INPUT) Log.v(
4147 TAG, "Dispatching to " + focus + ": " + event);
4148
4149 if (uid != 0 && uid != focus.mSession.mUid) {
4150 if (mContext.checkPermission(
4151 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4152 != PackageManager.PERMISSION_GRANTED) {
4153 Log.w(TAG, "Permission denied: injecting key event from pid "
4154 + pid + " uid " + uid + " to window " + focus
4155 + " owned by uid " + focus.mSession.mUid);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004156 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004157 }
4158 }
Romain Guy06882f82009-06-10 13:36:04 -07004159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 synchronized(mWindowMap) {
4161 mKeyWaiter.bindTargetWindowLocked(focus);
4162 }
4163
4164 // NOSHIP extra state logging
4165 mKeyWaiter.recordDispatchState(event, focus);
4166 // END NOSHIP
Romain Guy06882f82009-06-10 13:36:04 -07004167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004168 try {
4169 if (DEBUG_INPUT || DEBUG_FOCUS) {
4170 Log.v(TAG, "Delivering key " + event.getKeyCode()
4171 + " to " + focus);
4172 }
4173 focus.mClient.dispatchKey(event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004174 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004175 } catch (android.os.RemoteException e) {
4176 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4177 try {
4178 removeWindow(focus.mSession, focus.mClient);
4179 } catch (java.util.NoSuchElementException ex) {
4180 // This will happen if the window has already been
4181 // removed.
4182 }
4183 }
Romain Guy06882f82009-06-10 13:36:04 -07004184
Dianne Hackborncfaef692009-06-15 14:24:44 -07004185 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004186 }
Romain Guy06882f82009-06-10 13:36:04 -07004187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 public void pauseKeyDispatching(IBinder _token) {
4189 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4190 "pauseKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004191 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004192 }
4193
4194 synchronized (mWindowMap) {
4195 WindowToken token = mTokenMap.get(_token);
4196 if (token != null) {
4197 mKeyWaiter.pauseDispatchingLocked(token);
4198 }
4199 }
4200 }
4201
4202 public void resumeKeyDispatching(IBinder _token) {
4203 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4204 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004205 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004206 }
4207
4208 synchronized (mWindowMap) {
4209 WindowToken token = mTokenMap.get(_token);
4210 if (token != null) {
4211 mKeyWaiter.resumeDispatchingLocked(token);
4212 }
4213 }
4214 }
4215
4216 public void setEventDispatching(boolean enabled) {
4217 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4218 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004219 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004220 }
4221
4222 synchronized (mWindowMap) {
4223 mKeyWaiter.setEventDispatchingLocked(enabled);
4224 }
4225 }
Romain Guy06882f82009-06-10 13:36:04 -07004226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004227 /**
4228 * Injects a keystroke event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004229 *
4230 * @param ev A motion event describing the keystroke action. (Be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004231 * {@link SystemClock#uptimeMillis()} as the timebase.)
4232 * @param sync If true, wait for the event to be completed before returning to the caller.
4233 * @return Returns true if event was dispatched, false if it was dropped for any reason
4234 */
4235 public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
4236 long downTime = ev.getDownTime();
4237 long eventTime = ev.getEventTime();
4238
4239 int action = ev.getAction();
4240 int code = ev.getKeyCode();
4241 int repeatCount = ev.getRepeatCount();
4242 int metaState = ev.getMetaState();
4243 int deviceId = ev.getDeviceId();
4244 int scancode = ev.getScanCode();
4245
4246 if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
4247 if (downTime == 0) downTime = eventTime;
4248
4249 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
The Android Open Source Project10592532009-03-18 17:39:46 -07004250 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004251
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004252 final int pid = Binder.getCallingPid();
4253 final int uid = Binder.getCallingUid();
4254 final long ident = Binder.clearCallingIdentity();
4255 final int result = dispatchKey(newEvent, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004256 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004257 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004258 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004259 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004260 switch (result) {
4261 case INJECT_NO_PERMISSION:
4262 throw new SecurityException(
4263 "Injecting to another application requires INJECT_EVENT permission");
4264 case INJECT_SUCCEEDED:
4265 return true;
4266 }
4267 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004268 }
4269
4270 /**
4271 * Inject a pointer (touch) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004272 *
4273 * @param ev A motion event describing the pointer (touch) action. (As noted in
4274 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004275 * {@link SystemClock#uptimeMillis()} as the timebase.)
4276 * @param sync If true, wait for the event to be completed before returning to the caller.
4277 * @return Returns true if event was dispatched, false if it was dropped for any reason
4278 */
4279 public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004280 final int pid = Binder.getCallingPid();
4281 final int uid = Binder.getCallingUid();
4282 final long ident = Binder.clearCallingIdentity();
4283 final int result = dispatchPointer(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004284 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004285 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004286 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004287 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004288 switch (result) {
4289 case INJECT_NO_PERMISSION:
4290 throw new SecurityException(
4291 "Injecting to another application requires INJECT_EVENT permission");
4292 case INJECT_SUCCEEDED:
4293 return true;
4294 }
4295 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004296 }
Romain Guy06882f82009-06-10 13:36:04 -07004297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298 /**
4299 * Inject a trackball (navigation device) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004300 *
4301 * @param ev A motion event describing the trackball action. (As noted in
4302 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004303 * {@link SystemClock#uptimeMillis()} as the timebase.)
4304 * @param sync If true, wait for the event to be completed before returning to the caller.
4305 * @return Returns true if event was dispatched, false if it was dropped for any reason
4306 */
4307 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004308 final int pid = Binder.getCallingPid();
4309 final int uid = Binder.getCallingUid();
4310 final long ident = Binder.clearCallingIdentity();
4311 final int result = dispatchTrackball(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004312 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004313 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004314 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004315 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004316 switch (result) {
4317 case INJECT_NO_PERMISSION:
4318 throw new SecurityException(
4319 "Injecting to another application requires INJECT_EVENT permission");
4320 case INJECT_SUCCEEDED:
4321 return true;
4322 }
4323 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004324 }
Romain Guy06882f82009-06-10 13:36:04 -07004325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004326 private WindowState getFocusedWindow() {
4327 synchronized (mWindowMap) {
4328 return getFocusedWindowLocked();
4329 }
4330 }
4331
4332 private WindowState getFocusedWindowLocked() {
4333 return mCurrentFocus;
4334 }
Romain Guy06882f82009-06-10 13:36:04 -07004335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004336 /**
4337 * This class holds the state for dispatching key events. This state
4338 * is protected by the KeyWaiter instance, NOT by the window lock. You
4339 * can be holding the main window lock while acquire the KeyWaiter lock,
4340 * but not the other way around.
4341 */
4342 final class KeyWaiter {
4343 // NOSHIP debugging
4344 public class DispatchState {
4345 private KeyEvent event;
4346 private WindowState focus;
4347 private long time;
4348 private WindowState lastWin;
4349 private IBinder lastBinder;
4350 private boolean finished;
4351 private boolean gotFirstWindow;
4352 private boolean eventDispatching;
4353 private long timeToSwitch;
4354 private boolean wasFrozen;
4355 private boolean focusPaused;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004356 private WindowState curFocus;
Romain Guy06882f82009-06-10 13:36:04 -07004357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004358 DispatchState(KeyEvent theEvent, WindowState theFocus) {
4359 focus = theFocus;
4360 event = theEvent;
4361 time = System.currentTimeMillis();
4362 // snapshot KeyWaiter state
4363 lastWin = mLastWin;
4364 lastBinder = mLastBinder;
4365 finished = mFinished;
4366 gotFirstWindow = mGotFirstWindow;
4367 eventDispatching = mEventDispatching;
4368 timeToSwitch = mTimeToSwitch;
4369 wasFrozen = mWasFrozen;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004370 curFocus = mCurrentFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004371 // cache the paused state at ctor time as well
4372 if (theFocus == null || theFocus.mToken == null) {
4373 Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
4374 focusPaused = false;
4375 } else {
4376 focusPaused = theFocus.mToken.paused;
4377 }
4378 }
Romain Guy06882f82009-06-10 13:36:04 -07004379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004380 public String toString() {
4381 return "{{" + event + " to " + focus + " @ " + time
4382 + " lw=" + lastWin + " lb=" + lastBinder
4383 + " fin=" + finished + " gfw=" + gotFirstWindow
4384 + " ed=" + eventDispatching + " tts=" + timeToSwitch
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004385 + " wf=" + wasFrozen + " fp=" + focusPaused
4386 + " mcf=" + mCurrentFocus + "}}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004387 }
4388 };
4389 private DispatchState mDispatchState = null;
4390 public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
4391 mDispatchState = new DispatchState(theEvent, theFocus);
4392 }
4393 // END NOSHIP
4394
4395 public static final int RETURN_NOTHING = 0;
4396 public static final int RETURN_PENDING_POINTER = 1;
4397 public static final int RETURN_PENDING_TRACKBALL = 2;
Romain Guy06882f82009-06-10 13:36:04 -07004398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004399 final Object SKIP_TARGET_TOKEN = new Object();
4400 final Object CONSUMED_EVENT_TOKEN = new Object();
Romain Guy06882f82009-06-10 13:36:04 -07004401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004402 private WindowState mLastWin = null;
4403 private IBinder mLastBinder = null;
4404 private boolean mFinished = true;
4405 private boolean mGotFirstWindow = false;
4406 private boolean mEventDispatching = true;
4407 private long mTimeToSwitch = 0;
4408 /* package */ boolean mWasFrozen = false;
Romain Guy06882f82009-06-10 13:36:04 -07004409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004410 // Target of Motion events
4411 WindowState mMotionTarget;
Romain Guy06882f82009-06-10 13:36:04 -07004412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004413 // Windows above the target who would like to receive an "outside"
4414 // touch event for any down events outside of them.
4415 WindowState mOutsideTouchTargets;
4416
4417 /**
4418 * Wait for the last event dispatch to complete, then find the next
4419 * target that should receive the given event and wait for that one
4420 * to be ready to receive it.
4421 */
4422 Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
4423 MotionEvent nextMotion, boolean isPointerEvent,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004424 boolean failIfTimeout, int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004425 long startTime = SystemClock.uptimeMillis();
4426 long keyDispatchingTimeout = 5 * 1000;
4427 long waitedFor = 0;
4428
4429 while (true) {
4430 // Figure out which window we care about. It is either the
4431 // last window we are waiting to have process the event or,
4432 // if none, then the next window we think the event should go
4433 // to. Note: we retrieve mLastWin outside of the lock, so
4434 // it may change before we lock. Thus we must check it again.
4435 WindowState targetWin = mLastWin;
4436 boolean targetIsNew = targetWin == null;
4437 if (DEBUG_INPUT) Log.v(
4438 TAG, "waitForLastKey: mFinished=" + mFinished +
4439 ", mLastWin=" + mLastWin);
4440 if (targetIsNew) {
4441 Object target = findTargetWindow(nextKey, qev, nextMotion,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004442 isPointerEvent, callingPid, callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004443 if (target == SKIP_TARGET_TOKEN) {
4444 // The user has pressed a special key, and we are
4445 // dropping all pending events before it.
4446 if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey
4447 + " " + nextMotion);
4448 return null;
4449 }
4450 if (target == CONSUMED_EVENT_TOKEN) {
4451 if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
4452 + " " + nextMotion);
4453 return target;
4454 }
4455 targetWin = (WindowState)target;
4456 }
Romain Guy06882f82009-06-10 13:36:04 -07004457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004458 AppWindowToken targetApp = null;
Romain Guy06882f82009-06-10 13:36:04 -07004459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004460 // Now: is it okay to send the next event to this window?
4461 synchronized (this) {
4462 // First: did we come here based on the last window not
4463 // being null, but it changed by the time we got here?
4464 // If so, try again.
4465 if (!targetIsNew && mLastWin == null) {
4466 continue;
4467 }
Romain Guy06882f82009-06-10 13:36:04 -07004468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004469 // We never dispatch events if not finished with the
4470 // last one, or the display is frozen.
4471 if (mFinished && !mDisplayFrozen) {
4472 // If event dispatching is disabled, then we
4473 // just consume the events.
4474 if (!mEventDispatching) {
4475 if (DEBUG_INPUT) Log.v(TAG,
4476 "Skipping event; dispatching disabled: "
4477 + nextKey + " " + nextMotion);
4478 return null;
4479 }
4480 if (targetWin != null) {
4481 // If this is a new target, and that target is not
4482 // paused or unresponsive, then all looks good to
4483 // handle the event.
4484 if (targetIsNew && !targetWin.mToken.paused) {
4485 return targetWin;
4486 }
Romain Guy06882f82009-06-10 13:36:04 -07004487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004488 // If we didn't find a target window, and there is no
4489 // focused app window, then just eat the events.
4490 } else if (mFocusedApp == null) {
4491 if (DEBUG_INPUT) Log.v(TAG,
4492 "Skipping event; no focused app: "
4493 + nextKey + " " + nextMotion);
4494 return null;
4495 }
4496 }
Romain Guy06882f82009-06-10 13:36:04 -07004497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004498 if (DEBUG_INPUT) Log.v(
4499 TAG, "Waiting for last key in " + mLastBinder
4500 + " target=" + targetWin
4501 + " mFinished=" + mFinished
4502 + " mDisplayFrozen=" + mDisplayFrozen
4503 + " targetIsNew=" + targetIsNew
4504 + " paused="
4505 + (targetWin != null ? targetWin.mToken.paused : false)
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004506 + " mFocusedApp=" + mFocusedApp
4507 + " mCurrentFocus=" + mCurrentFocus);
Romain Guy06882f82009-06-10 13:36:04 -07004508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004509 targetApp = targetWin != null
4510 ? targetWin.mAppToken : mFocusedApp;
Romain Guy06882f82009-06-10 13:36:04 -07004511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004512 long curTimeout = keyDispatchingTimeout;
4513 if (mTimeToSwitch != 0) {
4514 long now = SystemClock.uptimeMillis();
4515 if (mTimeToSwitch <= now) {
4516 // If an app switch key has been pressed, and we have
4517 // waited too long for the current app to finish
4518 // processing keys, then wait no more!
4519 doFinishedKeyLocked(true);
4520 continue;
4521 }
4522 long switchTimeout = mTimeToSwitch - now;
4523 if (curTimeout > switchTimeout) {
4524 curTimeout = switchTimeout;
4525 }
4526 }
Romain Guy06882f82009-06-10 13:36:04 -07004527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004528 try {
4529 // after that continue
4530 // processing keys, so we don't get stuck.
4531 if (DEBUG_INPUT) Log.v(
4532 TAG, "Waiting for key dispatch: " + curTimeout);
4533 wait(curTimeout);
4534 if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
4535 + SystemClock.uptimeMillis() + " startTime="
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004536 + startTime + " switchTime=" + mTimeToSwitch
4537 + " target=" + targetWin + " mLW=" + mLastWin
4538 + " mLB=" + mLastBinder + " fin=" + mFinished
4539 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004540 } catch (InterruptedException e) {
4541 }
4542 }
4543
4544 // If we were frozen during configuration change, restart the
4545 // timeout checks from now; otherwise look at whether we timed
4546 // out before awakening.
4547 if (mWasFrozen) {
4548 waitedFor = 0;
4549 mWasFrozen = false;
4550 } else {
4551 waitedFor = SystemClock.uptimeMillis() - startTime;
4552 }
4553
4554 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
4555 IApplicationToken at = null;
4556 synchronized (this) {
4557 Log.w(TAG, "Key dispatching timed out sending to " +
4558 (targetWin != null ? targetWin.mAttrs.getTitle()
4559 : "<null>"));
4560 // NOSHIP debugging
4561 Log.w(TAG, "Dispatch state: " + mDispatchState);
4562 Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
4563 // END NOSHIP
4564 //dump();
4565 if (targetWin != null) {
4566 at = targetWin.getAppToken();
4567 } else if (targetApp != null) {
4568 at = targetApp.appToken;
4569 }
4570 }
4571
4572 boolean abort = true;
4573 if (at != null) {
4574 try {
4575 long timeout = at.getKeyDispatchingTimeout();
4576 if (timeout > waitedFor) {
4577 // we did not wait the proper amount of time for this application.
4578 // set the timeout to be the real timeout and wait again.
4579 keyDispatchingTimeout = timeout - waitedFor;
4580 continue;
4581 } else {
4582 abort = at.keyDispatchingTimedOut();
4583 }
4584 } catch (RemoteException ex) {
4585 }
4586 }
4587
4588 synchronized (this) {
4589 if (abort && (mLastWin == targetWin || targetWin == null)) {
4590 mFinished = true;
Romain Guy06882f82009-06-10 13:36:04 -07004591 if (mLastWin != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004592 if (DEBUG_INPUT) Log.v(TAG,
4593 "Window " + mLastWin +
4594 " timed out on key input");
4595 if (mLastWin.mToken.paused) {
4596 Log.w(TAG, "Un-pausing dispatching to this window");
4597 mLastWin.mToken.paused = false;
4598 }
4599 }
4600 if (mMotionTarget == targetWin) {
4601 mMotionTarget = null;
4602 }
4603 mLastWin = null;
4604 mLastBinder = null;
4605 if (failIfTimeout || targetWin == null) {
4606 return null;
4607 }
4608 } else {
4609 Log.w(TAG, "Continuing to wait for key to be dispatched");
4610 startTime = SystemClock.uptimeMillis();
4611 }
4612 }
4613 }
4614 }
4615 }
Romain Guy06882f82009-06-10 13:36:04 -07004616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004617 Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004618 MotionEvent nextMotion, boolean isPointerEvent,
4619 int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004620 mOutsideTouchTargets = null;
Romain Guy06882f82009-06-10 13:36:04 -07004621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004622 if (nextKey != null) {
4623 // Find the target window for a normal key event.
4624 final int keycode = nextKey.getKeyCode();
4625 final int repeatCount = nextKey.getRepeatCount();
4626 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
4627 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 if (!dispatch) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004630 if (callingUid == 0 ||
4631 mContext.checkPermission(
4632 android.Manifest.permission.INJECT_EVENTS,
4633 callingPid, callingUid)
4634 == PackageManager.PERMISSION_GRANTED) {
4635 mPolicy.interceptKeyTi(null, keycode,
4636 nextKey.getMetaState(), down, repeatCount);
4637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004638 Log.w(TAG, "Event timeout during app switch: dropping "
4639 + nextKey);
4640 return SKIP_TARGET_TOKEN;
4641 }
Romain Guy06882f82009-06-10 13:36:04 -07004642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
Romain Guy06882f82009-06-10 13:36:04 -07004644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004645 WindowState focus = null;
4646 synchronized(mWindowMap) {
4647 focus = getFocusedWindowLocked();
4648 }
Romain Guy06882f82009-06-10 13:36:04 -07004649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
Romain Guy06882f82009-06-10 13:36:04 -07004651
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004652 if (callingUid == 0 ||
4653 (focus != null && callingUid == focus.mSession.mUid) ||
4654 mContext.checkPermission(
4655 android.Manifest.permission.INJECT_EVENTS,
4656 callingPid, callingUid)
4657 == PackageManager.PERMISSION_GRANTED) {
4658 if (mPolicy.interceptKeyTi(focus,
4659 keycode, nextKey.getMetaState(), down, repeatCount)) {
4660 return CONSUMED_EVENT_TOKEN;
4661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004662 }
Romain Guy06882f82009-06-10 13:36:04 -07004663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004664 return focus;
Romain Guy06882f82009-06-10 13:36:04 -07004665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004666 } else if (!isPointerEvent) {
4667 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
4668 if (!dispatch) {
4669 Log.w(TAG, "Event timeout during app switch: dropping trackball "
4670 + nextMotion);
4671 return SKIP_TARGET_TOKEN;
4672 }
Romain Guy06882f82009-06-10 13:36:04 -07004673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 WindowState focus = null;
4675 synchronized(mWindowMap) {
4676 focus = getFocusedWindowLocked();
4677 }
Romain Guy06882f82009-06-10 13:36:04 -07004678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004679 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
4680 return focus;
4681 }
Romain Guy06882f82009-06-10 13:36:04 -07004682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004683 if (nextMotion == null) {
4684 return SKIP_TARGET_TOKEN;
4685 }
Romain Guy06882f82009-06-10 13:36:04 -07004686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
4688 KeyEvent.KEYCODE_UNKNOWN);
4689 if (!dispatch) {
4690 Log.w(TAG, "Event timeout during app switch: dropping pointer "
4691 + nextMotion);
4692 return SKIP_TARGET_TOKEN;
4693 }
Romain Guy06882f82009-06-10 13:36:04 -07004694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 // Find the target window for a pointer event.
4696 int action = nextMotion.getAction();
4697 final float xf = nextMotion.getX();
4698 final float yf = nextMotion.getY();
4699 final long eventTime = nextMotion.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004701 final boolean screenWasOff = qev != null
4702 && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07004703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004704 WindowState target = null;
Romain Guy06882f82009-06-10 13:36:04 -07004705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004706 synchronized(mWindowMap) {
4707 synchronized (this) {
4708 if (action == MotionEvent.ACTION_DOWN) {
4709 if (mMotionTarget != null) {
4710 // this is weird, we got a pen down, but we thought it was
4711 // already down!
4712 // XXX: We should probably send an ACTION_UP to the current
4713 // target.
4714 Log.w(TAG, "Pointer down received while already down in: "
4715 + mMotionTarget);
4716 mMotionTarget = null;
4717 }
Romain Guy06882f82009-06-10 13:36:04 -07004718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004719 // ACTION_DOWN is special, because we need to lock next events to
4720 // the window we'll land onto.
4721 final int x = (int)xf;
4722 final int y = (int)yf;
Romain Guy06882f82009-06-10 13:36:04 -07004723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004724 final ArrayList windows = mWindows;
4725 final int N = windows.size();
4726 WindowState topErrWindow = null;
4727 final Rect tmpRect = mTempRect;
4728 for (int i=N-1; i>=0; i--) {
4729 WindowState child = (WindowState)windows.get(i);
4730 //Log.i(TAG, "Checking dispatch to: " + child);
4731 final int flags = child.mAttrs.flags;
4732 if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
4733 if (topErrWindow == null) {
4734 topErrWindow = child;
4735 }
4736 }
4737 if (!child.isVisibleLw()) {
4738 //Log.i(TAG, "Not visible!");
4739 continue;
4740 }
4741 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
4742 //Log.i(TAG, "Not touchable!");
4743 if ((flags & WindowManager.LayoutParams
4744 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4745 child.mNextOutsideTouch = mOutsideTouchTargets;
4746 mOutsideTouchTargets = child;
4747 }
4748 continue;
4749 }
4750 tmpRect.set(child.mFrame);
4751 if (child.mTouchableInsets == ViewTreeObserver
4752 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
4753 // The touch is inside of the window if it is
4754 // inside the frame, AND the content part of that
4755 // frame that was given by the application.
4756 tmpRect.left += child.mGivenContentInsets.left;
4757 tmpRect.top += child.mGivenContentInsets.top;
4758 tmpRect.right -= child.mGivenContentInsets.right;
4759 tmpRect.bottom -= child.mGivenContentInsets.bottom;
4760 } else if (child.mTouchableInsets == ViewTreeObserver
4761 .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
4762 // The touch is inside of the window if it is
4763 // inside the frame, AND the visible part of that
4764 // frame that was given by the application.
4765 tmpRect.left += child.mGivenVisibleInsets.left;
4766 tmpRect.top += child.mGivenVisibleInsets.top;
4767 tmpRect.right -= child.mGivenVisibleInsets.right;
4768 tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
4769 }
4770 final int touchFlags = flags &
4771 (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
4772 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
4773 if (tmpRect.contains(x, y) || touchFlags == 0) {
4774 //Log.i(TAG, "Using this target!");
4775 if (!screenWasOff || (flags &
4776 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
4777 mMotionTarget = child;
4778 } else {
4779 //Log.i(TAG, "Waking, skip!");
4780 mMotionTarget = null;
4781 }
4782 break;
4783 }
Romain Guy06882f82009-06-10 13:36:04 -07004784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004785 if ((flags & WindowManager.LayoutParams
4786 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4787 child.mNextOutsideTouch = mOutsideTouchTargets;
4788 mOutsideTouchTargets = child;
4789 //Log.i(TAG, "Adding to outside target list: " + child);
4790 }
4791 }
4792
4793 // if there's an error window but it's not accepting
4794 // focus (typically because it is not yet visible) just
4795 // wait for it -- any other focused window may in fact
4796 // be in ANR state.
4797 if (topErrWindow != null && mMotionTarget != topErrWindow) {
4798 mMotionTarget = null;
4799 }
4800 }
Romain Guy06882f82009-06-10 13:36:04 -07004801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004802 target = mMotionTarget;
4803 }
4804 }
Romain Guy06882f82009-06-10 13:36:04 -07004805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004806 wakeupIfNeeded(target, eventType(nextMotion));
Romain Guy06882f82009-06-10 13:36:04 -07004807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004808 // Pointer events are a little different -- if there isn't a
4809 // target found for any event, then just drop it.
4810 return target != null ? target : SKIP_TARGET_TOKEN;
4811 }
Romain Guy06882f82009-06-10 13:36:04 -07004812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004813 boolean checkShouldDispatchKey(int keycode) {
4814 synchronized (this) {
4815 if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
4816 mTimeToSwitch = 0;
4817 return true;
4818 }
4819 if (mTimeToSwitch != 0
4820 && mTimeToSwitch < SystemClock.uptimeMillis()) {
4821 return false;
4822 }
4823 return true;
4824 }
4825 }
Romain Guy06882f82009-06-10 13:36:04 -07004826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004827 void bindTargetWindowLocked(WindowState win,
4828 int pendingWhat, QueuedEvent pendingMotion) {
4829 synchronized (this) {
4830 bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
4831 }
4832 }
Romain Guy06882f82009-06-10 13:36:04 -07004833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004834 void bindTargetWindowLocked(WindowState win) {
4835 synchronized (this) {
4836 bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
4837 }
4838 }
4839
4840 void bindTargetWindowLockedLocked(WindowState win,
4841 int pendingWhat, QueuedEvent pendingMotion) {
4842 mLastWin = win;
4843 mLastBinder = win.mClient.asBinder();
4844 mFinished = false;
4845 if (pendingMotion != null) {
4846 final Session s = win.mSession;
4847 if (pendingWhat == RETURN_PENDING_POINTER) {
4848 releasePendingPointerLocked(s);
4849 s.mPendingPointerMove = pendingMotion;
4850 s.mPendingPointerWindow = win;
Romain Guy06882f82009-06-10 13:36:04 -07004851 if (DEBUG_INPUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004852 "bindTargetToWindow " + s.mPendingPointerMove);
4853 } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
4854 releasePendingTrackballLocked(s);
4855 s.mPendingTrackballMove = pendingMotion;
4856 s.mPendingTrackballWindow = win;
4857 }
4858 }
4859 }
Romain Guy06882f82009-06-10 13:36:04 -07004860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004861 void releasePendingPointerLocked(Session s) {
4862 if (DEBUG_INPUT) Log.v(TAG,
4863 "releasePendingPointer " + s.mPendingPointerMove);
4864 if (s.mPendingPointerMove != null) {
4865 mQueue.recycleEvent(s.mPendingPointerMove);
4866 s.mPendingPointerMove = null;
4867 }
4868 }
Romain Guy06882f82009-06-10 13:36:04 -07004869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004870 void releasePendingTrackballLocked(Session s) {
4871 if (s.mPendingTrackballMove != null) {
4872 mQueue.recycleEvent(s.mPendingTrackballMove);
4873 s.mPendingTrackballMove = null;
4874 }
4875 }
Romain Guy06882f82009-06-10 13:36:04 -07004876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004877 MotionEvent finishedKey(Session session, IWindow client, boolean force,
4878 int returnWhat) {
4879 if (DEBUG_INPUT) Log.v(
4880 TAG, "finishedKey: client=" + client + ", force=" + force);
4881
4882 if (client == null) {
4883 return null;
4884 }
4885
4886 synchronized (this) {
4887 if (DEBUG_INPUT) Log.v(
4888 TAG, "finishedKey: client=" + client.asBinder()
4889 + ", force=" + force + ", last=" + mLastBinder
4890 + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
4891
4892 QueuedEvent qev = null;
4893 WindowState win = null;
4894 if (returnWhat == RETURN_PENDING_POINTER) {
4895 qev = session.mPendingPointerMove;
4896 win = session.mPendingPointerWindow;
4897 session.mPendingPointerMove = null;
4898 session.mPendingPointerWindow = null;
4899 } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
4900 qev = session.mPendingTrackballMove;
4901 win = session.mPendingTrackballWindow;
4902 session.mPendingTrackballMove = null;
4903 session.mPendingTrackballWindow = null;
4904 }
Romain Guy06882f82009-06-10 13:36:04 -07004905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004906 if (mLastBinder == client.asBinder()) {
4907 if (DEBUG_INPUT) Log.v(
4908 TAG, "finishedKey: last paused="
4909 + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
4910 if (mLastWin != null && (!mLastWin.mToken.paused || force
4911 || !mEventDispatching)) {
4912 doFinishedKeyLocked(false);
4913 } else {
4914 // Make sure to wake up anyone currently waiting to
4915 // dispatch a key, so they can re-evaluate their
4916 // current situation.
4917 mFinished = true;
4918 notifyAll();
4919 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004920 }
Romain Guy06882f82009-06-10 13:36:04 -07004921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004922 if (qev != null) {
4923 MotionEvent res = (MotionEvent)qev.event;
4924 if (DEBUG_INPUT) Log.v(TAG,
4925 "Returning pending motion: " + res);
4926 mQueue.recycleEvent(qev);
4927 if (win != null && returnWhat == RETURN_PENDING_POINTER) {
4928 res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
4929 }
4930 return res;
4931 }
4932 return null;
4933 }
4934 }
4935
4936 void tickle() {
4937 synchronized (this) {
4938 notifyAll();
4939 }
4940 }
Romain Guy06882f82009-06-10 13:36:04 -07004941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004942 void handleNewWindowLocked(WindowState newWindow) {
4943 if (!newWindow.canReceiveKeys()) {
4944 return;
4945 }
4946 synchronized (this) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004947 if (DEBUG_INPUT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004948 TAG, "New key dispatch window: win="
4949 + newWindow.mClient.asBinder()
4950 + ", last=" + mLastBinder
4951 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
4952 + "), finished=" + mFinished + ", paused="
4953 + newWindow.mToken.paused);
4954
4955 // Displaying a window implicitly causes dispatching to
4956 // be unpaused. (This is to protect against bugs if someone
4957 // pauses dispatching but forgets to resume.)
4958 newWindow.mToken.paused = false;
4959
4960 mGotFirstWindow = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004961
4962 if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
4963 if (DEBUG_INPUT) Log.v(TAG,
4964 "New SYSTEM_ERROR window; resetting state");
4965 mLastWin = null;
4966 mLastBinder = null;
4967 mMotionTarget = null;
4968 mFinished = true;
4969 } else if (mLastWin != null) {
4970 // If the new window is above the window we are
4971 // waiting on, then stop waiting and let key dispatching
4972 // start on the new guy.
4973 if (DEBUG_INPUT) Log.v(
4974 TAG, "Last win layer=" + mLastWin.mLayer
4975 + ", new win layer=" + newWindow.mLayer);
4976 if (newWindow.mLayer >= mLastWin.mLayer) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004977 // The new window is above the old; finish pending input to the last
4978 // window and start directing it to the new one.
4979 mLastWin.mToken.paused = false;
4980 doFinishedKeyLocked(true); // does a notifyAll()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004981 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004982 // Either the new window is lower, so there is no need to wake key waiters,
4983 // or we just finished key input to the previous window, which implicitly
4984 // notified the key waiters. In both cases, we don't need to issue the
4985 // notification here.
4986 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004987 }
4988
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004989 // Now that we've put a new window state in place, make the event waiter
4990 // take notice and retarget its attentions.
4991 notifyAll();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004992 }
4993 }
4994
4995 void pauseDispatchingLocked(WindowToken token) {
4996 synchronized (this)
4997 {
4998 if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
4999 token.paused = true;
5000
5001 /*
5002 if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
5003 mPaused = true;
5004 } else {
5005 if (mLastWin == null) {
Dave Bortcfe65242009-04-09 14:51:04 -07005006 Log.i(TAG, "Key dispatching not paused: no last window.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005007 } else if (mFinished) {
Dave Bortcfe65242009-04-09 14:51:04 -07005008 Log.i(TAG, "Key dispatching not paused: finished last key.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005009 } else {
Dave Bortcfe65242009-04-09 14:51:04 -07005010 Log.i(TAG, "Key dispatching not paused: window in higher layer.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005011 }
5012 }
5013 */
5014 }
5015 }
5016
5017 void resumeDispatchingLocked(WindowToken token) {
5018 synchronized (this) {
5019 if (token.paused) {
5020 if (DEBUG_INPUT) Log.v(
5021 TAG, "Resuming WindowToken " + token
5022 + ", last=" + mLastBinder
5023 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
5024 + "), finished=" + mFinished + ", paused="
5025 + token.paused);
5026 token.paused = false;
5027 if (mLastWin != null && mLastWin.mToken == token && mFinished) {
5028 doFinishedKeyLocked(true);
5029 } else {
5030 notifyAll();
5031 }
5032 }
5033 }
5034 }
5035
5036 void setEventDispatchingLocked(boolean enabled) {
5037 synchronized (this) {
5038 mEventDispatching = enabled;
5039 notifyAll();
5040 }
5041 }
Romain Guy06882f82009-06-10 13:36:04 -07005042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 void appSwitchComing() {
5044 synchronized (this) {
5045 // Don't wait for more than .5 seconds for app to finish
5046 // processing the pending events.
5047 long now = SystemClock.uptimeMillis() + 500;
5048 if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now);
5049 if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
5050 mTimeToSwitch = now;
5051 }
5052 notifyAll();
5053 }
5054 }
Romain Guy06882f82009-06-10 13:36:04 -07005055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005056 private final void doFinishedKeyLocked(boolean doRecycle) {
5057 if (mLastWin != null) {
5058 releasePendingPointerLocked(mLastWin.mSession);
5059 releasePendingTrackballLocked(mLastWin.mSession);
5060 }
Romain Guy06882f82009-06-10 13:36:04 -07005061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005062 if (mLastWin == null || !mLastWin.mToken.paused
5063 || !mLastWin.isVisibleLw()) {
5064 // If the current window has been paused, we aren't -really-
5065 // finished... so let the waiters still wait.
5066 mLastWin = null;
5067 mLastBinder = null;
5068 }
5069 mFinished = true;
5070 notifyAll();
5071 }
5072 }
5073
5074 private class KeyQ extends KeyInputQueue
5075 implements KeyInputQueue.FilterCallback {
5076 PowerManager.WakeLock mHoldingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07005077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 KeyQ() {
5079 super(mContext);
5080 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
5081 mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
5082 "KEEP_SCREEN_ON_FLAG");
5083 mHoldingScreen.setReferenceCounted(false);
5084 }
5085
5086 @Override
5087 boolean preprocessEvent(InputDevice device, RawInputEvent event) {
5088 if (mPolicy.preprocessInputEventTq(event)) {
5089 return true;
5090 }
Romain Guy06882f82009-06-10 13:36:04 -07005091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005092 switch (event.type) {
5093 case RawInputEvent.EV_KEY: {
5094 // XXX begin hack
5095 if (DEBUG) {
5096 if (event.keycode == KeyEvent.KEYCODE_G) {
5097 if (event.value != 0) {
5098 // G down
5099 mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
5100 }
5101 return false;
5102 }
5103 if (event.keycode == KeyEvent.KEYCODE_D) {
5104 if (event.value != 0) {
5105 //dump();
5106 }
5107 return false;
5108 }
5109 }
5110 // XXX end hack
Romain Guy06882f82009-06-10 13:36:04 -07005111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005112 boolean screenIsOff = !mPowerManager.screenIsOn();
5113 boolean screenIsDim = !mPowerManager.screenIsBright();
5114 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
Romain Guy06882f82009-06-10 13:36:04 -07005115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005116 if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
5117 mPowerManager.goToSleep(event.when);
5118 }
5119
5120 if (screenIsOff) {
5121 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5122 }
5123 if (screenIsDim) {
5124 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5125 }
5126 if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
5127 mPowerManager.userActivity(event.when, false,
Michael Chane96440f2009-05-06 10:27:36 -07005128 LocalPowerManager.BUTTON_EVENT, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005129 }
Romain Guy06882f82009-06-10 13:36:04 -07005130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005131 if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
5132 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
5133 filterQueue(this);
5134 mKeyWaiter.appSwitchComing();
5135 }
5136 return true;
5137 } else {
5138 return false;
5139 }
5140 }
Romain Guy06882f82009-06-10 13:36:04 -07005141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005142 case RawInputEvent.EV_REL: {
5143 boolean screenIsOff = !mPowerManager.screenIsOn();
5144 boolean screenIsDim = !mPowerManager.screenIsBright();
5145 if (screenIsOff) {
5146 if (!mPolicy.isWakeRelMovementTq(event.deviceId,
5147 device.classes, event)) {
5148 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5149 return false;
5150 }
5151 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5152 }
5153 if (screenIsDim) {
5154 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5155 }
5156 return true;
5157 }
Romain Guy06882f82009-06-10 13:36:04 -07005158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005159 case RawInputEvent.EV_ABS: {
5160 boolean screenIsOff = !mPowerManager.screenIsOn();
5161 boolean screenIsDim = !mPowerManager.screenIsBright();
5162 if (screenIsOff) {
5163 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
5164 device.classes, event)) {
5165 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5166 return false;
5167 }
5168 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5169 }
5170 if (screenIsDim) {
5171 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5172 }
5173 return true;
5174 }
Romain Guy06882f82009-06-10 13:36:04 -07005175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005176 default:
5177 return true;
5178 }
5179 }
5180
5181 public int filterEvent(QueuedEvent ev) {
5182 switch (ev.classType) {
5183 case RawInputEvent.CLASS_KEYBOARD:
5184 KeyEvent ke = (KeyEvent)ev.event;
5185 if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
5186 Log.w(TAG, "Dropping movement key during app switch: "
5187 + ke.getKeyCode() + ", action=" + ke.getAction());
5188 return FILTER_REMOVE;
5189 }
5190 return FILTER_ABORT;
5191 default:
5192 return FILTER_KEEP;
5193 }
5194 }
Romain Guy06882f82009-06-10 13:36:04 -07005195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005196 /**
5197 * Must be called with the main window manager lock held.
5198 */
5199 void setHoldScreenLocked(boolean holding) {
5200 boolean state = mHoldingScreen.isHeld();
5201 if (holding != state) {
5202 if (holding) {
5203 mHoldingScreen.acquire();
5204 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005205 mPolicy.screenOnStoppedLw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005206 mHoldingScreen.release();
5207 }
5208 }
5209 }
5210 };
5211
5212 public boolean detectSafeMode() {
5213 mSafeMode = mPolicy.detectSafeMode();
5214 return mSafeMode;
5215 }
Romain Guy06882f82009-06-10 13:36:04 -07005216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005217 public void systemReady() {
5218 mPolicy.systemReady();
5219 }
Romain Guy06882f82009-06-10 13:36:04 -07005220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005221 private final class InputDispatcherThread extends Thread {
5222 // Time to wait when there is nothing to do: 9999 seconds.
5223 static final int LONG_WAIT=9999*1000;
5224
5225 public InputDispatcherThread() {
5226 super("InputDispatcher");
5227 }
Romain Guy06882f82009-06-10 13:36:04 -07005228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005229 @Override
5230 public void run() {
5231 while (true) {
5232 try {
5233 process();
5234 } catch (Exception e) {
5235 Log.e(TAG, "Exception in input dispatcher", e);
5236 }
5237 }
5238 }
Romain Guy06882f82009-06-10 13:36:04 -07005239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005240 private void process() {
5241 android.os.Process.setThreadPriority(
5242 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -07005243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005244 // The last key event we saw
5245 KeyEvent lastKey = null;
5246
5247 // Last keydown time for auto-repeating keys
5248 long lastKeyTime = SystemClock.uptimeMillis();
5249 long nextKeyTime = lastKeyTime+LONG_WAIT;
5250
Romain Guy06882f82009-06-10 13:36:04 -07005251 // How many successive repeats we generated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005252 int keyRepeatCount = 0;
5253
5254 // Need to report that configuration has changed?
5255 boolean configChanged = false;
Romain Guy06882f82009-06-10 13:36:04 -07005256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257 while (true) {
5258 long curTime = SystemClock.uptimeMillis();
5259
5260 if (DEBUG_INPUT) Log.v(
5261 TAG, "Waiting for next key: now=" + curTime
5262 + ", repeat @ " + nextKeyTime);
5263
5264 // Retrieve next event, waiting only as long as the next
5265 // repeat timeout. If the configuration has changed, then
5266 // don't wait at all -- we'll report the change as soon as
5267 // we have processed all events.
5268 QueuedEvent ev = mQueue.getEvent(
5269 (int)((!configChanged && curTime < nextKeyTime)
5270 ? (nextKeyTime-curTime) : 0));
5271
5272 if (DEBUG_INPUT && ev != null) Log.v(
5273 TAG, "Event: type=" + ev.classType + " data=" + ev.event);
5274
5275 try {
5276 if (ev != null) {
5277 curTime = ev.when;
5278 int eventType;
5279 if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
5280 eventType = eventType((MotionEvent)ev.event);
5281 } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
5282 ev.classType == RawInputEvent.CLASS_TRACKBALL) {
5283 eventType = LocalPowerManager.BUTTON_EVENT;
5284 } else {
5285 eventType = LocalPowerManager.OTHER_EVENT;
5286 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005287 try {
Michael Chane96440f2009-05-06 10:27:36 -07005288 long now = SystemClock.uptimeMillis();
5289
5290 if ((now - mLastBatteryStatsCallTime)
5291 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
5292 mLastBatteryStatsCallTime = now;
5293 mBatteryStats.noteInputEvent();
5294 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005295 } catch (RemoteException e) {
5296 // Ignore
5297 }
Michael Chane96440f2009-05-06 10:27:36 -07005298 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005299 switch (ev.classType) {
5300 case RawInputEvent.CLASS_KEYBOARD:
5301 KeyEvent ke = (KeyEvent)ev.event;
5302 if (ke.isDown()) {
5303 lastKey = ke;
5304 keyRepeatCount = 0;
5305 lastKeyTime = curTime;
5306 nextKeyTime = lastKeyTime
5307 + KEY_REPEAT_FIRST_DELAY;
5308 if (DEBUG_INPUT) Log.v(
5309 TAG, "Received key down: first repeat @ "
5310 + nextKeyTime);
5311 } else {
5312 lastKey = null;
5313 // Arbitrary long timeout.
5314 lastKeyTime = curTime;
5315 nextKeyTime = curTime + LONG_WAIT;
5316 if (DEBUG_INPUT) Log.v(
5317 TAG, "Received key up: ignore repeat @ "
5318 + nextKeyTime);
5319 }
5320 dispatchKey((KeyEvent)ev.event, 0, 0);
5321 mQueue.recycleEvent(ev);
5322 break;
5323 case RawInputEvent.CLASS_TOUCHSCREEN:
5324 //Log.i(TAG, "Read next event " + ev);
5325 dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
5326 break;
5327 case RawInputEvent.CLASS_TRACKBALL:
5328 dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
5329 break;
5330 case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
5331 configChanged = true;
5332 break;
5333 default:
5334 mQueue.recycleEvent(ev);
5335 break;
5336 }
Romain Guy06882f82009-06-10 13:36:04 -07005337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005338 } else if (configChanged) {
5339 configChanged = false;
5340 sendNewConfiguration();
Romain Guy06882f82009-06-10 13:36:04 -07005341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005342 } else if (lastKey != null) {
5343 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005345 // Timeout occurred while key was down. If it is at or
5346 // past the key repeat time, dispatch the repeat.
5347 if (DEBUG_INPUT) Log.v(
5348 TAG, "Key timeout: repeat=" + nextKeyTime
5349 + ", now=" + curTime);
5350 if (curTime < nextKeyTime) {
5351 continue;
5352 }
Romain Guy06882f82009-06-10 13:36:04 -07005353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005354 lastKeyTime = nextKeyTime;
5355 nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
5356 keyRepeatCount++;
5357 if (DEBUG_INPUT) Log.v(
5358 TAG, "Key repeat: count=" + keyRepeatCount
5359 + ", next @ " + nextKeyTime);
The Android Open Source Project10592532009-03-18 17:39:46 -07005360 dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
Romain Guy06882f82009-06-10 13:36:04 -07005361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 } else {
5363 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005365 lastKeyTime = curTime;
5366 nextKeyTime = curTime + LONG_WAIT;
5367 }
Romain Guy06882f82009-06-10 13:36:04 -07005368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005369 } catch (Exception e) {
5370 Log.e(TAG,
5371 "Input thread received uncaught exception: " + e, e);
5372 }
5373 }
5374 }
5375 }
5376
5377 // -------------------------------------------------------------
5378 // Client Session State
5379 // -------------------------------------------------------------
5380
5381 private final class Session extends IWindowSession.Stub
5382 implements IBinder.DeathRecipient {
5383 final IInputMethodClient mClient;
5384 final IInputContext mInputContext;
5385 final int mUid;
5386 final int mPid;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005387 final String mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005388 SurfaceSession mSurfaceSession;
5389 int mNumWindow = 0;
5390 boolean mClientDead = false;
Romain Guy06882f82009-06-10 13:36:04 -07005391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005392 /**
5393 * Current pointer move event being dispatched to client window... must
5394 * hold key lock to access.
5395 */
5396 QueuedEvent mPendingPointerMove;
5397 WindowState mPendingPointerWindow;
Romain Guy06882f82009-06-10 13:36:04 -07005398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005399 /**
5400 * Current trackball move event being dispatched to client window... must
5401 * hold key lock to access.
5402 */
5403 QueuedEvent mPendingTrackballMove;
5404 WindowState mPendingTrackballWindow;
5405
5406 public Session(IInputMethodClient client, IInputContext inputContext) {
5407 mClient = client;
5408 mInputContext = inputContext;
5409 mUid = Binder.getCallingUid();
5410 mPid = Binder.getCallingPid();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005411 StringBuilder sb = new StringBuilder();
5412 sb.append("Session{");
5413 sb.append(Integer.toHexString(System.identityHashCode(this)));
5414 sb.append(" uid ");
5415 sb.append(mUid);
5416 sb.append("}");
5417 mStringName = sb.toString();
Romain Guy06882f82009-06-10 13:36:04 -07005418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005419 synchronized (mWindowMap) {
5420 if (mInputMethodManager == null && mHaveInputMethods) {
5421 IBinder b = ServiceManager.getService(
5422 Context.INPUT_METHOD_SERVICE);
5423 mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
5424 }
5425 }
5426 long ident = Binder.clearCallingIdentity();
5427 try {
5428 // Note: it is safe to call in to the input method manager
5429 // here because we are not holding our lock.
5430 if (mInputMethodManager != null) {
5431 mInputMethodManager.addClient(client, inputContext,
5432 mUid, mPid);
5433 } else {
5434 client.setUsingInputMethod(false);
5435 }
5436 client.asBinder().linkToDeath(this, 0);
5437 } catch (RemoteException e) {
5438 // The caller has died, so we can just forget about this.
5439 try {
5440 if (mInputMethodManager != null) {
5441 mInputMethodManager.removeClient(client);
5442 }
5443 } catch (RemoteException ee) {
5444 }
5445 } finally {
5446 Binder.restoreCallingIdentity(ident);
5447 }
5448 }
Romain Guy06882f82009-06-10 13:36:04 -07005449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005450 @Override
5451 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5452 throws RemoteException {
5453 try {
5454 return super.onTransact(code, data, reply, flags);
5455 } catch (RuntimeException e) {
5456 // Log all 'real' exceptions thrown to the caller
5457 if (!(e instanceof SecurityException)) {
5458 Log.e(TAG, "Window Session Crash", e);
5459 }
5460 throw e;
5461 }
5462 }
5463
5464 public void binderDied() {
5465 // Note: it is safe to call in to the input method manager
5466 // here because we are not holding our lock.
5467 try {
5468 if (mInputMethodManager != null) {
5469 mInputMethodManager.removeClient(mClient);
5470 }
5471 } catch (RemoteException e) {
5472 }
5473 synchronized(mWindowMap) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07005474 mClient.asBinder().unlinkToDeath(this, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005475 mClientDead = true;
5476 killSessionLocked();
5477 }
5478 }
5479
5480 public int add(IWindow window, WindowManager.LayoutParams attrs,
5481 int viewVisibility, Rect outContentInsets) {
5482 return addWindow(this, window, attrs, viewVisibility, outContentInsets);
5483 }
Romain Guy06882f82009-06-10 13:36:04 -07005484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005485 public void remove(IWindow window) {
5486 removeWindow(this, window);
5487 }
Romain Guy06882f82009-06-10 13:36:04 -07005488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005489 public int relayout(IWindow window, WindowManager.LayoutParams attrs,
5490 int requestedWidth, int requestedHeight, int viewFlags,
5491 boolean insetsPending, Rect outFrame, Rect outContentInsets,
5492 Rect outVisibleInsets, Surface outSurface) {
5493 return relayoutWindow(this, window, attrs,
5494 requestedWidth, requestedHeight, viewFlags, insetsPending,
5495 outFrame, outContentInsets, outVisibleInsets, outSurface);
5496 }
Romain Guy06882f82009-06-10 13:36:04 -07005497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005498 public void setTransparentRegion(IWindow window, Region region) {
5499 setTransparentRegionWindow(this, window, region);
5500 }
Romain Guy06882f82009-06-10 13:36:04 -07005501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005502 public void setInsets(IWindow window, int touchableInsets,
5503 Rect contentInsets, Rect visibleInsets) {
5504 setInsetsWindow(this, window, touchableInsets, contentInsets,
5505 visibleInsets);
5506 }
Romain Guy06882f82009-06-10 13:36:04 -07005507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005508 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
5509 getWindowDisplayFrame(this, window, outDisplayFrame);
5510 }
Romain Guy06882f82009-06-10 13:36:04 -07005511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005512 public void finishDrawing(IWindow window) {
5513 if (localLOGV) Log.v(
5514 TAG, "IWindow finishDrawing called for " + window);
5515 finishDrawingWindow(this, window);
5516 }
5517
5518 public void finishKey(IWindow window) {
5519 if (localLOGV) Log.v(
5520 TAG, "IWindow finishKey called for " + window);
5521 mKeyWaiter.finishedKey(this, window, false,
5522 KeyWaiter.RETURN_NOTHING);
5523 }
5524
5525 public MotionEvent getPendingPointerMove(IWindow window) {
5526 if (localLOGV) Log.v(
5527 TAG, "IWindow getPendingMotionEvent called for " + window);
5528 return mKeyWaiter.finishedKey(this, window, false,
5529 KeyWaiter.RETURN_PENDING_POINTER);
5530 }
Romain Guy06882f82009-06-10 13:36:04 -07005531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005532 public MotionEvent getPendingTrackballMove(IWindow window) {
5533 if (localLOGV) Log.v(
5534 TAG, "IWindow getPendingMotionEvent called for " + window);
5535 return mKeyWaiter.finishedKey(this, window, false,
5536 KeyWaiter.RETURN_PENDING_TRACKBALL);
5537 }
5538
5539 public void setInTouchMode(boolean mode) {
5540 synchronized(mWindowMap) {
5541 mInTouchMode = mode;
5542 }
5543 }
5544
5545 public boolean getInTouchMode() {
5546 synchronized(mWindowMap) {
5547 return mInTouchMode;
5548 }
5549 }
5550
5551 public boolean performHapticFeedback(IWindow window, int effectId,
5552 boolean always) {
5553 synchronized(mWindowMap) {
5554 long ident = Binder.clearCallingIdentity();
5555 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005556 return mPolicy.performHapticFeedbackLw(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005557 windowForClientLocked(this, window), effectId, always);
5558 } finally {
5559 Binder.restoreCallingIdentity(ident);
5560 }
5561 }
5562 }
Romain Guy06882f82009-06-10 13:36:04 -07005563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005564 void windowAddedLocked() {
5565 if (mSurfaceSession == null) {
5566 if (localLOGV) Log.v(
5567 TAG, "First window added to " + this + ", creating SurfaceSession");
5568 mSurfaceSession = new SurfaceSession();
5569 mSessions.add(this);
5570 }
5571 mNumWindow++;
5572 }
5573
5574 void windowRemovedLocked() {
5575 mNumWindow--;
5576 killSessionLocked();
5577 }
Romain Guy06882f82009-06-10 13:36:04 -07005578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005579 void killSessionLocked() {
5580 if (mNumWindow <= 0 && mClientDead) {
5581 mSessions.remove(this);
5582 if (mSurfaceSession != null) {
5583 if (localLOGV) Log.v(
5584 TAG, "Last window removed from " + this
5585 + ", destroying " + mSurfaceSession);
5586 try {
5587 mSurfaceSession.kill();
5588 } catch (Exception e) {
5589 Log.w(TAG, "Exception thrown when killing surface session "
5590 + mSurfaceSession + " in session " + this
5591 + ": " + e.toString());
5592 }
5593 mSurfaceSession = null;
5594 }
5595 }
5596 }
Romain Guy06882f82009-06-10 13:36:04 -07005597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005598 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005599 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
5600 pw.print(" mClientDead="); pw.print(mClientDead);
5601 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
5602 if (mPendingPointerWindow != null || mPendingPointerMove != null) {
5603 pw.print(prefix);
5604 pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
5605 pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
5606 }
5607 if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
5608 pw.print(prefix);
5609 pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
5610 pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
5611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005612 }
5613
5614 @Override
5615 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005616 return mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005617 }
5618 }
5619
5620 // -------------------------------------------------------------
5621 // Client Window State
5622 // -------------------------------------------------------------
5623
5624 private final class WindowState implements WindowManagerPolicy.WindowState {
5625 final Session mSession;
5626 final IWindow mClient;
5627 WindowToken mToken;
The Android Open Source Project10592532009-03-18 17:39:46 -07005628 WindowToken mRootToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005629 AppWindowToken mAppToken;
5630 AppWindowToken mTargetAppToken;
5631 final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
5632 final DeathRecipient mDeathRecipient;
5633 final WindowState mAttachedWindow;
5634 final ArrayList mChildWindows = new ArrayList();
5635 final int mBaseLayer;
5636 final int mSubLayer;
5637 final boolean mLayoutAttached;
5638 final boolean mIsImWindow;
5639 int mViewVisibility;
5640 boolean mPolicyVisibility = true;
5641 boolean mPolicyVisibilityAfterAnim = true;
5642 boolean mAppFreezing;
5643 Surface mSurface;
5644 boolean mAttachedHidden; // is our parent window hidden?
5645 boolean mLastHidden; // was this window last hidden?
5646 int mRequestedWidth;
5647 int mRequestedHeight;
5648 int mLastRequestedWidth;
5649 int mLastRequestedHeight;
5650 int mReqXPos;
5651 int mReqYPos;
5652 int mLayer;
5653 int mAnimLayer;
5654 int mLastLayer;
5655 boolean mHaveFrame;
5656
5657 WindowState mNextOutsideTouch;
Romain Guy06882f82009-06-10 13:36:04 -07005658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005659 // Actual frame shown on-screen (may be modified by animation)
5660 final Rect mShownFrame = new Rect();
5661 final Rect mLastShownFrame = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005663 /**
5664 * Insets that determine the actually visible area
5665 */
5666 final Rect mVisibleInsets = new Rect();
5667 final Rect mLastVisibleInsets = new Rect();
5668 boolean mVisibleInsetsChanged;
5669
5670 /**
5671 * Insets that are covered by system windows
5672 */
5673 final Rect mContentInsets = new Rect();
5674 final Rect mLastContentInsets = new Rect();
5675 boolean mContentInsetsChanged;
5676
5677 /**
5678 * Set to true if we are waiting for this window to receive its
5679 * given internal insets before laying out other windows based on it.
5680 */
5681 boolean mGivenInsetsPending;
Romain Guy06882f82009-06-10 13:36:04 -07005682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005683 /**
5684 * These are the content insets that were given during layout for
5685 * this window, to be applied to windows behind it.
5686 */
5687 final Rect mGivenContentInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005689 /**
5690 * These are the visible insets that were given during layout for
5691 * this window, to be applied to windows behind it.
5692 */
5693 final Rect mGivenVisibleInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005695 /**
5696 * Flag indicating whether the touchable region should be adjusted by
5697 * the visible insets; if false the area outside the visible insets is
5698 * NOT touchable, so we must use those to adjust the frame during hit
5699 * tests.
5700 */
5701 int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
Romain Guy06882f82009-06-10 13:36:04 -07005702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005703 // Current transformation being applied.
5704 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
5705 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
5706 float mHScale=1, mVScale=1;
5707 float mLastHScale=1, mLastVScale=1;
5708 final Matrix mTmpMatrix = new Matrix();
5709
5710 // "Real" frame that the application sees.
5711 final Rect mFrame = new Rect();
5712 final Rect mLastFrame = new Rect();
5713
5714 final Rect mContainingFrame = new Rect();
5715 final Rect mDisplayFrame = new Rect();
5716 final Rect mContentFrame = new Rect();
5717 final Rect mVisibleFrame = new Rect();
5718
5719 float mShownAlpha = 1;
5720 float mAlpha = 1;
5721 float mLastAlpha = 1;
5722
5723 // Set to true if, when the window gets displayed, it should perform
5724 // an enter animation.
5725 boolean mEnterAnimationPending;
5726
5727 // Currently running animation.
5728 boolean mAnimating;
5729 boolean mLocalAnimating;
5730 Animation mAnimation;
5731 boolean mAnimationIsEntrance;
5732 boolean mHasTransformation;
5733 boolean mHasLocalTransformation;
5734 final Transformation mTransformation = new Transformation();
5735
5736 // This is set after IWindowSession.relayout() has been called at
5737 // least once for the window. It allows us to detect the situation
5738 // where we don't yet have a surface, but should have one soon, so
5739 // we can give the window focus before waiting for the relayout.
5740 boolean mRelayoutCalled;
Romain Guy06882f82009-06-10 13:36:04 -07005741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 // This is set after the Surface has been created but before the
5743 // window has been drawn. During this time the surface is hidden.
5744 boolean mDrawPending;
5745
5746 // This is set after the window has finished drawing for the first
5747 // time but before its surface is shown. The surface will be
5748 // displayed when the next layout is run.
5749 boolean mCommitDrawPending;
5750
5751 // This is set during the time after the window's drawing has been
5752 // committed, and before its surface is actually shown. It is used
5753 // to delay showing the surface until all windows in a token are ready
5754 // to be shown.
5755 boolean mReadyToShow;
Romain Guy06882f82009-06-10 13:36:04 -07005756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005757 // Set when the window has been shown in the screen the first time.
5758 boolean mHasDrawn;
5759
5760 // Currently running an exit animation?
5761 boolean mExiting;
5762
5763 // Currently on the mDestroySurface list?
5764 boolean mDestroying;
Romain Guy06882f82009-06-10 13:36:04 -07005765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005766 // Completely remove from window manager after exit animation?
5767 boolean mRemoveOnExit;
5768
5769 // Set when the orientation is changing and this window has not yet
5770 // been updated for the new orientation.
5771 boolean mOrientationChanging;
Romain Guy06882f82009-06-10 13:36:04 -07005772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005773 // Is this window now (or just being) removed?
5774 boolean mRemoved;
Romain Guy06882f82009-06-10 13:36:04 -07005775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005776 WindowState(Session s, IWindow c, WindowToken token,
5777 WindowState attachedWindow, WindowManager.LayoutParams a,
5778 int viewVisibility) {
5779 mSession = s;
5780 mClient = c;
5781 mToken = token;
5782 mAttrs.copyFrom(a);
5783 mViewVisibility = viewVisibility;
5784 DeathRecipient deathRecipient = new DeathRecipient();
5785 mAlpha = a.alpha;
5786 if (localLOGV) Log.v(
5787 TAG, "Window " + this + " client=" + c.asBinder()
5788 + " token=" + token + " (" + mAttrs.token + ")");
5789 try {
5790 c.asBinder().linkToDeath(deathRecipient, 0);
5791 } catch (RemoteException e) {
5792 mDeathRecipient = null;
5793 mAttachedWindow = null;
5794 mLayoutAttached = false;
5795 mIsImWindow = false;
5796 mBaseLayer = 0;
5797 mSubLayer = 0;
5798 return;
5799 }
5800 mDeathRecipient = deathRecipient;
Romain Guy06882f82009-06-10 13:36:04 -07005801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005802 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
5803 mAttrs.type <= LAST_SUB_WINDOW)) {
5804 // The multiplier here is to reserve space for multiple
5805 // windows in the same type layer.
5806 mBaseLayer = mPolicy.windowTypeToLayerLw(
5807 attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
5808 + TYPE_LAYER_OFFSET;
5809 mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
5810 mAttachedWindow = attachedWindow;
5811 mAttachedWindow.mChildWindows.add(this);
5812 mLayoutAttached = mAttrs.type !=
5813 WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
5814 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
5815 || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5816 } else {
5817 // The multiplier here is to reserve space for multiple
5818 // windows in the same type layer.
5819 mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
5820 * TYPE_LAYER_MULTIPLIER
5821 + TYPE_LAYER_OFFSET;
5822 mSubLayer = 0;
5823 mAttachedWindow = null;
5824 mLayoutAttached = false;
5825 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
5826 || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5827 }
5828
5829 WindowState appWin = this;
5830 while (appWin.mAttachedWindow != null) {
5831 appWin = mAttachedWindow;
5832 }
5833 WindowToken appToken = appWin.mToken;
5834 while (appToken.appWindowToken == null) {
5835 WindowToken parent = mTokenMap.get(appToken.token);
5836 if (parent == null || appToken == parent) {
5837 break;
5838 }
5839 appToken = parent;
5840 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005841 mRootToken = appToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005842 mAppToken = appToken.appWindowToken;
5843
5844 mSurface = null;
5845 mRequestedWidth = 0;
5846 mRequestedHeight = 0;
5847 mLastRequestedWidth = 0;
5848 mLastRequestedHeight = 0;
5849 mReqXPos = 0;
5850 mReqYPos = 0;
5851 mLayer = 0;
5852 mAnimLayer = 0;
5853 mLastLayer = 0;
5854 }
5855
5856 void attach() {
5857 if (localLOGV) Log.v(
5858 TAG, "Attaching " + this + " token=" + mToken
5859 + ", list=" + mToken.windows);
5860 mSession.windowAddedLocked();
5861 }
5862
5863 public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
5864 mHaveFrame = true;
5865
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005866 final Rect container = mContainingFrame;
5867 container.set(pf);
5868
5869 final Rect display = mDisplayFrame;
5870 display.set(df);
5871
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07005872 if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005873 container.intersect(mCompatibleScreenFrame);
5874 display.intersect(mCompatibleScreenFrame);
5875 }
5876
5877 final int pw = container.right - container.left;
5878 final int ph = container.bottom - container.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005879
5880 int w,h;
5881 if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
5882 w = mAttrs.width < 0 ? pw : mAttrs.width;
5883 h = mAttrs.height< 0 ? ph : mAttrs.height;
5884 } else {
5885 w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
5886 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
5887 }
Romain Guy06882f82009-06-10 13:36:04 -07005888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005889 final Rect content = mContentFrame;
5890 content.set(cf);
Romain Guy06882f82009-06-10 13:36:04 -07005891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892 final Rect visible = mVisibleFrame;
5893 visible.set(vf);
Romain Guy06882f82009-06-10 13:36:04 -07005894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005895 final Rect frame = mFrame;
Romain Guy06882f82009-06-10 13:36:04 -07005896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005897 //System.out.println("In: w=" + w + " h=" + h + " container=" +
5898 // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
5899
5900 Gravity.apply(mAttrs.gravity, w, h, container,
5901 (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
5902 (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
5903
5904 //System.out.println("Out: " + mFrame);
5905
5906 // Now make sure the window fits in the overall display.
5907 Gravity.applyDisplay(mAttrs.gravity, df, frame);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005909 // Make sure the content and visible frames are inside of the
5910 // final window frame.
5911 if (content.left < frame.left) content.left = frame.left;
5912 if (content.top < frame.top) content.top = frame.top;
5913 if (content.right > frame.right) content.right = frame.right;
5914 if (content.bottom > frame.bottom) content.bottom = frame.bottom;
5915 if (visible.left < frame.left) visible.left = frame.left;
5916 if (visible.top < frame.top) visible.top = frame.top;
5917 if (visible.right > frame.right) visible.right = frame.right;
5918 if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005920 final Rect contentInsets = mContentInsets;
5921 contentInsets.left = content.left-frame.left;
5922 contentInsets.top = content.top-frame.top;
5923 contentInsets.right = frame.right-content.right;
5924 contentInsets.bottom = frame.bottom-content.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005926 final Rect visibleInsets = mVisibleInsets;
5927 visibleInsets.left = visible.left-frame.left;
5928 visibleInsets.top = visible.top-frame.top;
5929 visibleInsets.right = frame.right-visible.right;
5930 visibleInsets.bottom = frame.bottom-visible.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005932 if (localLOGV) {
5933 //if ("com.google.android.youtube".equals(mAttrs.packageName)
5934 // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
5935 Log.v(TAG, "Resolving (mRequestedWidth="
5936 + mRequestedWidth + ", mRequestedheight="
5937 + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
5938 + "): frame=" + mFrame.toShortString()
5939 + " ci=" + contentInsets.toShortString()
5940 + " vi=" + visibleInsets.toShortString());
5941 //}
5942 }
5943 }
Romain Guy06882f82009-06-10 13:36:04 -07005944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005945 public Rect getFrameLw() {
5946 return mFrame;
5947 }
5948
5949 public Rect getShownFrameLw() {
5950 return mShownFrame;
5951 }
5952
5953 public Rect getDisplayFrameLw() {
5954 return mDisplayFrame;
5955 }
5956
5957 public Rect getContentFrameLw() {
5958 return mContentFrame;
5959 }
5960
5961 public Rect getVisibleFrameLw() {
5962 return mVisibleFrame;
5963 }
5964
5965 public boolean getGivenInsetsPendingLw() {
5966 return mGivenInsetsPending;
5967 }
5968
5969 public Rect getGivenContentInsetsLw() {
5970 return mGivenContentInsets;
5971 }
Romain Guy06882f82009-06-10 13:36:04 -07005972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005973 public Rect getGivenVisibleInsetsLw() {
5974 return mGivenVisibleInsets;
5975 }
Romain Guy06882f82009-06-10 13:36:04 -07005976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005977 public WindowManager.LayoutParams getAttrs() {
5978 return mAttrs;
5979 }
5980
5981 public int getSurfaceLayer() {
5982 return mLayer;
5983 }
Romain Guy06882f82009-06-10 13:36:04 -07005984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005985 public IApplicationToken getAppToken() {
5986 return mAppToken != null ? mAppToken.appToken : null;
5987 }
5988
5989 public boolean hasAppShownWindows() {
5990 return mAppToken != null ? mAppToken.firstWindowDrawn : false;
5991 }
5992
5993 public boolean hasAppStartingIcon() {
5994 return mAppToken != null ? (mAppToken.startingData != null) : false;
5995 }
5996
5997 public WindowManagerPolicy.WindowState getAppStartingWindow() {
5998 return mAppToken != null ? mAppToken.startingWindow : null;
5999 }
6000
6001 public void setAnimation(Animation anim) {
6002 if (localLOGV) Log.v(
6003 TAG, "Setting animation in " + this + ": " + anim);
6004 mAnimating = false;
6005 mLocalAnimating = false;
6006 mAnimation = anim;
6007 mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
6008 mAnimation.scaleCurrentDuration(mWindowAnimationScale);
6009 }
6010
6011 public void clearAnimation() {
6012 if (mAnimation != null) {
6013 mAnimating = true;
6014 mLocalAnimating = false;
6015 mAnimation = null;
6016 }
6017 }
Romain Guy06882f82009-06-10 13:36:04 -07006018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006019 Surface createSurfaceLocked() {
6020 if (mSurface == null) {
6021 mDrawPending = true;
6022 mCommitDrawPending = false;
6023 mReadyToShow = false;
6024 if (mAppToken != null) {
6025 mAppToken.allDrawn = false;
6026 }
6027
6028 int flags = 0;
6029 if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
6030 flags |= Surface.HARDWARE;
6031 } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
6032 flags |= Surface.GPU;
6033 } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
6034 flags |= Surface.PUSH_BUFFERS;
6035 }
6036
6037 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
6038 flags |= Surface.SECURE;
6039 }
6040 if (DEBUG_VISIBILITY) Log.v(
6041 TAG, "Creating surface in session "
6042 + mSession.mSurfaceSession + " window " + this
6043 + " w=" + mFrame.width()
6044 + " h=" + mFrame.height() + " format="
6045 + mAttrs.format + " flags=" + flags);
6046
6047 int w = mFrame.width();
6048 int h = mFrame.height();
6049 if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
6050 // for a scaled surface, we always want the requested
6051 // size.
6052 w = mRequestedWidth;
6053 h = mRequestedHeight;
6054 }
6055
6056 try {
6057 mSurface = new Surface(
Romain Guy06882f82009-06-10 13:36:04 -07006058 mSession.mSurfaceSession, mSession.mPid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006059 0, w, h, mAttrs.format, flags);
6060 } catch (Surface.OutOfResourcesException e) {
6061 Log.w(TAG, "OutOfResourcesException creating surface");
6062 reclaimSomeSurfaceMemoryLocked(this, "create");
6063 return null;
6064 } catch (Exception e) {
6065 Log.e(TAG, "Exception creating surface", e);
6066 return null;
6067 }
Romain Guy06882f82009-06-10 13:36:04 -07006068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006069 if (localLOGV) Log.v(
6070 TAG, "Got surface: " + mSurface
6071 + ", set left=" + mFrame.left + " top=" + mFrame.top
6072 + ", animLayer=" + mAnimLayer);
6073 if (SHOW_TRANSACTIONS) {
6074 Log.i(TAG, ">>> OPEN TRANSACTION");
6075 Log.i(TAG, " SURFACE " + mSurface + ": CREATE ("
6076 + mAttrs.getTitle() + ") pos=(" +
6077 mFrame.left + "," + mFrame.top + ") (" +
6078 mFrame.width() + "x" + mFrame.height() + "), layer=" +
6079 mAnimLayer + " HIDE");
6080 }
6081 Surface.openTransaction();
6082 try {
6083 try {
6084 mSurface.setPosition(mFrame.left, mFrame.top);
6085 mSurface.setLayer(mAnimLayer);
6086 mSurface.hide();
6087 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
6088 mSurface.setFlags(Surface.SURFACE_DITHER,
6089 Surface.SURFACE_DITHER);
6090 }
6091 } catch (RuntimeException e) {
6092 Log.w(TAG, "Error creating surface in " + w, e);
6093 reclaimSomeSurfaceMemoryLocked(this, "create-init");
6094 }
6095 mLastHidden = true;
6096 } finally {
6097 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
6098 Surface.closeTransaction();
6099 }
6100 if (localLOGV) Log.v(
6101 TAG, "Created surface " + this);
6102 }
6103 return mSurface;
6104 }
Romain Guy06882f82009-06-10 13:36:04 -07006105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006106 void destroySurfaceLocked() {
6107 // Window is no longer on-screen, so can no longer receive
6108 // key events... if we were waiting for it to finish
6109 // handling a key event, the wait is over!
6110 mKeyWaiter.finishedKey(mSession, mClient, true,
6111 KeyWaiter.RETURN_NOTHING);
6112 mKeyWaiter.releasePendingPointerLocked(mSession);
6113 mKeyWaiter.releasePendingTrackballLocked(mSession);
6114
6115 if (mAppToken != null && this == mAppToken.startingWindow) {
6116 mAppToken.startingDisplayed = false;
6117 }
Romain Guy06882f82009-06-10 13:36:04 -07006118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006119 if (localLOGV) Log.v(
6120 TAG, "Window " + this
6121 + " destroying surface " + mSurface + ", session " + mSession);
6122 if (mSurface != null) {
6123 try {
6124 if (SHOW_TRANSACTIONS) {
6125 RuntimeException ex = new RuntimeException();
6126 ex.fillInStackTrace();
6127 Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
6128 + mAttrs.getTitle() + ")", ex);
6129 }
6130 mSurface.clear();
6131 } catch (RuntimeException e) {
6132 Log.w(TAG, "Exception thrown when destroying Window " + this
6133 + " surface " + mSurface + " session " + mSession
6134 + ": " + e.toString());
6135 }
6136 mSurface = null;
6137 mDrawPending = false;
6138 mCommitDrawPending = false;
6139 mReadyToShow = false;
6140
6141 int i = mChildWindows.size();
6142 while (i > 0) {
6143 i--;
6144 WindowState c = (WindowState)mChildWindows.get(i);
6145 c.mAttachedHidden = true;
6146 }
6147 }
6148 }
6149
6150 boolean finishDrawingLocked() {
6151 if (mDrawPending) {
6152 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
6153 TAG, "finishDrawingLocked: " + mSurface);
6154 mCommitDrawPending = true;
6155 mDrawPending = false;
6156 return true;
6157 }
6158 return false;
6159 }
6160
6161 // This must be called while inside a transaction.
6162 void commitFinishDrawingLocked(long currentTime) {
6163 //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
6164 if (!mCommitDrawPending) {
6165 return;
6166 }
6167 mCommitDrawPending = false;
6168 mReadyToShow = true;
6169 final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING;
6170 final AppWindowToken atoken = mAppToken;
6171 if (atoken == null || atoken.allDrawn || starting) {
6172 performShowLocked();
6173 }
6174 }
6175
6176 // This must be called while inside a transaction.
6177 boolean performShowLocked() {
6178 if (DEBUG_VISIBILITY) {
6179 RuntimeException e = new RuntimeException();
6180 e.fillInStackTrace();
6181 Log.v(TAG, "performShow on " + this
6182 + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
6183 + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
6184 }
6185 if (mReadyToShow && isReadyForDisplay()) {
6186 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i(
6187 TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)");
6188 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this
6189 + " during animation: policyVis=" + mPolicyVisibility
6190 + " attHidden=" + mAttachedHidden
6191 + " tok.hiddenRequested="
6192 + (mAppToken != null ? mAppToken.hiddenRequested : false)
6193 + " tok.idden="
6194 + (mAppToken != null ? mAppToken.hidden : false)
6195 + " animating=" + mAnimating
6196 + " tok animating="
6197 + (mAppToken != null ? mAppToken.animating : false));
6198 if (!showSurfaceRobustlyLocked(this)) {
6199 return false;
6200 }
6201 mLastAlpha = -1;
6202 mHasDrawn = true;
6203 mLastHidden = false;
6204 mReadyToShow = false;
6205 enableScreenIfNeededLocked();
6206
6207 applyEnterAnimationLocked(this);
Romain Guy06882f82009-06-10 13:36:04 -07006208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006209 int i = mChildWindows.size();
6210 while (i > 0) {
6211 i--;
6212 WindowState c = (WindowState)mChildWindows.get(i);
6213 if (c.mSurface != null && c.mAttachedHidden) {
6214 c.mAttachedHidden = false;
6215 c.performShowLocked();
6216 }
6217 }
Romain Guy06882f82009-06-10 13:36:04 -07006218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006219 if (mAttrs.type != TYPE_APPLICATION_STARTING
6220 && mAppToken != null) {
6221 mAppToken.firstWindowDrawn = true;
6222 if (mAnimation == null && mAppToken.startingData != null) {
6223 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6224 + mToken
6225 + ": first real window is shown, no animation");
6226 mFinishedStarting.add(mAppToken);
6227 mH.sendEmptyMessage(H.FINISHED_STARTING);
6228 }
6229 mAppToken.updateReportedVisibilityLocked();
6230 }
6231 }
6232 return true;
6233 }
Romain Guy06882f82009-06-10 13:36:04 -07006234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006235 // This must be called while inside a transaction. Returns true if
6236 // there is more animation to run.
6237 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6238 if (!mDisplayFrozen) {
6239 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07006240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006241 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
6242 mHasTransformation = true;
6243 mHasLocalTransformation = true;
6244 if (!mLocalAnimating) {
6245 if (DEBUG_ANIM) Log.v(
6246 TAG, "Starting animation in " + this +
6247 " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
6248 " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
6249 mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
6250 mAnimation.setStartTime(currentTime);
6251 mLocalAnimating = true;
6252 mAnimating = true;
6253 }
6254 mTransformation.clear();
6255 final boolean more = mAnimation.getTransformation(
6256 currentTime, mTransformation);
6257 if (DEBUG_ANIM) Log.v(
6258 TAG, "Stepped animation in " + this +
6259 ": more=" + more + ", xform=" + mTransformation);
6260 if (more) {
6261 // we're not done!
6262 return true;
6263 }
6264 if (DEBUG_ANIM) Log.v(
6265 TAG, "Finished animation in " + this +
6266 " @ " + currentTime);
6267 mAnimation = null;
6268 //WindowManagerService.this.dump();
6269 }
6270 mHasLocalTransformation = false;
6271 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
6272 && mAppToken.hasTransformation) {
6273 // When our app token is animating, we kind-of pretend like
6274 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
6275 // part of this check means that we will only do this if
6276 // our window is not currently exiting, or it is not
6277 // locally animating itself. The idea being that one that
6278 // is exiting and doing a local animation should be removed
6279 // once that animation is done.
6280 mAnimating = true;
6281 mHasTransformation = true;
6282 mTransformation.clear();
6283 return false;
6284 } else if (mHasTransformation) {
6285 // Little trick to get through the path below to act like
6286 // we have finished an animation.
6287 mAnimating = true;
6288 } else if (isAnimating()) {
6289 mAnimating = true;
6290 }
6291 } else if (mAnimation != null) {
6292 // If the display is frozen, and there is a pending animation,
6293 // clear it and make sure we run the cleanup code.
6294 mAnimating = true;
6295 mLocalAnimating = true;
6296 mAnimation = null;
6297 }
Romain Guy06882f82009-06-10 13:36:04 -07006298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006299 if (!mAnimating && !mLocalAnimating) {
6300 return false;
6301 }
6302
6303 if (DEBUG_ANIM) Log.v(
6304 TAG, "Animation done in " + this + ": exiting=" + mExiting
6305 + ", reportedVisible="
6306 + (mAppToken != null ? mAppToken.reportedVisible : false));
Romain Guy06882f82009-06-10 13:36:04 -07006307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006308 mAnimating = false;
6309 mLocalAnimating = false;
6310 mAnimation = null;
6311 mAnimLayer = mLayer;
6312 if (mIsImWindow) {
6313 mAnimLayer += mInputMethodAnimLayerAdjustment;
6314 }
6315 if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
6316 + " anim layer: " + mAnimLayer);
6317 mHasTransformation = false;
6318 mHasLocalTransformation = false;
6319 mPolicyVisibility = mPolicyVisibilityAfterAnim;
6320 mTransformation.clear();
6321 if (mHasDrawn
6322 && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
6323 && mAppToken != null
6324 && mAppToken.firstWindowDrawn
6325 && mAppToken.startingData != null) {
6326 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6327 + mToken + ": first real window done animating");
6328 mFinishedStarting.add(mAppToken);
6329 mH.sendEmptyMessage(H.FINISHED_STARTING);
6330 }
Romain Guy06882f82009-06-10 13:36:04 -07006331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006332 finishExit();
6333
6334 if (mAppToken != null) {
6335 mAppToken.updateReportedVisibilityLocked();
6336 }
6337
6338 return false;
6339 }
6340
6341 void finishExit() {
6342 if (DEBUG_ANIM) Log.v(
6343 TAG, "finishExit in " + this
6344 + ": exiting=" + mExiting
6345 + " remove=" + mRemoveOnExit
6346 + " windowAnimating=" + isWindowAnimating());
Romain Guy06882f82009-06-10 13:36:04 -07006347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006348 final int N = mChildWindows.size();
6349 for (int i=0; i<N; i++) {
6350 ((WindowState)mChildWindows.get(i)).finishExit();
6351 }
Romain Guy06882f82009-06-10 13:36:04 -07006352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006353 if (!mExiting) {
6354 return;
6355 }
Romain Guy06882f82009-06-10 13:36:04 -07006356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006357 if (isWindowAnimating()) {
6358 return;
6359 }
6360
6361 if (localLOGV) Log.v(
6362 TAG, "Exit animation finished in " + this
6363 + ": remove=" + mRemoveOnExit);
6364 if (mSurface != null) {
6365 mDestroySurface.add(this);
6366 mDestroying = true;
6367 if (SHOW_TRANSACTIONS) Log.i(
6368 TAG, " SURFACE " + mSurface + ": HIDE (finishExit)");
6369 try {
6370 mSurface.hide();
6371 } catch (RuntimeException e) {
6372 Log.w(TAG, "Error hiding surface in " + this, e);
6373 }
6374 mLastHidden = true;
6375 mKeyWaiter.releasePendingPointerLocked(mSession);
6376 }
6377 mExiting = false;
6378 if (mRemoveOnExit) {
6379 mPendingRemove.add(this);
6380 mRemoveOnExit = false;
6381 }
6382 }
Romain Guy06882f82009-06-10 13:36:04 -07006383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006384 boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
6385 if (dsdx < .99999f || dsdx > 1.00001f) return false;
6386 if (dtdy < .99999f || dtdy > 1.00001f) return false;
6387 if (dtdx < -.000001f || dtdx > .000001f) return false;
6388 if (dsdy < -.000001f || dsdy > .000001f) return false;
6389 return true;
6390 }
Romain Guy06882f82009-06-10 13:36:04 -07006391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006392 void computeShownFrameLocked() {
6393 final boolean selfTransformation = mHasLocalTransformation;
6394 Transformation attachedTransformation =
6395 (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
6396 ? mAttachedWindow.mTransformation : null;
6397 Transformation appTransformation =
6398 (mAppToken != null && mAppToken.hasTransformation)
6399 ? mAppToken.transformation : null;
6400 if (selfTransformation || attachedTransformation != null
6401 || appTransformation != null) {
Romain Guy06882f82009-06-10 13:36:04 -07006402 // cache often used attributes locally
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006403 final Rect frame = mFrame;
6404 final float tmpFloats[] = mTmpFloats;
6405 final Matrix tmpMatrix = mTmpMatrix;
6406
6407 // Compute the desired transformation.
6408 tmpMatrix.setTranslate(frame.left, frame.top);
6409 if (selfTransformation) {
6410 tmpMatrix.preConcat(mTransformation.getMatrix());
6411 }
6412 if (attachedTransformation != null) {
6413 tmpMatrix.preConcat(attachedTransformation.getMatrix());
6414 }
6415 if (appTransformation != null) {
6416 tmpMatrix.preConcat(appTransformation.getMatrix());
6417 }
6418
6419 // "convert" it into SurfaceFlinger's format
6420 // (a 2x2 matrix + an offset)
6421 // Here we must not transform the position of the surface
6422 // since it is already included in the transformation.
6423 //Log.i(TAG, "Transform: " + matrix);
Romain Guy06882f82009-06-10 13:36:04 -07006424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006425 tmpMatrix.getValues(tmpFloats);
6426 mDsDx = tmpFloats[Matrix.MSCALE_X];
6427 mDtDx = tmpFloats[Matrix.MSKEW_X];
6428 mDsDy = tmpFloats[Matrix.MSKEW_Y];
6429 mDtDy = tmpFloats[Matrix.MSCALE_Y];
6430 int x = (int)tmpFloats[Matrix.MTRANS_X];
6431 int y = (int)tmpFloats[Matrix.MTRANS_Y];
6432 int w = frame.width();
6433 int h = frame.height();
6434 mShownFrame.set(x, y, x+w, y+h);
6435
6436 // Now set the alpha... but because our current hardware
6437 // can't do alpha transformation on a non-opaque surface,
6438 // turn it off if we are running an animation that is also
6439 // transforming since it is more important to have that
6440 // animation be smooth.
6441 mShownAlpha = mAlpha;
6442 if (!mLimitedAlphaCompositing
6443 || (!PixelFormat.formatHasAlpha(mAttrs.format)
6444 || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
6445 && x == frame.left && y == frame.top))) {
6446 //Log.i(TAG, "Applying alpha transform");
6447 if (selfTransformation) {
6448 mShownAlpha *= mTransformation.getAlpha();
6449 }
6450 if (attachedTransformation != null) {
6451 mShownAlpha *= attachedTransformation.getAlpha();
6452 }
6453 if (appTransformation != null) {
6454 mShownAlpha *= appTransformation.getAlpha();
6455 }
6456 } else {
6457 //Log.i(TAG, "Not applying alpha transform");
6458 }
Romain Guy06882f82009-06-10 13:36:04 -07006459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006460 if (localLOGV) Log.v(
6461 TAG, "Continuing animation in " + this +
6462 ": " + mShownFrame +
6463 ", alpha=" + mTransformation.getAlpha());
6464 return;
6465 }
Romain Guy06882f82009-06-10 13:36:04 -07006466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006467 mShownFrame.set(mFrame);
6468 mShownAlpha = mAlpha;
6469 mDsDx = 1;
6470 mDtDx = 0;
6471 mDsDy = 0;
6472 mDtDy = 1;
6473 }
Romain Guy06882f82009-06-10 13:36:04 -07006474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006475 /**
6476 * Is this window visible? It is not visible if there is no
6477 * surface, or we are in the process of running an exit animation
6478 * that will remove the surface, or its app token has been hidden.
6479 */
6480 public boolean isVisibleLw() {
6481 final AppWindowToken atoken = mAppToken;
6482 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6483 && (atoken == null || !atoken.hiddenRequested)
6484 && !mExiting && !mDestroying;
6485 }
6486
6487 /**
6488 * Is this window visible, ignoring its app token? It is not visible
6489 * if there is no surface, or we are in the process of running an exit animation
6490 * that will remove the surface.
6491 */
6492 public boolean isWinVisibleLw() {
6493 final AppWindowToken atoken = mAppToken;
6494 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6495 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
6496 && !mExiting && !mDestroying;
6497 }
6498
6499 /**
6500 * The same as isVisible(), but follows the current hidden state of
6501 * the associated app token, not the pending requested hidden state.
6502 */
6503 boolean isVisibleNow() {
6504 return mSurface != null && mPolicyVisibility && !mAttachedHidden
The Android Open Source Project10592532009-03-18 17:39:46 -07006505 && !mRootToken.hidden && !mExiting && !mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006506 }
6507
6508 /**
6509 * Same as isVisible(), but we also count it as visible between the
6510 * call to IWindowSession.add() and the first relayout().
6511 */
6512 boolean isVisibleOrAdding() {
6513 final AppWindowToken atoken = mAppToken;
6514 return (mSurface != null
6515 || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
6516 && mPolicyVisibility && !mAttachedHidden
6517 && (atoken == null || !atoken.hiddenRequested)
6518 && !mExiting && !mDestroying;
6519 }
6520
6521 /**
6522 * Is this window currently on-screen? It is on-screen either if it
6523 * is visible or it is currently running an animation before no longer
6524 * being visible.
6525 */
6526 boolean isOnScreen() {
6527 final AppWindowToken atoken = mAppToken;
6528 if (atoken != null) {
6529 return mSurface != null && mPolicyVisibility && !mDestroying
6530 && ((!mAttachedHidden && !atoken.hiddenRequested)
6531 || mAnimating || atoken.animating);
6532 } else {
6533 return mSurface != null && mPolicyVisibility && !mDestroying
6534 && (!mAttachedHidden || mAnimating);
6535 }
6536 }
Romain Guy06882f82009-06-10 13:36:04 -07006537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006538 /**
6539 * Like isOnScreen(), but we don't return true if the window is part
6540 * of a transition that has not yet been started.
6541 */
6542 boolean isReadyForDisplay() {
6543 final AppWindowToken atoken = mAppToken;
6544 final boolean animating = atoken != null ? atoken.animating : false;
6545 return mSurface != null && mPolicyVisibility && !mDestroying
The Android Open Source Project10592532009-03-18 17:39:46 -07006546 && ((!mAttachedHidden && !mRootToken.hidden)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006547 || mAnimating || animating);
6548 }
6549
6550 /** Is the window or its container currently animating? */
6551 boolean isAnimating() {
6552 final WindowState attached = mAttachedWindow;
6553 final AppWindowToken atoken = mAppToken;
6554 return mAnimation != null
6555 || (attached != null && attached.mAnimation != null)
Romain Guy06882f82009-06-10 13:36:04 -07006556 || (atoken != null &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006557 (atoken.animation != null
6558 || atoken.inPendingTransaction));
6559 }
6560
6561 /** Is this window currently animating? */
6562 boolean isWindowAnimating() {
6563 return mAnimation != null;
6564 }
6565
6566 /**
6567 * Like isOnScreen, but returns false if the surface hasn't yet
6568 * been drawn.
6569 */
6570 public boolean isDisplayedLw() {
6571 final AppWindowToken atoken = mAppToken;
6572 return mSurface != null && mPolicyVisibility && !mDestroying
6573 && !mDrawPending && !mCommitDrawPending
6574 && ((!mAttachedHidden &&
6575 (atoken == null || !atoken.hiddenRequested))
6576 || mAnimating);
6577 }
6578
6579 public boolean fillsScreenLw(int screenWidth, int screenHeight,
6580 boolean shownFrame, boolean onlyOpaque) {
6581 if (mSurface == null) {
6582 return false;
6583 }
6584 if (mAppToken != null && !mAppToken.appFullscreen) {
6585 return false;
6586 }
6587 if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
6588 return false;
6589 }
6590 final Rect frame = shownFrame ? mShownFrame : mFrame;
6591 if (frame.left <= 0 && frame.top <= 0
6592 && frame.right >= screenWidth
6593 && frame.bottom >= screenHeight) {
6594 return true;
6595 }
6596 return false;
6597 }
Romain Guy06882f82009-06-10 13:36:04 -07006598
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006599 /**
6600 * Return true if the window is opaque and fully drawn.
6601 */
6602 boolean isOpaqueDrawn() {
6603 return mAttrs.format == PixelFormat.OPAQUE && mSurface != null
6604 && mAnimation == null && !mDrawPending && !mCommitDrawPending;
6605 }
6606
6607 boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
6608 return
6609 // only if the application is requesting compatible window
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07006610 (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
6611 // only if it's visible
6612 mHasDrawn && mViewVisibility == View.VISIBLE &&
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006613 // and only if the application wanted to fill the screen
6614 mAttrs.width == mAttrs.FILL_PARENT &&
6615 mAttrs.height == mAttrs.FILL_PARENT &&
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07006616 // and only if the window is not hidden
6617 mFrame.left == mCompatibleScreenFrame.left &&
6618 // and starting window do not need background filler
6619 mAttrs.type != mAttrs.TYPE_APPLICATION_STARTING &&
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006620 // and only if the screen is bigger
6621 ((mFrame.right - mFrame.right) < screenWidth ||
6622 (mFrame.bottom - mFrame.top) < screenHeight);
6623 }
6624
6625 boolean isFullscreen(int screenWidth, int screenHeight) {
6626 return mFrame.left <= 0 && mFrame.top <= 0 &&
6627 mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006628 }
6629
6630 void removeLocked() {
6631 if (mAttachedWindow != null) {
6632 mAttachedWindow.mChildWindows.remove(this);
6633 }
6634 destroySurfaceLocked();
6635 mSession.windowRemovedLocked();
6636 try {
6637 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
6638 } catch (RuntimeException e) {
6639 // Ignore if it has already been removed (usually because
6640 // we are doing this as part of processing a death note.)
6641 }
6642 }
6643
6644 private class DeathRecipient implements IBinder.DeathRecipient {
6645 public void binderDied() {
6646 try {
6647 synchronized(mWindowMap) {
6648 WindowState win = windowForClientLocked(mSession, mClient);
6649 Log.i(TAG, "WIN DEATH: " + win);
6650 if (win != null) {
6651 removeWindowLocked(mSession, win);
6652 }
6653 }
6654 } catch (IllegalArgumentException ex) {
6655 // This will happen if the window has already been
6656 // removed.
6657 }
6658 }
6659 }
6660
6661 /** Returns true if this window desires key events. */
6662 public final boolean canReceiveKeys() {
6663 return isVisibleOrAdding()
6664 && (mViewVisibility == View.VISIBLE)
6665 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
6666 }
6667
6668 public boolean hasDrawnLw() {
6669 return mHasDrawn;
6670 }
6671
6672 public boolean showLw(boolean doAnimation) {
6673 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
6674 mPolicyVisibility = true;
6675 mPolicyVisibilityAfterAnim = true;
6676 if (doAnimation) {
6677 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
6678 }
6679 requestAnimationLocked(0);
6680 return true;
6681 }
6682 return false;
6683 }
6684
6685 public boolean hideLw(boolean doAnimation) {
6686 boolean current = doAnimation ? mPolicyVisibilityAfterAnim
6687 : mPolicyVisibility;
6688 if (current) {
6689 if (doAnimation) {
6690 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
6691 if (mAnimation == null) {
6692 doAnimation = false;
6693 }
6694 }
6695 if (doAnimation) {
6696 mPolicyVisibilityAfterAnim = false;
6697 } else {
6698 mPolicyVisibilityAfterAnim = false;
6699 mPolicyVisibility = false;
6700 }
6701 requestAnimationLocked(0);
6702 return true;
6703 }
6704 return false;
6705 }
6706
6707 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006708 StringBuilder sb = new StringBuilder(64);
Romain Guy06882f82009-06-10 13:36:04 -07006709
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006710 pw.print(prefix); pw.print("mSession="); pw.print(mSession);
6711 pw.print(" mClient="); pw.println(mClient.asBinder());
6712 pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
6713 if (mAttachedWindow != null || mLayoutAttached) {
6714 pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
6715 pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
6716 }
6717 if (mIsImWindow) {
6718 pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
6719 }
6720 pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
6721 pw.print(" mSubLayer="); pw.print(mSubLayer);
6722 pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
6723 pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
6724 : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)));
6725 pw.print("="); pw.print(mAnimLayer);
6726 pw.print(" mLastLayer="); pw.println(mLastLayer);
6727 if (mSurface != null) {
6728 pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
6729 }
6730 pw.print(prefix); pw.print("mToken="); pw.println(mToken);
6731 pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
6732 if (mAppToken != null) {
6733 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
6734 }
6735 if (mTargetAppToken != null) {
6736 pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken);
6737 }
6738 pw.print(prefix); pw.print("mViewVisibility=0x");
6739 pw.print(Integer.toHexString(mViewVisibility));
6740 pw.print(" mLastHidden="); pw.print(mLastHidden);
6741 pw.print(" mHaveFrame="); pw.println(mHaveFrame);
6742 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
6743 pw.print(prefix); pw.print("mPolicyVisibility=");
6744 pw.print(mPolicyVisibility);
6745 pw.print(" mPolicyVisibilityAfterAnim=");
6746 pw.print(mPolicyVisibilityAfterAnim);
6747 pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
6748 }
6749 pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
6750 pw.print(" h="); pw.print(mRequestedHeight);
6751 pw.print(" x="); pw.print(mReqXPos);
6752 pw.print(" y="); pw.println(mReqYPos);
6753 pw.print(prefix); pw.print("mGivenContentInsets=");
6754 mGivenContentInsets.printShortString(pw);
6755 pw.print(" mGivenVisibleInsets=");
6756 mGivenVisibleInsets.printShortString(pw);
6757 pw.println();
6758 if (mTouchableInsets != 0 || mGivenInsetsPending) {
6759 pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
6760 pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
6761 }
6762 pw.print(prefix); pw.print("mShownFrame=");
6763 mShownFrame.printShortString(pw);
6764 pw.print(" last="); mLastShownFrame.printShortString(pw);
6765 pw.println();
6766 pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
6767 pw.print(" last="); mLastFrame.printShortString(pw);
6768 pw.println();
6769 pw.print(prefix); pw.print("mContainingFrame=");
6770 mContainingFrame.printShortString(pw);
6771 pw.print(" mDisplayFrame=");
6772 mDisplayFrame.printShortString(pw);
6773 pw.println();
6774 pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw);
6775 pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw);
6776 pw.println();
6777 pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw);
6778 pw.print(" last="); mLastContentInsets.printShortString(pw);
6779 pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw);
6780 pw.print(" last="); mLastVisibleInsets.printShortString(pw);
6781 pw.println();
6782 if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
6783 pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
6784 pw.print(" mAlpha="); pw.print(mAlpha);
6785 pw.print(" mLastAlpha="); pw.println(mLastAlpha);
6786 }
6787 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
6788 || mAnimation != null) {
6789 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
6790 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
6791 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
6792 pw.print(" mAnimation="); pw.println(mAnimation);
6793 }
6794 if (mHasTransformation || mHasLocalTransformation) {
6795 pw.print(prefix); pw.print("XForm: has=");
6796 pw.print(mHasTransformation);
6797 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
6798 pw.print(" "); mTransformation.printShortString(pw);
6799 pw.println();
6800 }
6801 pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending);
6802 pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending);
6803 pw.print(" mReadyToShow="); pw.print(mReadyToShow);
6804 pw.print(" mHasDrawn="); pw.println(mHasDrawn);
6805 if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
6806 pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
6807 pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
6808 pw.print(" mDestroying="); pw.print(mDestroying);
6809 pw.print(" mRemoved="); pw.println(mRemoved);
6810 }
6811 if (mOrientationChanging || mAppFreezing) {
6812 pw.print(prefix); pw.print("mOrientationChanging=");
6813 pw.print(mOrientationChanging);
6814 pw.print(" mAppFreezing="); pw.println(mAppFreezing);
6815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006816 }
6817
6818 @Override
6819 public String toString() {
6820 return "Window{"
6821 + Integer.toHexString(System.identityHashCode(this))
6822 + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
6823 }
6824 }
Romain Guy06882f82009-06-10 13:36:04 -07006825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006826 // -------------------------------------------------------------
6827 // Window Token State
6828 // -------------------------------------------------------------
6829
6830 class WindowToken {
6831 // The actual token.
6832 final IBinder token;
6833
6834 // The type of window this token is for, as per WindowManager.LayoutParams.
6835 final int windowType;
Romain Guy06882f82009-06-10 13:36:04 -07006836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006837 // Set if this token was explicitly added by a client, so should
6838 // not be removed when all windows are removed.
6839 final boolean explicit;
Romain Guy06882f82009-06-10 13:36:04 -07006840
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006841 // For printing.
6842 String stringName;
Romain Guy06882f82009-06-10 13:36:04 -07006843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006844 // If this is an AppWindowToken, this is non-null.
6845 AppWindowToken appWindowToken;
Romain Guy06882f82009-06-10 13:36:04 -07006846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006847 // All of the windows associated with this token.
6848 final ArrayList<WindowState> windows = new ArrayList<WindowState>();
6849
6850 // Is key dispatching paused for this token?
6851 boolean paused = false;
6852
6853 // Should this token's windows be hidden?
6854 boolean hidden;
6855
6856 // Temporary for finding which tokens no longer have visible windows.
6857 boolean hasVisible;
6858
6859 WindowToken(IBinder _token, int type, boolean _explicit) {
6860 token = _token;
6861 windowType = type;
6862 explicit = _explicit;
6863 }
6864
6865 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006866 pw.print(prefix); pw.print("token="); pw.println(token);
6867 pw.print(prefix); pw.print("windows="); pw.println(windows);
6868 pw.print(prefix); pw.print("windowType="); pw.print(windowType);
6869 pw.print(" hidden="); pw.print(hidden);
6870 pw.print(" hasVisible="); pw.println(hasVisible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006871 }
6872
6873 @Override
6874 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006875 if (stringName == null) {
6876 StringBuilder sb = new StringBuilder();
6877 sb.append("WindowToken{");
6878 sb.append(Integer.toHexString(System.identityHashCode(this)));
6879 sb.append(" token="); sb.append(token); sb.append('}');
6880 stringName = sb.toString();
6881 }
6882 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006883 }
6884 };
6885
6886 class AppWindowToken extends WindowToken {
6887 // Non-null only for application tokens.
6888 final IApplicationToken appToken;
6889
6890 // All of the windows and child windows that are included in this
6891 // application token. Note this list is NOT sorted!
6892 final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
6893
6894 int groupId = -1;
6895 boolean appFullscreen;
6896 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Romain Guy06882f82009-06-10 13:36:04 -07006897
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006898 // These are used for determining when all windows associated with
6899 // an activity have been drawn, so they can be made visible together
6900 // at the same time.
6901 int lastTransactionSequence = mTransactionSequence-1;
6902 int numInterestingWindows;
6903 int numDrawnWindows;
6904 boolean inPendingTransaction;
6905 boolean allDrawn;
Romain Guy06882f82009-06-10 13:36:04 -07006906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006907 // Is this token going to be hidden in a little while? If so, it
6908 // won't be taken into account for setting the screen orientation.
6909 boolean willBeHidden;
Romain Guy06882f82009-06-10 13:36:04 -07006910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006911 // Is this window's surface needed? This is almost like hidden, except
6912 // it will sometimes be true a little earlier: when the token has
6913 // been shown, but is still waiting for its app transition to execute
6914 // before making its windows shown.
6915 boolean hiddenRequested;
Romain Guy06882f82009-06-10 13:36:04 -07006916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006917 // Have we told the window clients to hide themselves?
6918 boolean clientHidden;
Romain Guy06882f82009-06-10 13:36:04 -07006919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006920 // Last visibility state we reported to the app token.
6921 boolean reportedVisible;
6922
6923 // Set to true when the token has been removed from the window mgr.
6924 boolean removed;
6925
6926 // Have we been asked to have this token keep the screen frozen?
6927 boolean freezingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07006928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006929 boolean animating;
6930 Animation animation;
6931 boolean hasTransformation;
6932 final Transformation transformation = new Transformation();
Romain Guy06882f82009-06-10 13:36:04 -07006933
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006934 // Offset to the window of all layers in the token, for use by
6935 // AppWindowToken animations.
6936 int animLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -07006937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006938 // Information about an application starting window if displayed.
6939 StartingData startingData;
6940 WindowState startingWindow;
6941 View startingView;
6942 boolean startingDisplayed;
6943 boolean startingMoved;
6944 boolean firstWindowDrawn;
6945
6946 AppWindowToken(IApplicationToken _token) {
6947 super(_token.asBinder(),
6948 WindowManager.LayoutParams.TYPE_APPLICATION, true);
6949 appWindowToken = this;
6950 appToken = _token;
6951 }
Romain Guy06882f82009-06-10 13:36:04 -07006952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 public void setAnimation(Animation anim) {
6954 if (localLOGV) Log.v(
6955 TAG, "Setting animation in " + this + ": " + anim);
6956 animation = anim;
6957 animating = false;
6958 anim.restrictDuration(MAX_ANIMATION_DURATION);
6959 anim.scaleCurrentDuration(mTransitionAnimationScale);
6960 int zorder = anim.getZAdjustment();
6961 int adj = 0;
6962 if (zorder == Animation.ZORDER_TOP) {
6963 adj = TYPE_LAYER_OFFSET;
6964 } else if (zorder == Animation.ZORDER_BOTTOM) {
6965 adj = -TYPE_LAYER_OFFSET;
6966 }
Romain Guy06882f82009-06-10 13:36:04 -07006967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006968 if (animLayerAdjustment != adj) {
6969 animLayerAdjustment = adj;
6970 updateLayers();
6971 }
6972 }
Romain Guy06882f82009-06-10 13:36:04 -07006973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006974 public void setDummyAnimation() {
6975 if (animation == null) {
6976 if (localLOGV) Log.v(
6977 TAG, "Setting dummy animation in " + this);
6978 animation = sDummyAnimation;
6979 }
6980 }
6981
6982 public void clearAnimation() {
6983 if (animation != null) {
6984 animation = null;
6985 animating = true;
6986 }
6987 }
Romain Guy06882f82009-06-10 13:36:04 -07006988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 void updateLayers() {
6990 final int N = allAppWindows.size();
6991 final int adj = animLayerAdjustment;
6992 for (int i=0; i<N; i++) {
6993 WindowState w = allAppWindows.get(i);
6994 w.mAnimLayer = w.mLayer + adj;
6995 if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
6996 + w.mAnimLayer);
6997 if (w == mInputMethodTarget) {
6998 setInputMethodAnimLayerAdjustment(adj);
6999 }
7000 }
7001 }
Romain Guy06882f82009-06-10 13:36:04 -07007002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007003 void sendAppVisibilityToClients() {
7004 final int N = allAppWindows.size();
7005 for (int i=0; i<N; i++) {
7006 WindowState win = allAppWindows.get(i);
7007 if (win == startingWindow && clientHidden) {
7008 // Don't hide the starting window.
7009 continue;
7010 }
7011 try {
7012 if (DEBUG_VISIBILITY) Log.v(TAG,
7013 "Setting visibility of " + win + ": " + (!clientHidden));
7014 win.mClient.dispatchAppVisibility(!clientHidden);
7015 } catch (RemoteException e) {
7016 }
7017 }
7018 }
Romain Guy06882f82009-06-10 13:36:04 -07007019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 void showAllWindowsLocked() {
7021 final int NW = allAppWindows.size();
7022 for (int i=0; i<NW; i++) {
7023 WindowState w = allAppWindows.get(i);
7024 if (DEBUG_VISIBILITY) Log.v(TAG,
7025 "performing show on: " + w);
7026 w.performShowLocked();
7027 }
7028 }
Romain Guy06882f82009-06-10 13:36:04 -07007029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007030 // This must be called while inside a transaction.
7031 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
7032 if (!mDisplayFrozen) {
7033 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07007034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007035 if (animation == sDummyAnimation) {
7036 // This guy is going to animate, but not yet. For now count
7037 // it is not animating for purposes of scheduling transactions;
7038 // when it is really time to animate, this will be set to
7039 // a real animation and the next call will execute normally.
7040 return false;
7041 }
Romain Guy06882f82009-06-10 13:36:04 -07007042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007043 if ((allDrawn || animating || startingDisplayed) && animation != null) {
7044 if (!animating) {
7045 if (DEBUG_ANIM) Log.v(
7046 TAG, "Starting animation in " + this +
7047 " @ " + currentTime + ": dw=" + dw + " dh=" + dh
7048 + " scale=" + mTransitionAnimationScale
7049 + " allDrawn=" + allDrawn + " animating=" + animating);
7050 animation.initialize(dw, dh, dw, dh);
7051 animation.setStartTime(currentTime);
7052 animating = true;
7053 }
7054 transformation.clear();
7055 final boolean more = animation.getTransformation(
7056 currentTime, transformation);
7057 if (DEBUG_ANIM) Log.v(
7058 TAG, "Stepped animation in " + this +
7059 ": more=" + more + ", xform=" + transformation);
7060 if (more) {
7061 // we're done!
7062 hasTransformation = true;
7063 return true;
7064 }
7065 if (DEBUG_ANIM) Log.v(
7066 TAG, "Finished animation in " + this +
7067 " @ " + currentTime);
7068 animation = null;
7069 }
7070 } else if (animation != null) {
7071 // If the display is frozen, and there is a pending animation,
7072 // clear it and make sure we run the cleanup code.
7073 animating = true;
7074 animation = null;
7075 }
7076
7077 hasTransformation = false;
Romain Guy06882f82009-06-10 13:36:04 -07007078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007079 if (!animating) {
7080 return false;
7081 }
7082
7083 clearAnimation();
7084 animating = false;
7085 if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
7086 moveInputMethodWindowsIfNeededLocked(true);
7087 }
Romain Guy06882f82009-06-10 13:36:04 -07007088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007089 if (DEBUG_ANIM) Log.v(
7090 TAG, "Animation done in " + this
7091 + ": reportedVisible=" + reportedVisible);
7092
7093 transformation.clear();
7094 if (animLayerAdjustment != 0) {
7095 animLayerAdjustment = 0;
7096 updateLayers();
7097 }
Romain Guy06882f82009-06-10 13:36:04 -07007098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007099 final int N = windows.size();
7100 for (int i=0; i<N; i++) {
7101 ((WindowState)windows.get(i)).finishExit();
7102 }
7103 updateReportedVisibilityLocked();
Romain Guy06882f82009-06-10 13:36:04 -07007104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007105 return false;
7106 }
7107
7108 void updateReportedVisibilityLocked() {
7109 if (appToken == null) {
7110 return;
7111 }
Romain Guy06882f82009-06-10 13:36:04 -07007112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007113 int numInteresting = 0;
7114 int numVisible = 0;
7115 boolean nowGone = true;
Romain Guy06882f82009-06-10 13:36:04 -07007116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007117 if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
7118 final int N = allAppWindows.size();
7119 for (int i=0; i<N; i++) {
7120 WindowState win = allAppWindows.get(i);
7121 if (win == startingWindow || win.mAppFreezing) {
7122 continue;
7123 }
7124 if (DEBUG_VISIBILITY) {
7125 Log.v(TAG, "Win " + win + ": isDisplayed="
7126 + win.isDisplayedLw()
7127 + ", isAnimating=" + win.isAnimating());
7128 if (!win.isDisplayedLw()) {
7129 Log.v(TAG, "Not displayed: s=" + win.mSurface
7130 + " pv=" + win.mPolicyVisibility
7131 + " dp=" + win.mDrawPending
7132 + " cdp=" + win.mCommitDrawPending
7133 + " ah=" + win.mAttachedHidden
7134 + " th="
7135 + (win.mAppToken != null
7136 ? win.mAppToken.hiddenRequested : false)
7137 + " a=" + win.mAnimating);
7138 }
7139 }
7140 numInteresting++;
7141 if (win.isDisplayedLw()) {
7142 if (!win.isAnimating()) {
7143 numVisible++;
7144 }
7145 nowGone = false;
7146 } else if (win.isAnimating()) {
7147 nowGone = false;
7148 }
7149 }
Romain Guy06882f82009-06-10 13:36:04 -07007150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007151 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
7152 if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
7153 + numInteresting + " visible=" + numVisible);
7154 if (nowVisible != reportedVisible) {
7155 if (DEBUG_VISIBILITY) Log.v(
7156 TAG, "Visibility changed in " + this
7157 + ": vis=" + nowVisible);
7158 reportedVisible = nowVisible;
7159 Message m = mH.obtainMessage(
7160 H.REPORT_APPLICATION_TOKEN_WINDOWS,
7161 nowVisible ? 1 : 0,
7162 nowGone ? 1 : 0,
7163 this);
7164 mH.sendMessage(m);
7165 }
7166 }
Romain Guy06882f82009-06-10 13:36:04 -07007167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007168 void dump(PrintWriter pw, String prefix) {
7169 super.dump(pw, prefix);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007170 if (appToken != null) {
7171 pw.print(prefix); pw.println("app=true");
7172 }
7173 if (allAppWindows.size() > 0) {
7174 pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
7175 }
7176 pw.print(prefix); pw.print("groupId="); pw.print(groupId);
7177 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
7178 pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
7179 pw.print(" clientHidden="); pw.print(clientHidden);
7180 pw.print(" willBeHidden="); pw.print(willBeHidden);
7181 pw.print(" reportedVisible="); pw.println(reportedVisible);
7182 if (paused || freezingScreen) {
7183 pw.print(prefix); pw.print("paused="); pw.print(paused);
7184 pw.print(" freezingScreen="); pw.println(freezingScreen);
7185 }
7186 if (numInterestingWindows != 0 || numDrawnWindows != 0
7187 || inPendingTransaction || allDrawn) {
7188 pw.print(prefix); pw.print("numInterestingWindows=");
7189 pw.print(numInterestingWindows);
7190 pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
7191 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
7192 pw.print(" allDrawn="); pw.println(allDrawn);
7193 }
7194 if (animating || animation != null) {
7195 pw.print(prefix); pw.print("animating="); pw.print(animating);
7196 pw.print(" animation="); pw.println(animation);
7197 }
7198 if (animLayerAdjustment != 0) {
7199 pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
7200 }
7201 if (hasTransformation) {
7202 pw.print(prefix); pw.print("hasTransformation="); pw.print(hasTransformation);
7203 pw.print(" transformation="); transformation.printShortString(pw);
7204 pw.println();
7205 }
7206 if (startingData != null || removed || firstWindowDrawn) {
7207 pw.print(prefix); pw.print("startingData="); pw.print(startingData);
7208 pw.print(" removed="); pw.print(removed);
7209 pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
7210 }
7211 if (startingWindow != null || startingView != null
7212 || startingDisplayed || startingMoved) {
7213 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
7214 pw.print(" startingView="); pw.print(startingView);
7215 pw.print(" startingDisplayed="); pw.print(startingDisplayed);
7216 pw.print(" startingMoved"); pw.println(startingMoved);
7217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 }
7219
7220 @Override
7221 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007222 if (stringName == null) {
7223 StringBuilder sb = new StringBuilder();
7224 sb.append("AppWindowToken{");
7225 sb.append(Integer.toHexString(System.identityHashCode(this)));
7226 sb.append(" token="); sb.append(token); sb.append('}');
7227 stringName = sb.toString();
7228 }
7229 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007230 }
7231 }
Romain Guy06882f82009-06-10 13:36:04 -07007232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007233 public static WindowManager.LayoutParams findAnimations(
7234 ArrayList<AppWindowToken> order,
7235 ArrayList<AppWindowToken> tokenList1,
7236 ArrayList<AppWindowToken> tokenList2) {
7237 // We need to figure out which animation to use...
7238 WindowManager.LayoutParams animParams = null;
7239 int animSrc = 0;
Romain Guy06882f82009-06-10 13:36:04 -07007240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007241 //Log.i(TAG, "Looking for animations...");
7242 for (int i=order.size()-1; i>=0; i--) {
7243 AppWindowToken wtoken = order.get(i);
7244 //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
7245 if (tokenList1.contains(wtoken) || tokenList2.contains(wtoken)) {
7246 int j = wtoken.windows.size();
7247 while (j > 0) {
7248 j--;
7249 WindowState win = wtoken.windows.get(j);
7250 //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
7251 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
7252 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
7253 //Log.i(TAG, "Found base or application window, done!");
7254 if (wtoken.appFullscreen) {
7255 return win.mAttrs;
7256 }
7257 if (animSrc < 2) {
7258 animParams = win.mAttrs;
7259 animSrc = 2;
7260 }
7261 } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
7262 //Log.i(TAG, "Found normal window, we may use this...");
7263 animParams = win.mAttrs;
7264 animSrc = 1;
7265 }
7266 }
7267 }
7268 }
Romain Guy06882f82009-06-10 13:36:04 -07007269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007270 return animParams;
7271 }
Romain Guy06882f82009-06-10 13:36:04 -07007272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007273 // -------------------------------------------------------------
7274 // DummyAnimation
7275 // -------------------------------------------------------------
7276
7277 // This is an animation that does nothing: it just immediately finishes
7278 // itself every time it is called. It is used as a stub animation in cases
7279 // where we want to synchronize multiple things that may be animating.
7280 static final class DummyAnimation extends Animation {
7281 public boolean getTransformation(long currentTime, Transformation outTransformation) {
7282 return false;
7283 }
7284 }
7285 static final Animation sDummyAnimation = new DummyAnimation();
Romain Guy06882f82009-06-10 13:36:04 -07007286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007287 // -------------------------------------------------------------
7288 // Async Handler
7289 // -------------------------------------------------------------
7290
7291 static final class StartingData {
7292 final String pkg;
7293 final int theme;
7294 final CharSequence nonLocalizedLabel;
7295 final int labelRes;
7296 final int icon;
Romain Guy06882f82009-06-10 13:36:04 -07007297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007298 StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
7299 int _labelRes, int _icon) {
7300 pkg = _pkg;
7301 theme = _theme;
7302 nonLocalizedLabel = _nonLocalizedLabel;
7303 labelRes = _labelRes;
7304 icon = _icon;
7305 }
7306 }
7307
7308 private final class H extends Handler {
7309 public static final int REPORT_FOCUS_CHANGE = 2;
7310 public static final int REPORT_LOSING_FOCUS = 3;
7311 public static final int ANIMATE = 4;
7312 public static final int ADD_STARTING = 5;
7313 public static final int REMOVE_STARTING = 6;
7314 public static final int FINISHED_STARTING = 7;
7315 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007316 public static final int WINDOW_FREEZE_TIMEOUT = 11;
7317 public static final int HOLD_SCREEN_CHANGED = 12;
7318 public static final int APP_TRANSITION_TIMEOUT = 13;
7319 public static final int PERSIST_ANIMATION_SCALE = 14;
7320 public static final int FORCE_GC = 15;
7321 public static final int ENABLE_SCREEN = 16;
7322 public static final int APP_FREEZE_TIMEOUT = 17;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007323 public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
Romain Guy06882f82009-06-10 13:36:04 -07007324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007325 private Session mLastReportedHold;
Romain Guy06882f82009-06-10 13:36:04 -07007326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007327 public H() {
7328 }
Romain Guy06882f82009-06-10 13:36:04 -07007329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007330 @Override
7331 public void handleMessage(Message msg) {
7332 switch (msg.what) {
7333 case REPORT_FOCUS_CHANGE: {
7334 WindowState lastFocus;
7335 WindowState newFocus;
Romain Guy06882f82009-06-10 13:36:04 -07007336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007337 synchronized(mWindowMap) {
7338 lastFocus = mLastFocus;
7339 newFocus = mCurrentFocus;
7340 if (lastFocus == newFocus) {
7341 // Focus is not changing, so nothing to do.
7342 return;
7343 }
7344 mLastFocus = newFocus;
7345 //Log.i(TAG, "Focus moving from " + lastFocus
7346 // + " to " + newFocus);
7347 if (newFocus != null && lastFocus != null
7348 && !newFocus.isDisplayedLw()) {
7349 //Log.i(TAG, "Delaying loss of focus...");
7350 mLosingFocus.add(lastFocus);
7351 lastFocus = null;
7352 }
7353 }
7354
7355 if (lastFocus != newFocus) {
7356 //System.out.println("Changing focus from " + lastFocus
7357 // + " to " + newFocus);
7358 if (newFocus != null) {
7359 try {
7360 //Log.i(TAG, "Gaining focus: " + newFocus);
7361 newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7362 } catch (RemoteException e) {
7363 // Ignore if process has died.
7364 }
7365 }
7366
7367 if (lastFocus != null) {
7368 try {
7369 //Log.i(TAG, "Losing focus: " + lastFocus);
7370 lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7371 } catch (RemoteException e) {
7372 // Ignore if process has died.
7373 }
7374 }
7375 }
7376 } break;
7377
7378 case REPORT_LOSING_FOCUS: {
7379 ArrayList<WindowState> losers;
Romain Guy06882f82009-06-10 13:36:04 -07007380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007381 synchronized(mWindowMap) {
7382 losers = mLosingFocus;
7383 mLosingFocus = new ArrayList<WindowState>();
7384 }
7385
7386 final int N = losers.size();
7387 for (int i=0; i<N; i++) {
7388 try {
7389 //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
7390 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7391 } catch (RemoteException e) {
7392 // Ignore if process has died.
7393 }
7394 }
7395 } break;
7396
7397 case ANIMATE: {
7398 synchronized(mWindowMap) {
7399 mAnimationPending = false;
7400 performLayoutAndPlaceSurfacesLocked();
7401 }
7402 } break;
7403
7404 case ADD_STARTING: {
7405 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7406 final StartingData sd = wtoken.startingData;
7407
7408 if (sd == null) {
7409 // Animation has been canceled... do nothing.
7410 return;
7411 }
Romain Guy06882f82009-06-10 13:36:04 -07007412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007413 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
7414 + wtoken + ": pkg=" + sd.pkg);
Romain Guy06882f82009-06-10 13:36:04 -07007415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007416 View view = null;
7417 try {
7418 view = mPolicy.addStartingWindow(
7419 wtoken.token, sd.pkg,
7420 sd.theme, sd.nonLocalizedLabel, sd.labelRes,
7421 sd.icon);
7422 } catch (Exception e) {
7423 Log.w(TAG, "Exception when adding starting window", e);
7424 }
7425
7426 if (view != null) {
7427 boolean abort = false;
7428
7429 synchronized(mWindowMap) {
7430 if (wtoken.removed || wtoken.startingData == null) {
7431 // If the window was successfully added, then
7432 // we need to remove it.
7433 if (wtoken.startingWindow != null) {
7434 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7435 "Aborted starting " + wtoken
7436 + ": removed=" + wtoken.removed
7437 + " startingData=" + wtoken.startingData);
7438 wtoken.startingWindow = null;
7439 wtoken.startingData = null;
7440 abort = true;
7441 }
7442 } else {
7443 wtoken.startingView = view;
7444 }
7445 if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
7446 "Added starting " + wtoken
7447 + ": startingWindow="
7448 + wtoken.startingWindow + " startingView="
7449 + wtoken.startingView);
7450 }
7451
7452 if (abort) {
7453 try {
7454 mPolicy.removeStartingWindow(wtoken.token, view);
7455 } catch (Exception e) {
7456 Log.w(TAG, "Exception when removing starting window", e);
7457 }
7458 }
7459 }
7460 } break;
7461
7462 case REMOVE_STARTING: {
7463 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7464 IBinder token = null;
7465 View view = null;
7466 synchronized (mWindowMap) {
7467 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
7468 + wtoken + ": startingWindow="
7469 + wtoken.startingWindow + " startingView="
7470 + wtoken.startingView);
7471 if (wtoken.startingWindow != null) {
7472 view = wtoken.startingView;
7473 token = wtoken.token;
7474 wtoken.startingData = null;
7475 wtoken.startingView = null;
7476 wtoken.startingWindow = null;
7477 }
7478 }
7479 if (view != null) {
7480 try {
7481 mPolicy.removeStartingWindow(token, view);
7482 } catch (Exception e) {
7483 Log.w(TAG, "Exception when removing starting window", e);
7484 }
7485 }
7486 } break;
7487
7488 case FINISHED_STARTING: {
7489 IBinder token = null;
7490 View view = null;
7491 while (true) {
7492 synchronized (mWindowMap) {
7493 final int N = mFinishedStarting.size();
7494 if (N <= 0) {
7495 break;
7496 }
7497 AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7498
7499 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7500 "Finished starting " + wtoken
7501 + ": startingWindow=" + wtoken.startingWindow
7502 + " startingView=" + wtoken.startingView);
7503
7504 if (wtoken.startingWindow == null) {
7505 continue;
7506 }
7507
7508 view = wtoken.startingView;
7509 token = wtoken.token;
7510 wtoken.startingData = null;
7511 wtoken.startingView = null;
7512 wtoken.startingWindow = null;
7513 }
7514
7515 try {
7516 mPolicy.removeStartingWindow(token, view);
7517 } catch (Exception e) {
7518 Log.w(TAG, "Exception when removing starting window", e);
7519 }
7520 }
7521 } break;
7522
7523 case REPORT_APPLICATION_TOKEN_WINDOWS: {
7524 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7525
7526 boolean nowVisible = msg.arg1 != 0;
7527 boolean nowGone = msg.arg2 != 0;
7528
7529 try {
7530 if (DEBUG_VISIBILITY) Log.v(
7531 TAG, "Reporting visible in " + wtoken
7532 + " visible=" + nowVisible
7533 + " gone=" + nowGone);
7534 if (nowVisible) {
7535 wtoken.appToken.windowsVisible();
7536 } else {
7537 wtoken.appToken.windowsGone();
7538 }
7539 } catch (RemoteException ex) {
7540 }
7541 } break;
Romain Guy06882f82009-06-10 13:36:04 -07007542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007543 case WINDOW_FREEZE_TIMEOUT: {
7544 synchronized (mWindowMap) {
7545 Log.w(TAG, "Window freeze timeout expired.");
7546 int i = mWindows.size();
7547 while (i > 0) {
7548 i--;
7549 WindowState w = (WindowState)mWindows.get(i);
7550 if (w.mOrientationChanging) {
7551 w.mOrientationChanging = false;
7552 Log.w(TAG, "Force clearing orientation change: " + w);
7553 }
7554 }
7555 performLayoutAndPlaceSurfacesLocked();
7556 }
7557 break;
7558 }
Romain Guy06882f82009-06-10 13:36:04 -07007559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007560 case HOLD_SCREEN_CHANGED: {
7561 Session oldHold;
7562 Session newHold;
7563 synchronized (mWindowMap) {
7564 oldHold = mLastReportedHold;
7565 newHold = (Session)msg.obj;
7566 mLastReportedHold = newHold;
7567 }
Romain Guy06882f82009-06-10 13:36:04 -07007568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007569 if (oldHold != newHold) {
7570 try {
7571 if (oldHold != null) {
7572 mBatteryStats.noteStopWakelock(oldHold.mUid,
7573 "window",
7574 BatteryStats.WAKE_TYPE_WINDOW);
7575 }
7576 if (newHold != null) {
7577 mBatteryStats.noteStartWakelock(newHold.mUid,
7578 "window",
7579 BatteryStats.WAKE_TYPE_WINDOW);
7580 }
7581 } catch (RemoteException e) {
7582 }
7583 }
7584 break;
7585 }
Romain Guy06882f82009-06-10 13:36:04 -07007586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007587 case APP_TRANSITION_TIMEOUT: {
7588 synchronized (mWindowMap) {
7589 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
7590 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7591 "*** APP TRANSITION TIMEOUT");
7592 mAppTransitionReady = true;
7593 mAppTransitionTimeout = true;
7594 performLayoutAndPlaceSurfacesLocked();
7595 }
7596 }
7597 break;
7598 }
Romain Guy06882f82009-06-10 13:36:04 -07007599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007600 case PERSIST_ANIMATION_SCALE: {
7601 Settings.System.putFloat(mContext.getContentResolver(),
7602 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7603 Settings.System.putFloat(mContext.getContentResolver(),
7604 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7605 break;
7606 }
Romain Guy06882f82009-06-10 13:36:04 -07007607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007608 case FORCE_GC: {
7609 synchronized(mWindowMap) {
7610 if (mAnimationPending) {
7611 // If we are animating, don't do the gc now but
7612 // delay a bit so we don't interrupt the animation.
7613 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7614 2000);
7615 return;
7616 }
7617 // If we are currently rotating the display, it will
7618 // schedule a new message when done.
7619 if (mDisplayFrozen) {
7620 return;
7621 }
7622 mFreezeGcPending = 0;
7623 }
7624 Runtime.getRuntime().gc();
7625 break;
7626 }
Romain Guy06882f82009-06-10 13:36:04 -07007627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007628 case ENABLE_SCREEN: {
7629 performEnableScreen();
7630 break;
7631 }
Romain Guy06882f82009-06-10 13:36:04 -07007632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007633 case APP_FREEZE_TIMEOUT: {
7634 synchronized (mWindowMap) {
7635 Log.w(TAG, "App freeze timeout expired.");
7636 int i = mAppTokens.size();
7637 while (i > 0) {
7638 i--;
7639 AppWindowToken tok = mAppTokens.get(i);
7640 if (tok.freezingScreen) {
7641 Log.w(TAG, "Force clearing freeze: " + tok);
7642 unsetAppFreezingScreenLocked(tok, true, true);
7643 }
7644 }
7645 }
7646 break;
7647 }
Romain Guy06882f82009-06-10 13:36:04 -07007648
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007649 case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
Dianne Hackborncfaef692009-06-15 14:24:44 -07007650 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007651 sendNewConfiguration();
7652 }
7653 break;
7654 }
Romain Guy06882f82009-06-10 13:36:04 -07007655
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007656 }
7657 }
7658 }
7659
7660 // -------------------------------------------------------------
7661 // IWindowManager API
7662 // -------------------------------------------------------------
7663
7664 public IWindowSession openSession(IInputMethodClient client,
7665 IInputContext inputContext) {
7666 if (client == null) throw new IllegalArgumentException("null client");
7667 if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7668 return new Session(client, inputContext);
7669 }
7670
7671 public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7672 synchronized (mWindowMap) {
7673 // The focus for the client is the window immediately below
7674 // where we would place the input method window.
7675 int idx = findDesiredInputMethodWindowIndexLocked(false);
7676 WindowState imFocus;
7677 if (idx > 0) {
7678 imFocus = (WindowState)mWindows.get(idx-1);
7679 if (imFocus != null) {
7680 if (imFocus.mSession.mClient != null &&
7681 imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7682 return true;
7683 }
7684 }
7685 }
7686 }
7687 return false;
7688 }
Romain Guy06882f82009-06-10 13:36:04 -07007689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007690 // -------------------------------------------------------------
7691 // Internals
7692 // -------------------------------------------------------------
7693
7694 final WindowState windowForClientLocked(Session session, IWindow client) {
7695 return windowForClientLocked(session, client.asBinder());
7696 }
Romain Guy06882f82009-06-10 13:36:04 -07007697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007698 final WindowState windowForClientLocked(Session session, IBinder client) {
7699 WindowState win = mWindowMap.get(client);
7700 if (localLOGV) Log.v(
7701 TAG, "Looking up client " + client + ": " + win);
7702 if (win == null) {
7703 RuntimeException ex = new RuntimeException();
7704 Log.w(TAG, "Requested window " + client + " does not exist", ex);
7705 return null;
7706 }
7707 if (session != null && win.mSession != session) {
7708 RuntimeException ex = new RuntimeException();
7709 Log.w(TAG, "Requested window " + client + " is in session " +
7710 win.mSession + ", not " + session, ex);
7711 return null;
7712 }
7713
7714 return win;
7715 }
7716
7717 private final void assignLayersLocked() {
7718 int N = mWindows.size();
7719 int curBaseLayer = 0;
7720 int curLayer = 0;
7721 int i;
Romain Guy06882f82009-06-10 13:36:04 -07007722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007723 for (i=0; i<N; i++) {
7724 WindowState w = (WindowState)mWindows.get(i);
7725 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
7726 curLayer += WINDOW_LAYER_MULTIPLIER;
7727 w.mLayer = curLayer;
7728 } else {
7729 curBaseLayer = curLayer = w.mBaseLayer;
7730 w.mLayer = curLayer;
7731 }
7732 if (w.mTargetAppToken != null) {
7733 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
7734 } else if (w.mAppToken != null) {
7735 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
7736 } else {
7737 w.mAnimLayer = w.mLayer;
7738 }
7739 if (w.mIsImWindow) {
7740 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
7741 }
7742 if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
7743 + w.mAnimLayer);
7744 //System.out.println(
7745 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7746 }
7747 }
7748
7749 private boolean mInLayout = false;
7750 private final void performLayoutAndPlaceSurfacesLocked() {
7751 if (mInLayout) {
Dave Bortcfe65242009-04-09 14:51:04 -07007752 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007753 throw new RuntimeException("Recursive call!");
7754 }
7755 Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7756 return;
7757 }
7758
7759 boolean recoveringMemory = false;
7760 if (mForceRemoves != null) {
7761 recoveringMemory = true;
7762 // Wait a little it for things to settle down, and off we go.
7763 for (int i=0; i<mForceRemoves.size(); i++) {
7764 WindowState ws = mForceRemoves.get(i);
7765 Log.i(TAG, "Force removing: " + ws);
7766 removeWindowInnerLocked(ws.mSession, ws);
7767 }
7768 mForceRemoves = null;
7769 Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
7770 Object tmp = new Object();
7771 synchronized (tmp) {
7772 try {
7773 tmp.wait(250);
7774 } catch (InterruptedException e) {
7775 }
7776 }
7777 }
Romain Guy06882f82009-06-10 13:36:04 -07007778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007779 mInLayout = true;
7780 try {
7781 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
Romain Guy06882f82009-06-10 13:36:04 -07007782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007783 int i = mPendingRemove.size()-1;
7784 if (i >= 0) {
7785 while (i >= 0) {
7786 WindowState w = mPendingRemove.get(i);
7787 removeWindowInnerLocked(w.mSession, w);
7788 i--;
7789 }
7790 mPendingRemove.clear();
7791
7792 mInLayout = false;
7793 assignLayersLocked();
7794 mLayoutNeeded = true;
7795 performLayoutAndPlaceSurfacesLocked();
7796
7797 } else {
7798 mInLayout = false;
7799 if (mLayoutNeeded) {
7800 requestAnimationLocked(0);
7801 }
7802 }
7803 } catch (RuntimeException e) {
7804 mInLayout = false;
7805 Log.e(TAG, "Unhandled exception while layout out windows", e);
7806 }
7807 }
7808
7809 private final void performLayoutLockedInner() {
7810 final int dw = mDisplay.getWidth();
7811 final int dh = mDisplay.getHeight();
7812
7813 final int N = mWindows.size();
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007814 int repeats = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007815 int i;
7816
7817 // FIRST LOOP: Perform a layout, if needed.
Romain Guy06882f82009-06-10 13:36:04 -07007818
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007819 while (mLayoutNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007820 mPolicy.beginLayoutLw(dw, dh);
7821
7822 // First perform layout of any root windows (not attached
7823 // to another window).
7824 int topAttached = -1;
7825 for (i = N-1; i >= 0; i--) {
7826 WindowState win = (WindowState) mWindows.get(i);
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007827
7828 // Don't do layout of a window if it is not visible, or
7829 // soon won't be visible, to avoid wasting time and funky
7830 // changes while a window is animating away.
7831 final AppWindowToken atoken = win.mAppToken;
7832 final boolean gone = win.mViewVisibility == View.GONE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007833 || !win.mRelayoutCalled
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007834 || win.mRootToken.hidden
7835 || (atoken != null && atoken.hiddenRequested)
7836 || !win.mPolicyVisibility
7837 || win.mAttachedHidden
7838 || win.mExiting || win.mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007839
7840 // If this view is GONE, then skip it -- keep the current
7841 // frame, and let the caller know so they can ignore it
7842 // if they want. (We do the normal layout for INVISIBLE
7843 // windows, since that means "perform layout as normal,
7844 // just don't display").
7845 if (!gone || !win.mHaveFrame) {
7846 if (!win.mLayoutAttached) {
7847 mPolicy.layoutWindowLw(win, win.mAttrs, null);
7848 } else {
7849 if (topAttached < 0) topAttached = i;
7850 }
7851 }
7852 }
Romain Guy06882f82009-06-10 13:36:04 -07007853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007854 // Now perform layout of attached windows, which usually
7855 // depend on the position of the window they are attached to.
7856 // XXX does not deal with windows that are attached to windows
7857 // that are themselves attached.
7858 for (i = topAttached; i >= 0; i--) {
7859 WindowState win = (WindowState) mWindows.get(i);
7860
7861 // If this view is GONE, then skip it -- keep the current
7862 // frame, and let the caller know so they can ignore it
7863 // if they want. (We do the normal layout for INVISIBLE
7864 // windows, since that means "perform layout as normal,
7865 // just don't display").
7866 if (win.mLayoutAttached) {
7867 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7868 || !win.mHaveFrame) {
7869 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7870 }
7871 }
7872 }
7873
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007874 if (!mPolicy.finishLayoutLw()) {
7875 mLayoutNeeded = false;
7876 } else if (repeats > 2) {
7877 Log.w(TAG, "Layout repeat aborted after too many iterations");
7878 mLayoutNeeded = false;
7879 } else {
7880 repeats++;
7881 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007882 }
7883 }
Romain Guy06882f82009-06-10 13:36:04 -07007884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007885 private final void performLayoutAndPlaceSurfacesLockedInner(
7886 boolean recoveringMemory) {
7887 final long currentTime = SystemClock.uptimeMillis();
7888 final int dw = mDisplay.getWidth();
7889 final int dh = mDisplay.getHeight();
7890
7891 final int N = mWindows.size();
7892 int i;
7893
7894 // FIRST LOOP: Perform a layout, if needed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007895 performLayoutLockedInner();
Romain Guy06882f82009-06-10 13:36:04 -07007896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007897 if (mFxSession == null) {
7898 mFxSession = new SurfaceSession();
7899 }
Romain Guy06882f82009-06-10 13:36:04 -07007900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007901 if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
7902
7903 // Initialize state of exiting tokens.
7904 for (i=mExitingTokens.size()-1; i>=0; i--) {
7905 mExitingTokens.get(i).hasVisible = false;
7906 }
7907
7908 // Initialize state of exiting applications.
7909 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7910 mExitingAppTokens.get(i).hasVisible = false;
7911 }
7912
7913 // SECOND LOOP: Execute animations and update visibility of windows.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007914 boolean orientationChangeComplete = true;
7915 Session holdScreen = null;
7916 float screenBrightness = -1;
7917 boolean focusDisplayed = false;
7918 boolean animating = false;
7919
7920 Surface.openTransaction();
7921 try {
7922 boolean restart;
7923
7924 do {
7925 final int transactionSequence = ++mTransactionSequence;
7926
7927 // Update animations of all applications, including those
7928 // associated with exiting/removed apps
7929 boolean tokensAnimating = false;
7930 final int NAT = mAppTokens.size();
7931 for (i=0; i<NAT; i++) {
7932 if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7933 tokensAnimating = true;
7934 }
7935 }
7936 final int NEAT = mExitingAppTokens.size();
7937 for (i=0; i<NEAT; i++) {
7938 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7939 tokensAnimating = true;
7940 }
7941 }
7942
7943 animating = tokensAnimating;
7944 restart = false;
7945
7946 boolean tokenMayBeDrawn = false;
7947
7948 mPolicy.beginAnimationLw(dw, dh);
7949
7950 for (i=N-1; i>=0; i--) {
7951 WindowState w = (WindowState)mWindows.get(i);
7952
7953 final WindowManager.LayoutParams attrs = w.mAttrs;
7954
7955 if (w.mSurface != null) {
7956 // Execute animation.
7957 w.commitFinishDrawingLocked(currentTime);
7958 if (w.stepAnimationLocked(currentTime, dw, dh)) {
7959 animating = true;
7960 //w.dump(" ");
7961 }
7962
7963 mPolicy.animatingWindowLw(w, attrs);
7964 }
7965
7966 final AppWindowToken atoken = w.mAppToken;
7967 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7968 if (atoken.lastTransactionSequence != transactionSequence) {
7969 atoken.lastTransactionSequence = transactionSequence;
7970 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7971 atoken.startingDisplayed = false;
7972 }
7973 if ((w.isOnScreen() || w.mAttrs.type
7974 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7975 && !w.mExiting && !w.mDestroying) {
7976 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7977 Log.v(TAG, "Eval win " + w + ": isDisplayed="
7978 + w.isDisplayedLw()
7979 + ", isAnimating=" + w.isAnimating());
7980 if (!w.isDisplayedLw()) {
7981 Log.v(TAG, "Not displayed: s=" + w.mSurface
7982 + " pv=" + w.mPolicyVisibility
7983 + " dp=" + w.mDrawPending
7984 + " cdp=" + w.mCommitDrawPending
7985 + " ah=" + w.mAttachedHidden
7986 + " th=" + atoken.hiddenRequested
7987 + " a=" + w.mAnimating);
7988 }
7989 }
7990 if (w != atoken.startingWindow) {
7991 if (!atoken.freezingScreen || !w.mAppFreezing) {
7992 atoken.numInterestingWindows++;
7993 if (w.isDisplayedLw()) {
7994 atoken.numDrawnWindows++;
7995 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
7996 "tokenMayBeDrawn: " + atoken
7997 + " freezingScreen=" + atoken.freezingScreen
7998 + " mAppFreezing=" + w.mAppFreezing);
7999 tokenMayBeDrawn = true;
8000 }
8001 }
8002 } else if (w.isDisplayedLw()) {
8003 atoken.startingDisplayed = true;
8004 }
8005 }
8006 } else if (w.mReadyToShow) {
8007 w.performShowLocked();
8008 }
8009 }
8010
8011 if (mPolicy.finishAnimationLw()) {
8012 restart = true;
8013 }
8014
8015 if (tokenMayBeDrawn) {
8016 // See if any windows have been drawn, so they (and others
8017 // associated with them) can now be shown.
8018 final int NT = mTokenList.size();
8019 for (i=0; i<NT; i++) {
8020 AppWindowToken wtoken = mTokenList.get(i).appWindowToken;
8021 if (wtoken == null) {
8022 continue;
8023 }
8024 if (wtoken.freezingScreen) {
8025 int numInteresting = wtoken.numInterestingWindows;
8026 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8027 if (DEBUG_VISIBILITY) Log.v(TAG,
8028 "allDrawn: " + wtoken
8029 + " interesting=" + numInteresting
8030 + " drawn=" + wtoken.numDrawnWindows);
8031 wtoken.showAllWindowsLocked();
8032 unsetAppFreezingScreenLocked(wtoken, false, true);
8033 orientationChangeComplete = true;
8034 }
8035 } else if (!wtoken.allDrawn) {
8036 int numInteresting = wtoken.numInterestingWindows;
8037 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8038 if (DEBUG_VISIBILITY) Log.v(TAG,
8039 "allDrawn: " + wtoken
8040 + " interesting=" + numInteresting
8041 + " drawn=" + wtoken.numDrawnWindows);
8042 wtoken.allDrawn = true;
8043 restart = true;
8044
8045 // We can now show all of the drawn windows!
8046 if (!mOpeningApps.contains(wtoken)) {
8047 wtoken.showAllWindowsLocked();
8048 }
8049 }
8050 }
8051 }
8052 }
8053
8054 // If we are ready to perform an app transition, check through
8055 // all of the app tokens to be shown and see if they are ready
8056 // to go.
8057 if (mAppTransitionReady) {
8058 int NN = mOpeningApps.size();
8059 boolean goodToGo = true;
8060 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8061 "Checking " + NN + " opening apps (frozen="
8062 + mDisplayFrozen + " timeout="
8063 + mAppTransitionTimeout + ")...");
8064 if (!mDisplayFrozen && !mAppTransitionTimeout) {
8065 // If the display isn't frozen, wait to do anything until
8066 // all of the apps are ready. Otherwise just go because
8067 // we'll unfreeze the display when everyone is ready.
8068 for (i=0; i<NN && goodToGo; i++) {
8069 AppWindowToken wtoken = mOpeningApps.get(i);
8070 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8071 "Check opening app" + wtoken + ": allDrawn="
8072 + wtoken.allDrawn + " startingDisplayed="
8073 + wtoken.startingDisplayed);
8074 if (!wtoken.allDrawn && !wtoken.startingDisplayed
8075 && !wtoken.startingMoved) {
8076 goodToGo = false;
8077 }
8078 }
8079 }
8080 if (goodToGo) {
8081 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
8082 int transit = mNextAppTransition;
8083 if (mSkipAppTransitionAnimation) {
8084 transit = WindowManagerPolicy.TRANSIT_NONE;
8085 }
8086 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8087 mAppTransitionReady = false;
8088 mAppTransitionTimeout = false;
8089 mStartingIconInTransition = false;
8090 mSkipAppTransitionAnimation = false;
8091
8092 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8093
8094 // We need to figure out which animation to use...
8095 WindowManager.LayoutParams lp = findAnimations(mAppTokens,
8096 mOpeningApps, mClosingApps);
8097
8098 NN = mOpeningApps.size();
8099 for (i=0; i<NN; i++) {
8100 AppWindowToken wtoken = mOpeningApps.get(i);
8101 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8102 "Now opening app" + wtoken);
8103 wtoken.reportedVisible = false;
8104 wtoken.inPendingTransaction = false;
8105 setTokenVisibilityLocked(wtoken, lp, true, transit, false);
8106 wtoken.updateReportedVisibilityLocked();
8107 wtoken.showAllWindowsLocked();
8108 }
8109 NN = mClosingApps.size();
8110 for (i=0; i<NN; i++) {
8111 AppWindowToken wtoken = mClosingApps.get(i);
8112 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8113 "Now closing app" + wtoken);
8114 wtoken.inPendingTransaction = false;
8115 setTokenVisibilityLocked(wtoken, lp, false, transit, false);
8116 wtoken.updateReportedVisibilityLocked();
8117 // Force the allDrawn flag, because we want to start
8118 // this guy's animations regardless of whether it's
8119 // gotten drawn.
8120 wtoken.allDrawn = true;
8121 }
8122
8123 mOpeningApps.clear();
8124 mClosingApps.clear();
8125
8126 // This has changed the visibility of windows, so perform
8127 // a new layout to get them all up-to-date.
8128 mLayoutNeeded = true;
8129 moveInputMethodWindowsIfNeededLocked(true);
8130 performLayoutLockedInner();
8131 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
8132
8133 restart = true;
8134 }
8135 }
8136 } while (restart);
8137
8138 // THIRD LOOP: Update the surfaces of all windows.
8139
8140 final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8141
8142 boolean obscured = false;
8143 boolean blurring = false;
8144 boolean dimming = false;
8145 boolean covered = false;
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008146 boolean syswin = false;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008147 boolean backgroundFillerShown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008148
8149 for (i=N-1; i>=0; i--) {
8150 WindowState w = (WindowState)mWindows.get(i);
8151
8152 boolean displayed = false;
8153 final WindowManager.LayoutParams attrs = w.mAttrs;
8154 final int attrFlags = attrs.flags;
8155
8156 if (w.mSurface != null) {
8157 w.computeShownFrameLocked();
8158 if (localLOGV) Log.v(
8159 TAG, "Placing surface #" + i + " " + w.mSurface
8160 + ": new=" + w.mShownFrame + ", old="
8161 + w.mLastShownFrame);
8162
8163 boolean resize;
8164 int width, height;
8165 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8166 resize = w.mLastRequestedWidth != w.mRequestedWidth ||
8167 w.mLastRequestedHeight != w.mRequestedHeight;
8168 // for a scaled surface, we just want to use
8169 // the requested size.
8170 width = w.mRequestedWidth;
8171 height = w.mRequestedHeight;
8172 w.mLastRequestedWidth = width;
8173 w.mLastRequestedHeight = height;
8174 w.mLastShownFrame.set(w.mShownFrame);
8175 try {
8176 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8177 } catch (RuntimeException e) {
8178 Log.w(TAG, "Error positioning surface in " + w, e);
8179 if (!recoveringMemory) {
8180 reclaimSomeSurfaceMemoryLocked(w, "position");
8181 }
8182 }
8183 } else {
8184 resize = !w.mLastShownFrame.equals(w.mShownFrame);
8185 width = w.mShownFrame.width();
8186 height = w.mShownFrame.height();
8187 w.mLastShownFrame.set(w.mShownFrame);
8188 if (resize) {
8189 if (SHOW_TRANSACTIONS) Log.i(
8190 TAG, " SURFACE " + w.mSurface + ": ("
8191 + w.mShownFrame.left + ","
8192 + w.mShownFrame.top + ") ("
8193 + w.mShownFrame.width() + "x"
8194 + w.mShownFrame.height() + ")");
8195 }
8196 }
8197
8198 if (resize) {
8199 if (width < 1) width = 1;
8200 if (height < 1) height = 1;
8201 if (w.mSurface != null) {
8202 try {
8203 w.mSurface.setSize(width, height);
8204 w.mSurface.setPosition(w.mShownFrame.left,
8205 w.mShownFrame.top);
8206 } catch (RuntimeException e) {
8207 // If something goes wrong with the surface (such
8208 // as running out of memory), don't take down the
8209 // entire system.
8210 Log.e(TAG, "Failure updating surface of " + w
8211 + "size=(" + width + "x" + height
8212 + "), pos=(" + w.mShownFrame.left
8213 + "," + w.mShownFrame.top + ")", e);
8214 if (!recoveringMemory) {
8215 reclaimSomeSurfaceMemoryLocked(w, "size");
8216 }
8217 }
8218 }
8219 }
8220 if (!w.mAppFreezing) {
8221 w.mContentInsetsChanged =
8222 !w.mLastContentInsets.equals(w.mContentInsets);
8223 w.mVisibleInsetsChanged =
8224 !w.mLastVisibleInsets.equals(w.mVisibleInsets);
Romain Guy06882f82009-06-10 13:36:04 -07008225 if (!w.mLastFrame.equals(w.mFrame)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008226 || w.mContentInsetsChanged
8227 || w.mVisibleInsetsChanged) {
8228 w.mLastFrame.set(w.mFrame);
8229 w.mLastContentInsets.set(w.mContentInsets);
8230 w.mLastVisibleInsets.set(w.mVisibleInsets);
8231 // If the orientation is changing, then we need to
8232 // hold off on unfreezing the display until this
8233 // window has been redrawn; to do that, we need
8234 // to go through the process of getting informed
8235 // by the application when it has finished drawing.
8236 if (w.mOrientationChanging) {
8237 if (DEBUG_ORIENTATION) Log.v(TAG,
8238 "Orientation start waiting for draw in "
8239 + w + ", surface " + w.mSurface);
8240 w.mDrawPending = true;
8241 w.mCommitDrawPending = false;
8242 w.mReadyToShow = false;
8243 if (w.mAppToken != null) {
8244 w.mAppToken.allDrawn = false;
8245 }
8246 }
Romain Guy06882f82009-06-10 13:36:04 -07008247 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008248 "Resizing window " + w + " to " + w.mFrame);
8249 mResizingWindows.add(w);
8250 } else if (w.mOrientationChanging) {
8251 if (!w.mDrawPending && !w.mCommitDrawPending) {
8252 if (DEBUG_ORIENTATION) Log.v(TAG,
8253 "Orientation not waiting for draw in "
8254 + w + ", surface " + w.mSurface);
8255 w.mOrientationChanging = false;
8256 }
8257 }
8258 }
8259
8260 if (w.mAttachedHidden) {
8261 if (!w.mLastHidden) {
8262 //dump();
8263 w.mLastHidden = true;
8264 if (SHOW_TRANSACTIONS) Log.i(
8265 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)");
8266 if (w.mSurface != null) {
8267 try {
8268 w.mSurface.hide();
8269 } catch (RuntimeException e) {
8270 Log.w(TAG, "Exception hiding surface in " + w);
8271 }
8272 }
8273 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8274 }
8275 // If we are waiting for this window to handle an
8276 // orientation change, well, it is hidden, so
8277 // doesn't really matter. Note that this does
8278 // introduce a potential glitch if the window
8279 // becomes unhidden before it has drawn for the
8280 // new orientation.
8281 if (w.mOrientationChanging) {
8282 w.mOrientationChanging = false;
8283 if (DEBUG_ORIENTATION) Log.v(TAG,
8284 "Orientation change skips hidden " + w);
8285 }
8286 } else if (!w.isReadyForDisplay()) {
8287 if (!w.mLastHidden) {
8288 //dump();
8289 w.mLastHidden = true;
8290 if (SHOW_TRANSACTIONS) Log.i(
8291 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)");
8292 if (w.mSurface != null) {
8293 try {
8294 w.mSurface.hide();
8295 } catch (RuntimeException e) {
8296 Log.w(TAG, "Exception exception hiding surface in " + w);
8297 }
8298 }
8299 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8300 }
8301 // If we are waiting for this window to handle an
8302 // orientation change, well, it is hidden, so
8303 // doesn't really matter. Note that this does
8304 // introduce a potential glitch if the window
8305 // becomes unhidden before it has drawn for the
8306 // new orientation.
8307 if (w.mOrientationChanging) {
8308 w.mOrientationChanging = false;
8309 if (DEBUG_ORIENTATION) Log.v(TAG,
8310 "Orientation change skips hidden " + w);
8311 }
8312 } else if (w.mLastLayer != w.mAnimLayer
8313 || w.mLastAlpha != w.mShownAlpha
8314 || w.mLastDsDx != w.mDsDx
8315 || w.mLastDtDx != w.mDtDx
8316 || w.mLastDsDy != w.mDsDy
8317 || w.mLastDtDy != w.mDtDy
8318 || w.mLastHScale != w.mHScale
8319 || w.mLastVScale != w.mVScale
8320 || w.mLastHidden) {
8321 displayed = true;
8322 w.mLastAlpha = w.mShownAlpha;
8323 w.mLastLayer = w.mAnimLayer;
8324 w.mLastDsDx = w.mDsDx;
8325 w.mLastDtDx = w.mDtDx;
8326 w.mLastDsDy = w.mDsDy;
8327 w.mLastDtDy = w.mDtDy;
8328 w.mLastHScale = w.mHScale;
8329 w.mLastVScale = w.mVScale;
8330 if (SHOW_TRANSACTIONS) Log.i(
8331 TAG, " SURFACE " + w.mSurface + ": alpha="
8332 + w.mShownAlpha + " layer=" + w.mAnimLayer);
8333 if (w.mSurface != null) {
8334 try {
8335 w.mSurface.setAlpha(w.mShownAlpha);
8336 w.mSurface.setLayer(w.mAnimLayer);
8337 w.mSurface.setMatrix(
8338 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8339 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8340 } catch (RuntimeException e) {
8341 Log.w(TAG, "Error updating surface in " + w, e);
8342 if (!recoveringMemory) {
8343 reclaimSomeSurfaceMemoryLocked(w, "update");
8344 }
8345 }
8346 }
8347
8348 if (w.mLastHidden && !w.mDrawPending
8349 && !w.mCommitDrawPending
8350 && !w.mReadyToShow) {
8351 if (SHOW_TRANSACTIONS) Log.i(
8352 TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)");
8353 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w
8354 + " during relayout");
8355 if (showSurfaceRobustlyLocked(w)) {
8356 w.mHasDrawn = true;
8357 w.mLastHidden = false;
8358 } else {
8359 w.mOrientationChanging = false;
8360 }
8361 }
8362 if (w.mSurface != null) {
8363 w.mToken.hasVisible = true;
8364 }
8365 } else {
8366 displayed = true;
8367 }
8368
8369 if (displayed) {
8370 if (!covered) {
8371 if (attrs.width == LayoutParams.FILL_PARENT
8372 && attrs.height == LayoutParams.FILL_PARENT) {
8373 covered = true;
8374 }
8375 }
8376 if (w.mOrientationChanging) {
8377 if (w.mDrawPending || w.mCommitDrawPending) {
8378 orientationChangeComplete = false;
8379 if (DEBUG_ORIENTATION) Log.v(TAG,
8380 "Orientation continue waiting for draw in " + w);
8381 } else {
8382 w.mOrientationChanging = false;
8383 if (DEBUG_ORIENTATION) Log.v(TAG,
8384 "Orientation change complete in " + w);
8385 }
8386 }
8387 w.mToken.hasVisible = true;
8388 }
8389 } else if (w.mOrientationChanging) {
8390 if (DEBUG_ORIENTATION) Log.v(TAG,
8391 "Orientation change skips hidden " + w);
8392 w.mOrientationChanging = false;
8393 }
8394
8395 final boolean canBeSeen = w.isDisplayedLw();
8396
8397 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8398 focusDisplayed = true;
8399 }
8400
8401 // Update effect.
8402 if (!obscured) {
8403 if (w.mSurface != null) {
8404 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8405 holdScreen = w.mSession;
8406 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008407 if (!syswin && w.mAttrs.screenBrightness >= 0
8408 && screenBrightness < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008409 screenBrightness = w.mAttrs.screenBrightness;
8410 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008411 if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8412 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8413 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
8414 syswin = true;
8415 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008416 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008417
8418 boolean opaqueDrawn = w.isOpaqueDrawn();
8419 if (opaqueDrawn && w.isFullscreen(dw, dh)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008420 // This window completely covers everything behind it,
8421 // so we want to leave all of them as unblurred (for
8422 // performance reasons).
8423 obscured = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008424 } else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
8425 if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008426 // This window is in compatibility mode, and needs background filler.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008427 obscured = true;
8428 if (mBackgroundFillerSurface == null) {
8429 try {
8430 mBackgroundFillerSurface = new Surface(mFxSession, 0,
8431 0, dw, dh,
8432 PixelFormat.OPAQUE,
8433 Surface.FX_SURFACE_NORMAL);
8434 } catch (Exception e) {
8435 Log.e(TAG, "Exception creating filler surface", e);
8436 }
8437 }
8438 try {
8439 mBackgroundFillerSurface.setPosition(0, 0);
8440 mBackgroundFillerSurface.setSize(dw, dh);
8441 // Using the same layer as Dim because they will never be shown at the
8442 // same time.
8443 mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
8444 mBackgroundFillerSurface.show();
8445 } catch (RuntimeException e) {
8446 Log.e(TAG, "Exception showing filler surface");
8447 }
8448 backgroundFillerShown = true;
8449 mBackgroundFillerShown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008450 } else if (canBeSeen && !obscured &&
8451 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8452 if (localLOGV) Log.v(TAG, "Win " + w
8453 + ": blurring=" + blurring
8454 + " obscured=" + obscured
8455 + " displayed=" + displayed);
8456 if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8457 if (!dimming) {
8458 //Log.i(TAG, "DIM BEHIND: " + w);
8459 dimming = true;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008460 if (mDimAnimator == null) {
8461 mDimAnimator = new DimAnimator(mFxSession);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008462 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008463 mDimAnimator.show(dw, dh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008464 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008465 mDimAnimator.updateParameters(w, currentTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008466 }
8467 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8468 if (!blurring) {
8469 //Log.i(TAG, "BLUR BEHIND: " + w);
8470 blurring = true;
8471 mBlurShown = true;
8472 if (mBlurSurface == null) {
8473 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8474 + mBlurSurface + ": CREATE");
8475 try {
Romain Guy06882f82009-06-10 13:36:04 -07008476 mBlurSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008477 -1, 16, 16,
8478 PixelFormat.OPAQUE,
8479 Surface.FX_SURFACE_BLUR);
8480 } catch (Exception e) {
8481 Log.e(TAG, "Exception creating Blur surface", e);
8482 }
8483 }
8484 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8485 + mBlurSurface + ": SHOW pos=(0,0) (" +
8486 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8487 if (mBlurSurface != null) {
8488 mBlurSurface.setPosition(0, 0);
8489 mBlurSurface.setSize(dw, dh);
8490 try {
8491 mBlurSurface.show();
8492 } catch (RuntimeException e) {
8493 Log.w(TAG, "Failure showing blur surface", e);
8494 }
8495 }
8496 }
8497 mBlurSurface.setLayer(w.mAnimLayer-2);
8498 }
8499 }
8500 }
8501 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008502
8503 if (backgroundFillerShown == false && mBackgroundFillerShown) {
8504 mBackgroundFillerShown = false;
8505 if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
8506 try {
8507 mBackgroundFillerSurface.hide();
8508 } catch (RuntimeException e) {
8509 Log.e(TAG, "Exception hiding filler surface", e);
8510 }
8511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008512
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008513 if (mDimAnimator != null && mDimAnimator.mDimShown) {
8514 animating |= mDimAnimator.updateSurface(dimming, currentTime, mDisplayFrozen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008515 }
Romain Guy06882f82009-06-10 13:36:04 -07008516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008517 if (!blurring && mBlurShown) {
8518 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
8519 + ": HIDE");
8520 try {
8521 mBlurSurface.hide();
8522 } catch (IllegalArgumentException e) {
8523 Log.w(TAG, "Illegal argument exception hiding blur surface");
8524 }
8525 mBlurShown = false;
8526 }
8527
8528 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
8529 } catch (RuntimeException e) {
8530 Log.e(TAG, "Unhandled exception in Window Manager", e);
8531 }
8532
8533 Surface.closeTransaction();
Romain Guy06882f82009-06-10 13:36:04 -07008534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008535 if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
8536 "With display frozen, orientationChangeComplete="
8537 + orientationChangeComplete);
8538 if (orientationChangeComplete) {
8539 if (mWindowsFreezingScreen) {
8540 mWindowsFreezingScreen = false;
8541 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8542 }
8543 if (mAppsFreezingScreen == 0) {
8544 stopFreezingDisplayLocked();
8545 }
8546 }
Romain Guy06882f82009-06-10 13:36:04 -07008547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008548 i = mResizingWindows.size();
8549 if (i > 0) {
8550 do {
8551 i--;
8552 WindowState win = mResizingWindows.get(i);
8553 try {
8554 win.mClient.resized(win.mFrame.width(),
8555 win.mFrame.height(), win.mLastContentInsets,
8556 win.mLastVisibleInsets, win.mDrawPending);
8557 win.mContentInsetsChanged = false;
8558 win.mVisibleInsetsChanged = false;
8559 } catch (RemoteException e) {
8560 win.mOrientationChanging = false;
8561 }
8562 } while (i > 0);
8563 mResizingWindows.clear();
8564 }
Romain Guy06882f82009-06-10 13:36:04 -07008565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 // Destroy the surface of any windows that are no longer visible.
8567 i = mDestroySurface.size();
8568 if (i > 0) {
8569 do {
8570 i--;
8571 WindowState win = mDestroySurface.get(i);
8572 win.mDestroying = false;
8573 if (mInputMethodWindow == win) {
8574 mInputMethodWindow = null;
8575 }
8576 win.destroySurfaceLocked();
8577 } while (i > 0);
8578 mDestroySurface.clear();
8579 }
8580
8581 // Time to remove any exiting tokens?
8582 for (i=mExitingTokens.size()-1; i>=0; i--) {
8583 WindowToken token = mExitingTokens.get(i);
8584 if (!token.hasVisible) {
8585 mExitingTokens.remove(i);
8586 }
8587 }
8588
8589 // Time to remove any exiting applications?
8590 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8591 AppWindowToken token = mExitingAppTokens.get(i);
8592 if (!token.hasVisible && !mClosingApps.contains(token)) {
8593 mAppTokens.remove(token);
8594 mExitingAppTokens.remove(i);
8595 }
8596 }
8597
8598 if (focusDisplayed) {
8599 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8600 }
8601 if (animating) {
8602 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8603 }
8604 mQueue.setHoldScreenLocked(holdScreen != null);
8605 if (screenBrightness < 0 || screenBrightness > 1.0f) {
8606 mPowerManager.setScreenBrightnessOverride(-1);
8607 } else {
8608 mPowerManager.setScreenBrightnessOverride((int)
8609 (screenBrightness * Power.BRIGHTNESS_ON));
8610 }
8611 if (holdScreen != mHoldingScreenOn) {
8612 mHoldingScreenOn = holdScreen;
8613 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8614 mH.sendMessage(m);
8615 }
8616 }
8617
8618 void requestAnimationLocked(long delay) {
8619 if (!mAnimationPending) {
8620 mAnimationPending = true;
8621 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8622 }
8623 }
Romain Guy06882f82009-06-10 13:36:04 -07008624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008625 /**
8626 * Have the surface flinger show a surface, robustly dealing with
8627 * error conditions. In particular, if there is not enough memory
8628 * to show the surface, then we will try to get rid of other surfaces
8629 * in order to succeed.
Romain Guy06882f82009-06-10 13:36:04 -07008630 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008631 * @return Returns true if the surface was successfully shown.
8632 */
8633 boolean showSurfaceRobustlyLocked(WindowState win) {
8634 try {
8635 if (win.mSurface != null) {
8636 win.mSurface.show();
8637 }
8638 return true;
8639 } catch (RuntimeException e) {
8640 Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
8641 }
Romain Guy06882f82009-06-10 13:36:04 -07008642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008643 reclaimSomeSurfaceMemoryLocked(win, "show");
Romain Guy06882f82009-06-10 13:36:04 -07008644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008645 return false;
8646 }
Romain Guy06882f82009-06-10 13:36:04 -07008647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648 void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
8649 final Surface surface = win.mSurface;
Romain Guy06882f82009-06-10 13:36:04 -07008650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008651 EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
8652 win.mSession.mPid, operation);
Romain Guy06882f82009-06-10 13:36:04 -07008653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008654 if (mForceRemoves == null) {
8655 mForceRemoves = new ArrayList<WindowState>();
8656 }
Romain Guy06882f82009-06-10 13:36:04 -07008657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008658 long callingIdentity = Binder.clearCallingIdentity();
8659 try {
8660 // There was some problem... first, do a sanity check of the
8661 // window list to make sure we haven't left any dangling surfaces
8662 // around.
8663 int N = mWindows.size();
8664 boolean leakedSurface = false;
8665 Log.i(TAG, "Out of memory for surface! Looking for leaks...");
8666 for (int i=0; i<N; i++) {
8667 WindowState ws = (WindowState)mWindows.get(i);
8668 if (ws.mSurface != null) {
8669 if (!mSessions.contains(ws.mSession)) {
8670 Log.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8671 + ws + " surface=" + ws.mSurface
8672 + " token=" + win.mToken
8673 + " pid=" + ws.mSession.mPid
8674 + " uid=" + ws.mSession.mUid);
8675 ws.mSurface.clear();
8676 ws.mSurface = null;
8677 mForceRemoves.add(ws);
8678 i--;
8679 N--;
8680 leakedSurface = true;
8681 } else if (win.mAppToken != null && win.mAppToken.clientHidden) {
8682 Log.w(TAG, "LEAKED SURFACE (app token hidden): "
8683 + ws + " surface=" + ws.mSurface
8684 + " token=" + win.mAppToken);
8685 ws.mSurface.clear();
8686 ws.mSurface = null;
8687 leakedSurface = true;
8688 }
8689 }
8690 }
Romain Guy06882f82009-06-10 13:36:04 -07008691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008692 boolean killedApps = false;
8693 if (!leakedSurface) {
8694 Log.w(TAG, "No leaked surfaces; killing applicatons!");
8695 SparseIntArray pidCandidates = new SparseIntArray();
8696 for (int i=0; i<N; i++) {
8697 WindowState ws = (WindowState)mWindows.get(i);
8698 if (ws.mSurface != null) {
8699 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8700 }
8701 }
8702 if (pidCandidates.size() > 0) {
8703 int[] pids = new int[pidCandidates.size()];
8704 for (int i=0; i<pids.length; i++) {
8705 pids[i] = pidCandidates.keyAt(i);
8706 }
8707 try {
8708 if (mActivityManager.killPidsForMemory(pids)) {
8709 killedApps = true;
8710 }
8711 } catch (RemoteException e) {
8712 }
8713 }
8714 }
Romain Guy06882f82009-06-10 13:36:04 -07008715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008716 if (leakedSurface || killedApps) {
8717 // We managed to reclaim some memory, so get rid of the trouble
8718 // surface and ask the app to request another one.
8719 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8720 if (surface != null) {
8721 surface.clear();
8722 win.mSurface = null;
8723 }
Romain Guy06882f82009-06-10 13:36:04 -07008724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008725 try {
8726 win.mClient.dispatchGetNewSurface();
8727 } catch (RemoteException e) {
8728 }
8729 }
8730 } finally {
8731 Binder.restoreCallingIdentity(callingIdentity);
8732 }
8733 }
Romain Guy06882f82009-06-10 13:36:04 -07008734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008735 private boolean updateFocusedWindowLocked(int mode) {
8736 WindowState newFocus = computeFocusedWindowLocked();
8737 if (mCurrentFocus != newFocus) {
8738 // This check makes sure that we don't already have the focus
8739 // change message pending.
8740 mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8741 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8742 if (localLOGV) Log.v(
8743 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8744 final WindowState oldFocus = mCurrentFocus;
8745 mCurrentFocus = newFocus;
8746 mLosingFocus.remove(newFocus);
Romain Guy06882f82009-06-10 13:36:04 -07008747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008748 final WindowState imWindow = mInputMethodWindow;
8749 if (newFocus != imWindow && oldFocus != imWindow) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008750 if (moveInputMethodWindowsIfNeededLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008751 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008752 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8753 mLayoutNeeded = true;
8754 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008755 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8756 performLayoutLockedInner();
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008757 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8758 // Client will do the layout, but we need to assign layers
8759 // for handleNewWindowLocked() below.
8760 assignLayersLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008761 }
8762 }
Romain Guy06882f82009-06-10 13:36:04 -07008763
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008764 if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8765 mKeyWaiter.handleNewWindowLocked(newFocus);
8766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008767 return true;
8768 }
8769 return false;
8770 }
8771
8772 private WindowState computeFocusedWindowLocked() {
8773 WindowState result = null;
8774 WindowState win;
8775
8776 int i = mWindows.size() - 1;
8777 int nextAppIndex = mAppTokens.size()-1;
8778 WindowToken nextApp = nextAppIndex >= 0
8779 ? mAppTokens.get(nextAppIndex) : null;
8780
8781 while (i >= 0) {
8782 win = (WindowState)mWindows.get(i);
8783
8784 if (localLOGV || DEBUG_FOCUS) Log.v(
8785 TAG, "Looking for focus: " + i
8786 + " = " + win
8787 + ", flags=" + win.mAttrs.flags
8788 + ", canReceive=" + win.canReceiveKeys());
8789
8790 AppWindowToken thisApp = win.mAppToken;
Romain Guy06882f82009-06-10 13:36:04 -07008791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008792 // If this window's application has been removed, just skip it.
8793 if (thisApp != null && thisApp.removed) {
8794 i--;
8795 continue;
8796 }
Romain Guy06882f82009-06-10 13:36:04 -07008797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008798 // If there is a focused app, don't allow focus to go to any
8799 // windows below it. If this is an application window, step
8800 // through the app tokens until we find its app.
8801 if (thisApp != null && nextApp != null && thisApp != nextApp
8802 && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8803 int origAppIndex = nextAppIndex;
8804 while (nextAppIndex > 0) {
8805 if (nextApp == mFocusedApp) {
8806 // Whoops, we are below the focused app... no focus
8807 // for you!
8808 if (localLOGV || DEBUG_FOCUS) Log.v(
8809 TAG, "Reached focused app: " + mFocusedApp);
8810 return null;
8811 }
8812 nextAppIndex--;
8813 nextApp = mAppTokens.get(nextAppIndex);
8814 if (nextApp == thisApp) {
8815 break;
8816 }
8817 }
8818 if (thisApp != nextApp) {
8819 // Uh oh, the app token doesn't exist! This shouldn't
8820 // happen, but if it does we can get totally hosed...
8821 // so restart at the original app.
8822 nextAppIndex = origAppIndex;
8823 nextApp = mAppTokens.get(nextAppIndex);
8824 }
8825 }
8826
8827 // Dispatch to this window if it is wants key events.
8828 if (win.canReceiveKeys()) {
8829 if (DEBUG_FOCUS) Log.v(
8830 TAG, "Found focus @ " + i + " = " + win);
8831 result = win;
8832 break;
8833 }
8834
8835 i--;
8836 }
8837
8838 return result;
8839 }
8840
8841 private void startFreezingDisplayLocked() {
8842 if (mDisplayFrozen) {
Chris Tate2ad63a92009-03-25 17:36:48 -07008843 // Freezing the display also suspends key event delivery, to
8844 // keep events from going astray while the display is reconfigured.
8845 // If someone has changed orientation again while the screen is
8846 // still frozen, the events will continue to be blocked while the
8847 // successive orientation change is processed. To prevent spurious
8848 // ANRs, we reset the event dispatch timeout in this case.
8849 synchronized (mKeyWaiter) {
8850 mKeyWaiter.mWasFrozen = true;
8851 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008852 return;
8853 }
Romain Guy06882f82009-06-10 13:36:04 -07008854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008855 mScreenFrozenLock.acquire();
Romain Guy06882f82009-06-10 13:36:04 -07008856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008857 long now = SystemClock.uptimeMillis();
8858 //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8859 if (mFreezeGcPending != 0) {
8860 if (now > (mFreezeGcPending+1000)) {
8861 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
8862 mH.removeMessages(H.FORCE_GC);
8863 Runtime.getRuntime().gc();
8864 mFreezeGcPending = now;
8865 }
8866 } else {
8867 mFreezeGcPending = now;
8868 }
Romain Guy06882f82009-06-10 13:36:04 -07008869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008870 mDisplayFrozen = true;
8871 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
8872 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8873 mAppTransitionReady = true;
8874 }
Romain Guy06882f82009-06-10 13:36:04 -07008875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008876 if (PROFILE_ORIENTATION) {
8877 File file = new File("/data/system/frozen");
8878 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8879 }
8880 Surface.freezeDisplay(0);
8881 }
Romain Guy06882f82009-06-10 13:36:04 -07008882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008883 private void stopFreezingDisplayLocked() {
8884 if (!mDisplayFrozen) {
8885 return;
8886 }
Romain Guy06882f82009-06-10 13:36:04 -07008887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008888 mDisplayFrozen = false;
8889 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8890 if (PROFILE_ORIENTATION) {
8891 Debug.stopMethodTracing();
8892 }
8893 Surface.unfreezeDisplay(0);
Romain Guy06882f82009-06-10 13:36:04 -07008894
Chris Tate2ad63a92009-03-25 17:36:48 -07008895 // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
8896 // too because regular key delivery processing should resume immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008897 synchronized (mKeyWaiter) {
8898 mKeyWaiter.mWasFrozen = true;
8899 mKeyWaiter.notifyAll();
8900 }
8901
8902 // A little kludge: a lot could have happened while the
8903 // display was frozen, so now that we are coming back we
8904 // do a gc so that any remote references the system
8905 // processes holds on others can be released if they are
8906 // no longer needed.
8907 mH.removeMessages(H.FORCE_GC);
8908 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8909 2000);
Romain Guy06882f82009-06-10 13:36:04 -07008910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008911 mScreenFrozenLock.release();
8912 }
Romain Guy06882f82009-06-10 13:36:04 -07008913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008914 @Override
8915 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8916 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
8917 != PackageManager.PERMISSION_GRANTED) {
8918 pw.println("Permission Denial: can't dump WindowManager from from pid="
8919 + Binder.getCallingPid()
8920 + ", uid=" + Binder.getCallingUid());
8921 return;
8922 }
Romain Guy06882f82009-06-10 13:36:04 -07008923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008924 synchronized(mWindowMap) {
8925 pw.println("Current Window Manager state:");
8926 for (int i=mWindows.size()-1; i>=0; i--) {
8927 WindowState w = (WindowState)mWindows.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008928 pw.print(" Window #"); pw.print(i); pw.print(' ');
8929 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008930 w.dump(pw, " ");
8931 }
8932 if (mInputMethodDialogs.size() > 0) {
8933 pw.println(" ");
8934 pw.println(" Input method dialogs:");
8935 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
8936 WindowState w = mInputMethodDialogs.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008937 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008938 }
8939 }
8940 if (mPendingRemove.size() > 0) {
8941 pw.println(" ");
8942 pw.println(" Remove pending for:");
8943 for (int i=mPendingRemove.size()-1; i>=0; i--) {
8944 WindowState w = mPendingRemove.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008945 pw.print(" Remove #"); pw.print(i); pw.print(' ');
8946 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008947 w.dump(pw, " ");
8948 }
8949 }
8950 if (mForceRemoves != null && mForceRemoves.size() > 0) {
8951 pw.println(" ");
8952 pw.println(" Windows force removing:");
8953 for (int i=mForceRemoves.size()-1; i>=0; i--) {
8954 WindowState w = mForceRemoves.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008955 pw.print(" Removing #"); pw.print(i); pw.print(' ');
8956 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008957 w.dump(pw, " ");
8958 }
8959 }
8960 if (mDestroySurface.size() > 0) {
8961 pw.println(" ");
8962 pw.println(" Windows waiting to destroy their surface:");
8963 for (int i=mDestroySurface.size()-1; i>=0; i--) {
8964 WindowState w = mDestroySurface.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008965 pw.print(" Destroy #"); pw.print(i); pw.print(' ');
8966 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 w.dump(pw, " ");
8968 }
8969 }
8970 if (mLosingFocus.size() > 0) {
8971 pw.println(" ");
8972 pw.println(" Windows losing focus:");
8973 for (int i=mLosingFocus.size()-1; i>=0; i--) {
8974 WindowState w = mLosingFocus.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008975 pw.print(" Losing #"); pw.print(i); pw.print(' ');
8976 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008977 w.dump(pw, " ");
8978 }
8979 }
8980 if (mSessions.size() > 0) {
8981 pw.println(" ");
8982 pw.println(" All active sessions:");
8983 Iterator<Session> it = mSessions.iterator();
8984 while (it.hasNext()) {
8985 Session s = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008986 pw.print(" Session "); pw.print(s); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008987 s.dump(pw, " ");
8988 }
8989 }
8990 if (mTokenMap.size() > 0) {
8991 pw.println(" ");
8992 pw.println(" All tokens:");
8993 Iterator<WindowToken> it = mTokenMap.values().iterator();
8994 while (it.hasNext()) {
8995 WindowToken token = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008996 pw.print(" Token "); pw.print(token.token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008997 token.dump(pw, " ");
8998 }
8999 }
9000 if (mTokenList.size() > 0) {
9001 pw.println(" ");
9002 pw.println(" Window token list:");
9003 for (int i=0; i<mTokenList.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009004 pw.print(" #"); pw.print(i); pw.print(": ");
9005 pw.println(mTokenList.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009006 }
9007 }
9008 if (mAppTokens.size() > 0) {
9009 pw.println(" ");
9010 pw.println(" Application tokens in Z order:");
9011 for (int i=mAppTokens.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009012 pw.print(" App #"); pw.print(i); pw.print(": ");
9013 pw.println(mAppTokens.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009014 }
9015 }
9016 if (mFinishedStarting.size() > 0) {
9017 pw.println(" ");
9018 pw.println(" Finishing start of application tokens:");
9019 for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9020 WindowToken token = mFinishedStarting.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009021 pw.print(" Finished Starting #"); pw.print(i);
9022 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009023 token.dump(pw, " ");
9024 }
9025 }
9026 if (mExitingTokens.size() > 0) {
9027 pw.println(" ");
9028 pw.println(" Exiting tokens:");
9029 for (int i=mExitingTokens.size()-1; i>=0; i--) {
9030 WindowToken token = mExitingTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009031 pw.print(" Exiting #"); pw.print(i);
9032 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009033 token.dump(pw, " ");
9034 }
9035 }
9036 if (mExitingAppTokens.size() > 0) {
9037 pw.println(" ");
9038 pw.println(" Exiting application tokens:");
9039 for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9040 WindowToken token = mExitingAppTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009041 pw.print(" Exiting App #"); pw.print(i);
9042 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009043 token.dump(pw, " ");
9044 }
9045 }
9046 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009047 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
9048 pw.print(" mLastFocus="); pw.println(mLastFocus);
9049 pw.print(" mFocusedApp="); pw.println(mFocusedApp);
9050 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
9051 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
9052 pw.print(" mInTouchMode="); pw.println(mInTouchMode);
9053 pw.print(" mSystemBooted="); pw.print(mSystemBooted);
9054 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9055 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
9056 pw.print(" mBlurShown="); pw.println(mBlurShown);
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009057 if (mDimAnimator != null) {
9058 mDimAnimator.printTo(pw);
9059 } else {
9060 pw.print( " no DimAnimator ");
9061 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 pw.print(" mInputMethodAnimLayerAdjustment=");
9063 pw.println(mInputMethodAnimLayerAdjustment);
9064 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
9065 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9066 pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
9067 pw.print(" mRotation="); pw.print(mRotation);
9068 pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
9069 pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
9070 pw.print(" mAnimationPending="); pw.print(mAnimationPending);
9071 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9072 pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9073 pw.print(" mNextAppTransition=0x");
9074 pw.print(Integer.toHexString(mNextAppTransition));
9075 pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
9076 pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9077 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9078 pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9079 if (mOpeningApps.size() > 0) {
9080 pw.print(" mOpeningApps="); pw.println(mOpeningApps);
9081 }
9082 if (mClosingApps.size() > 0) {
9083 pw.print(" mClosingApps="); pw.println(mClosingApps);
9084 }
9085 pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth());
9086 pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087 pw.println(" KeyWaiter state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009088 pw.print(" mLastWin="); pw.print(mKeyWaiter.mLastWin);
9089 pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
9090 pw.print(" mFinished="); pw.print(mKeyWaiter.mFinished);
9091 pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
9092 pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
9093 pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009094 }
9095 }
9096
9097 public void monitor() {
9098 synchronized (mWindowMap) { }
9099 synchronized (mKeyguardDisabled) { }
9100 synchronized (mKeyWaiter) { }
9101 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009102
9103 /**
9104 * DimAnimator class that controls the dim animation. This holds the surface and
9105 * all state used for dim animation.
9106 */
9107 private static class DimAnimator {
9108 Surface mDimSurface;
9109 boolean mDimShown = false;
9110 float mDimCurrentAlpha;
9111 float mDimTargetAlpha;
9112 float mDimDeltaPerMs;
9113 long mLastDimAnimTime;
9114
9115 DimAnimator (SurfaceSession session) {
9116 if (mDimSurface == null) {
9117 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9118 + mDimSurface + ": CREATE");
9119 try {
9120 mDimSurface = new Surface(session, 0, -1, 16, 16, PixelFormat.OPAQUE,
9121 Surface.FX_SURFACE_DIM);
9122 } catch (Exception e) {
9123 Log.e(TAG, "Exception creating Dim surface", e);
9124 }
9125 }
9126 }
9127
9128 /**
9129 * Show the dim surface.
9130 */
9131 void show(int dw, int dh) {
9132 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
9133 dw + "x" + dh + ")");
9134 mDimShown = true;
9135 try {
9136 mDimSurface.setPosition(0, 0);
9137 mDimSurface.setSize(dw, dh);
9138 mDimSurface.show();
9139 } catch (RuntimeException e) {
9140 Log.w(TAG, "Failure showing dim surface", e);
9141 }
9142 }
9143
9144 /**
9145 * Set's the dim surface's layer and update dim parameters that will be used in
9146 * {@link updateSurface} after all windows are examined.
9147 */
9148 void updateParameters(WindowState w, long currentTime) {
9149 mDimSurface.setLayer(w.mAnimLayer-1);
9150
9151 final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
9152 if (SHOW_TRANSACTIONS) Log.i(TAG, "layer=" + (w.mAnimLayer-1) + ", target=" + target);
9153 if (mDimTargetAlpha != target) {
9154 // If the desired dim level has changed, then
9155 // start an animation to it.
9156 mLastDimAnimTime = currentTime;
9157 long duration = (w.mAnimating && w.mAnimation != null)
9158 ? w.mAnimation.computeDurationHint()
9159 : DEFAULT_DIM_DURATION;
9160 if (target > mDimTargetAlpha) {
9161 // This is happening behind the activity UI,
9162 // so we can make it run a little longer to
9163 // give a stronger impression without disrupting
9164 // the user.
9165 duration *= DIM_DURATION_MULTIPLIER;
9166 }
9167 if (duration < 1) {
9168 // Don't divide by zero
9169 duration = 1;
9170 }
9171 mDimTargetAlpha = target;
9172 mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
9173 }
9174 }
9175
9176 /**
9177 * Updating the surface's alpha. Returns true if the animation continues, or returns
9178 * false when the animation is finished and the dim surface is hidden.
9179 */
9180 boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
9181 if (!dimming) {
9182 if (mDimTargetAlpha != 0) {
9183 mLastDimAnimTime = currentTime;
9184 mDimTargetAlpha = 0;
9185 mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
9186 }
9187 }
9188
9189 boolean animating = false;
9190 if (mLastDimAnimTime != 0) {
9191 mDimCurrentAlpha += mDimDeltaPerMs
9192 * (currentTime-mLastDimAnimTime);
9193 boolean more = true;
9194 if (displayFrozen) {
9195 // If the display is frozen, there is no reason to animate.
9196 more = false;
9197 } else if (mDimDeltaPerMs > 0) {
9198 if (mDimCurrentAlpha > mDimTargetAlpha) {
9199 more = false;
9200 }
9201 } else if (mDimDeltaPerMs < 0) {
9202 if (mDimCurrentAlpha < mDimTargetAlpha) {
9203 more = false;
9204 }
9205 } else {
9206 more = false;
9207 }
9208
9209 // Do we need to continue animating?
9210 if (more) {
9211 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9212 + mDimSurface + ": alpha=" + mDimCurrentAlpha);
9213 mLastDimAnimTime = currentTime;
9214 mDimSurface.setAlpha(mDimCurrentAlpha);
9215 animating = true;
9216 } else {
9217 mDimCurrentAlpha = mDimTargetAlpha;
9218 mLastDimAnimTime = 0;
9219 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9220 + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
9221 mDimSurface.setAlpha(mDimCurrentAlpha);
9222 if (!dimming) {
9223 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
9224 + ": HIDE");
9225 try {
9226 mDimSurface.hide();
9227 } catch (RuntimeException e) {
9228 Log.w(TAG, "Illegal argument exception hiding dim surface");
9229 }
9230 mDimShown = false;
9231 }
9232 }
9233 }
9234 return animating;
9235 }
9236
9237 public void printTo(PrintWriter pw) {
9238 pw.print(" mDimShown="); pw.print(mDimShown);
9239 pw.print(" current="); pw.print(mDimCurrentAlpha);
9240 pw.print(" target="); pw.print(mDimTargetAlpha);
9241 pw.print(" delta="); pw.print(mDimDeltaPerMs);
9242 pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
9243 }
9244 }
9245
9246 /**
9247 * Animation that fade in after 0.5 interpolate time, or fade out in reverse order.
9248 * This is used for opening/closing transition for apps in compatible mode.
9249 */
9250 private static class FadeInOutAnimation extends Animation {
9251 int mWidth;
9252 boolean mFadeIn;
9253
9254 public FadeInOutAnimation(boolean fadeIn) {
9255 setInterpolator(new AccelerateInterpolator());
9256 setDuration(DEFAULT_FADE_IN_OUT_DURATION);
9257 mFadeIn = fadeIn;
9258 }
9259
9260 @Override
9261 protected void applyTransformation(float interpolatedTime, Transformation t) {
9262 float x = interpolatedTime;
9263 if (!mFadeIn) {
9264 x = 1.0f - x; // reverse the interpolation for fade out
9265 }
9266 if (x < 0.5) {
9267 // move the window out of the screen.
9268 t.getMatrix().setTranslate(mWidth, 0);
9269 } else {
9270 t.getMatrix().setTranslate(0, 0);// show
9271 t.setAlpha((x - 0.5f) * 2);
9272 }
9273 }
9274
9275 @Override
9276 public void initialize(int width, int height, int parentWidth, int parentHeight) {
9277 // width is the screen width {@see AppWindowToken#stepAnimatinoLocked}
9278 mWidth = width;
9279 }
9280
9281 @Override
9282 public boolean willChangeTransformationMatrix() {
9283 return true;
9284 }
9285
9286 @Override
9287 public boolean willChangeBounds() {
9288 return true;
9289 }
9290 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009291}
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009292