blob: 6af85db0a54a895a1d721356d082e66af4457b28 [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;
Mitsuru Oshimad2967e22009-07-20 14:01:43 -070030import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
32import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
33import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070034import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
36import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import 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;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070042import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
44import com.android.internal.app.IBatteryStats;
45import com.android.internal.policy.PolicyManager;
46import com.android.internal.view.IInputContext;
47import com.android.internal.view.IInputMethodClient;
48import com.android.internal.view.IInputMethodManager;
49import com.android.server.KeyInputQueue.QueuedEvent;
50import com.android.server.am.BatteryStatsService;
51
52import android.Manifest;
53import android.app.ActivityManagerNative;
54import android.app.IActivityManager;
55import android.content.Context;
56import android.content.pm.ActivityInfo;
57import android.content.pm.PackageManager;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -070058import android.content.res.CompatibilityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.content.res.Configuration;
60import android.graphics.Matrix;
61import android.graphics.PixelFormat;
62import android.graphics.Rect;
63import android.graphics.Region;
64import android.os.BatteryStats;
65import android.os.Binder;
66import android.os.Debug;
67import android.os.Handler;
68import android.os.IBinder;
Michael Chan53071d62009-05-13 17:29:48 -070069import android.os.LatencyTimer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.LocalPowerManager;
71import android.os.Looper;
72import android.os.Message;
73import android.os.Parcel;
74import android.os.ParcelFileDescriptor;
75import android.os.Power;
76import android.os.PowerManager;
77import android.os.Process;
78import android.os.RemoteException;
79import android.os.ServiceManager;
80import android.os.SystemClock;
81import android.os.SystemProperties;
82import android.os.TokenWatcher;
83import android.provider.Settings;
Dianne Hackborn723738c2009-06-25 19:48:04 -070084import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.util.EventLog;
86import android.util.Log;
87import android.util.SparseIntArray;
88import android.view.Display;
89import android.view.Gravity;
90import android.view.IApplicationToken;
91import android.view.IOnKeyguardExitResult;
92import android.view.IRotationWatcher;
93import android.view.IWindow;
94import android.view.IWindowManager;
95import android.view.IWindowSession;
96import android.view.KeyEvent;
97import android.view.MotionEvent;
98import android.view.RawInputEvent;
99import android.view.Surface;
100import android.view.SurfaceSession;
101import android.view.View;
102import android.view.ViewTreeObserver;
103import android.view.WindowManager;
104import android.view.WindowManagerImpl;
105import android.view.WindowManagerPolicy;
106import android.view.WindowManager.LayoutParams;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700107import android.view.animation.AccelerateInterpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import android.view.animation.Animation;
109import android.view.animation.AnimationUtils;
110import android.view.animation.Transformation;
111
112import java.io.BufferedWriter;
113import java.io.File;
114import java.io.FileDescriptor;
115import java.io.IOException;
116import java.io.OutputStream;
117import java.io.OutputStreamWriter;
118import java.io.PrintWriter;
119import java.io.StringWriter;
120import java.net.Socket;
121import java.util.ArrayList;
122import java.util.HashMap;
123import java.util.HashSet;
124import java.util.Iterator;
125import java.util.List;
126
127/** {@hide} */
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700128public class WindowManagerService extends IWindowManager.Stub
129 implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 static final String TAG = "WindowManager";
131 static final boolean DEBUG = false;
132 static final boolean DEBUG_FOCUS = false;
133 static final boolean DEBUG_ANIM = false;
134 static final boolean DEBUG_LAYERS = false;
135 static final boolean DEBUG_INPUT = false;
136 static final boolean DEBUG_INPUT_METHOD = false;
137 static final boolean DEBUG_VISIBILITY = false;
138 static final boolean DEBUG_ORIENTATION = false;
139 static final boolean DEBUG_APP_TRANSITIONS = false;
140 static final boolean DEBUG_STARTING_WINDOW = false;
141 static final boolean DEBUG_REORDER = false;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -0700142 static final boolean DEBUG_WALLPAPER = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static final boolean SHOW_TRANSACTIONS = false;
Michael Chan53071d62009-05-13 17:29:48 -0700144 static final boolean MEASURE_LATENCY = false;
145 static private LatencyTimer lt;
146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 static final boolean PROFILE_ORIENTATION = false;
148 static final boolean BLUR = true;
Dave Bortcfe65242009-04-09 14:51:04 -0700149 static final boolean localLOGV = DEBUG;
Romain Guy06882f82009-06-10 13:36:04 -0700150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
Romain Guy06882f82009-06-10 13:36:04 -0700152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 /** How long to wait for first key repeat, in milliseconds */
154 static final int KEY_REPEAT_FIRST_DELAY = 750;
Romain Guy06882f82009-06-10 13:36:04 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 /** How long to wait for subsequent key repeats, in milliseconds */
157 static final int KEY_REPEAT_DELAY = 50;
158
159 /** How much to multiply the policy's type layer, to reserve room
160 * for multiple windows of the same type and Z-ordering adjustment
161 * with TYPE_LAYER_OFFSET. */
162 static final int TYPE_LAYER_MULTIPLIER = 10000;
Romain Guy06882f82009-06-10 13:36:04 -0700163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
165 * or below others in the same layer. */
166 static final int TYPE_LAYER_OFFSET = 1000;
Romain Guy06882f82009-06-10 13:36:04 -0700167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 /** How much to increment the layer for each window, to reserve room
169 * for effect surfaces between them.
170 */
171 static final int WINDOW_LAYER_MULTIPLIER = 5;
Romain Guy06882f82009-06-10 13:36:04 -0700172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 /** The maximum length we will accept for a loaded animation duration:
174 * this is 10 seconds.
175 */
176 static final int MAX_ANIMATION_DURATION = 10*1000;
177
178 /** Amount of time (in milliseconds) to animate the dim surface from one
179 * value to another, when no window animation is driving it.
180 */
181 static final int DEFAULT_DIM_DURATION = 200;
182
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700183 /** Amount of time (in milliseconds) to animate the fade-in-out transition for
184 * compatible windows.
185 */
186 static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 /** Adjustment to time to perform a dim, to make it more dramatic.
189 */
190 static final int DIM_DURATION_MULTIPLIER = 6;
Romain Guy06882f82009-06-10 13:36:04 -0700191
Dianne Hackborncfaef692009-06-15 14:24:44 -0700192 static final int INJECT_FAILED = 0;
193 static final int INJECT_SUCCEEDED = 1;
194 static final int INJECT_NO_PERMISSION = -1;
195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 static final int UPDATE_FOCUS_NORMAL = 0;
197 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
198 static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
199 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
Romain Guy06882f82009-06-10 13:36:04 -0700200
Michael Chane96440f2009-05-06 10:27:36 -0700201 /** The minimum time between dispatching touch events. */
202 int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
203
204 // Last touch event time
205 long mLastTouchEventTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700206
Michael Chane96440f2009-05-06 10:27:36 -0700207 // Last touch event type
208 int mLastTouchEventType = OTHER_EVENT;
Romain Guy06882f82009-06-10 13:36:04 -0700209
Michael Chane96440f2009-05-06 10:27:36 -0700210 // Time to wait before calling useractivity again. This saves CPU usage
211 // when we get a flood of touch events.
212 static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
213
214 // Last time we call user activity
215 long mLastUserActivityCallTime = 0;
216
Romain Guy06882f82009-06-10 13:36:04 -0700217 // Last time we updated battery stats
Michael Chane96440f2009-05-06 10:27:36 -0700218 long mLastBatteryStatsCallTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 private static final String SYSTEM_SECURE = "ro.secure";
Romain Guy06882f82009-06-10 13:36:04 -0700221 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
223 /**
224 * Condition waited on by {@link #reenableKeyguard} to know the call to
225 * the window policy has finished.
226 */
227 private boolean mWaitingUntilKeyguardReenabled = false;
228
229
230 final TokenWatcher mKeyguardDisabled = new TokenWatcher(
231 new Handler(), "WindowManagerService.mKeyguardDisabled") {
232 public void acquired() {
233 mPolicy.enableKeyguard(false);
234 }
235 public void released() {
236 synchronized (mKeyguardDisabled) {
237 mPolicy.enableKeyguard(true);
238 mWaitingUntilKeyguardReenabled = false;
239 mKeyguardDisabled.notifyAll();
240 }
241 }
242 };
243
244 final Context mContext;
245
246 final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 final boolean mLimitedAlphaCompositing;
Romain Guy06882f82009-06-10 13:36:04 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
251
252 final IActivityManager mActivityManager;
Romain Guy06882f82009-06-10 13:36:04 -0700253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 final IBatteryStats mBatteryStats;
Romain Guy06882f82009-06-10 13:36:04 -0700255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 /**
257 * All currently active sessions with clients.
258 */
259 final HashSet<Session> mSessions = new HashSet<Session>();
Romain Guy06882f82009-06-10 13:36:04 -0700260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 /**
262 * Mapping from an IWindow IBinder to the server's Window object.
263 * This is also used as the lock for all of our state.
264 */
265 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
266
267 /**
268 * Mapping from a token IBinder to a WindowToken object.
269 */
270 final HashMap<IBinder, WindowToken> mTokenMap =
271 new HashMap<IBinder, WindowToken>();
272
273 /**
274 * The same tokens as mTokenMap, stored in a list for efficient iteration
275 * over them.
276 */
277 final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 /**
280 * Window tokens that are in the process of exiting, but still
281 * on screen for animations.
282 */
283 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
284
285 /**
286 * Z-ordered (bottom-most first) list of all application tokens, for
287 * controlling the ordering of windows in different applications. This
288 * contains WindowToken objects.
289 */
290 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
291
292 /**
293 * Application tokens that are in the process of exiting, but still
294 * on screen for animations.
295 */
296 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
297
298 /**
299 * List of window tokens that have finished starting their application,
300 * and now need to have the policy remove their windows.
301 */
302 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
303
304 /**
305 * Z-ordered (bottom-most first) list of all Window objects.
306 */
307 final ArrayList mWindows = new ArrayList();
308
309 /**
310 * Windows that are being resized. Used so we can tell the client about
311 * the resize after closing the transaction in which we resized the
312 * underlying surface.
313 */
314 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
315
316 /**
317 * Windows whose animations have ended and now must be removed.
318 */
319 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
320
321 /**
322 * Windows whose surface should be destroyed.
323 */
324 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
325
326 /**
327 * Windows that have lost input focus and are waiting for the new
328 * focus window to be displayed before they are told about this.
329 */
330 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
331
332 /**
333 * This is set when we have run out of memory, and will either be an empty
334 * list or contain windows that need to be force removed.
335 */
336 ArrayList<WindowState> mForceRemoves;
Romain Guy06882f82009-06-10 13:36:04 -0700337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 IInputMethodManager mInputMethodManager;
Romain Guy06882f82009-06-10 13:36:04 -0700339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 SurfaceSession mFxSession;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700341 private DimAnimator mDimAnimator = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 Surface mBlurSurface;
343 boolean mBlurShown;
Romain Guy06882f82009-06-10 13:36:04 -0700344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 int mTransactionSequence = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 final float[] mTmpFloats = new float[9];
348
349 boolean mSafeMode;
350 boolean mDisplayEnabled = false;
351 boolean mSystemBooted = false;
352 int mRotation = 0;
353 int mRequestedRotation = 0;
354 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Dianne Hackborn321ae682009-03-27 16:16:03 -0700355 int mLastRotationFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 ArrayList<IRotationWatcher> mRotationWatchers
357 = new ArrayList<IRotationWatcher>();
Romain Guy06882f82009-06-10 13:36:04 -0700358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 boolean mLayoutNeeded = true;
360 boolean mAnimationPending = false;
361 boolean mDisplayFrozen = false;
362 boolean mWindowsFreezingScreen = false;
363 long mFreezeGcPending = 0;
364 int mAppsFreezingScreen = 0;
365
366 // This is held as long as we have the screen frozen, to give us time to
367 // perform a rotation animation when turning off shows the lock screen which
368 // changes the orientation.
369 PowerManager.WakeLock mScreenFrozenLock;
Romain Guy06882f82009-06-10 13:36:04 -0700370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 // State management of app transitions. When we are preparing for a
372 // transition, mNextAppTransition will be the kind of transition to
373 // perform or TRANSIT_NONE if we are not waiting. If we are waiting,
374 // mOpeningApps and mClosingApps are the lists of tokens that will be
375 // made visible or hidden at the next transition.
376 int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
377 boolean mAppTransitionReady = false;
378 boolean mAppTransitionTimeout = false;
379 boolean mStartingIconInTransition = false;
380 boolean mSkipAppTransitionAnimation = false;
381 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
382 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 //flag to detect fat touch events
385 boolean mFatTouch = false;
386 Display mDisplay;
Romain Guy06882f82009-06-10 13:36:04 -0700387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 H mH = new H();
389
390 WindowState mCurrentFocus = null;
391 WindowState mLastFocus = null;
Romain Guy06882f82009-06-10 13:36:04 -0700392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 // This just indicates the window the input method is on top of, not
394 // necessarily the window its input is going to.
395 WindowState mInputMethodTarget = null;
396 WindowState mUpcomingInputMethodTarget = null;
397 boolean mInputMethodTargetWaitingAnim;
398 int mInputMethodAnimLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -0700399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 WindowState mInputMethodWindow = null;
401 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
402
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700403 final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
404
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700405 // If non-null, this is the currently visible window that is associated
406 // with the wallpaper.
407 WindowState mWallpaperTarget = null;
408 int mWallpaperAnimLayerAdjustment;
409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 AppWindowToken mFocusedApp = null;
411
412 PowerManagerService mPowerManager;
Romain Guy06882f82009-06-10 13:36:04 -0700413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 float mWindowAnimationScale = 1.0f;
415 float mTransitionAnimationScale = 1.0f;
Romain Guy06882f82009-06-10 13:36:04 -0700416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 final KeyWaiter mKeyWaiter = new KeyWaiter();
418 final KeyQ mQueue;
419 final InputDispatcherThread mInputThread;
420
421 // Who is holding the screen on.
422 Session mHoldingScreenOn;
Romain Guy06882f82009-06-10 13:36:04 -0700423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 /**
425 * Whether the UI is currently running in touch mode (not showing
426 * navigational focus because the user is directly pressing the screen).
427 */
428 boolean mInTouchMode = false;
429
430 private ViewServer mViewServer;
431
432 final Rect mTempRect = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -0700433
Dianne Hackbornc485a602009-03-24 22:39:49 -0700434 final Configuration mTempConfiguration = new Configuration();
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700435 int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700436
437 // The frame use to limit the size of the app running in compatibility mode.
438 Rect mCompatibleScreenFrame = new Rect();
439 // The surface used to fill the outer rim of the app running in compatibility mode.
440 Surface mBackgroundFillerSurface = null;
441 boolean mBackgroundFillerShown = false;
442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 public static WindowManagerService main(Context context,
444 PowerManagerService pm, boolean haveInputMethods) {
445 WMThread thr = new WMThread(context, pm, haveInputMethods);
446 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 synchronized (thr) {
449 while (thr.mService == null) {
450 try {
451 thr.wait();
452 } catch (InterruptedException e) {
453 }
454 }
455 }
Romain Guy06882f82009-06-10 13:36:04 -0700456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 return thr.mService;
458 }
Romain Guy06882f82009-06-10 13:36:04 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 static class WMThread extends Thread {
461 WindowManagerService mService;
Romain Guy06882f82009-06-10 13:36:04 -0700462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 private final Context mContext;
464 private final PowerManagerService mPM;
465 private final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 public WMThread(Context context, PowerManagerService pm,
468 boolean haveInputMethods) {
469 super("WindowManager");
470 mContext = context;
471 mPM = pm;
472 mHaveInputMethods = haveInputMethods;
473 }
Romain Guy06882f82009-06-10 13:36:04 -0700474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 public void run() {
476 Looper.prepare();
477 WindowManagerService s = new WindowManagerService(mContext, mPM,
478 mHaveInputMethods);
479 android.os.Process.setThreadPriority(
480 android.os.Process.THREAD_PRIORITY_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -0700481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 synchronized (this) {
483 mService = s;
484 notifyAll();
485 }
Romain Guy06882f82009-06-10 13:36:04 -0700486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 Looper.loop();
488 }
489 }
490
491 static class PolicyThread extends Thread {
492 private final WindowManagerPolicy mPolicy;
493 private final WindowManagerService mService;
494 private final Context mContext;
495 private final PowerManagerService mPM;
496 boolean mRunning = false;
Romain Guy06882f82009-06-10 13:36:04 -0700497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 public PolicyThread(WindowManagerPolicy policy,
499 WindowManagerService service, Context context,
500 PowerManagerService pm) {
501 super("WindowManagerPolicy");
502 mPolicy = policy;
503 mService = service;
504 mContext = context;
505 mPM = pm;
506 }
Romain Guy06882f82009-06-10 13:36:04 -0700507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 public void run() {
509 Looper.prepare();
510 //Looper.myLooper().setMessageLogging(new LogPrinter(
511 // Log.VERBOSE, "WindowManagerPolicy"));
512 android.os.Process.setThreadPriority(
513 android.os.Process.THREAD_PRIORITY_FOREGROUND);
514 mPolicy.init(mContext, mService, mPM);
Romain Guy06882f82009-06-10 13:36:04 -0700515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 synchronized (this) {
517 mRunning = true;
518 notifyAll();
519 }
Romain Guy06882f82009-06-10 13:36:04 -0700520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 Looper.loop();
522 }
523 }
524
525 private WindowManagerService(Context context, PowerManagerService pm,
526 boolean haveInputMethods) {
Michael Chan53071d62009-05-13 17:29:48 -0700527 if (MEASURE_LATENCY) {
528 lt = new LatencyTimer(100, 1000);
529 }
530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 mContext = context;
532 mHaveInputMethods = haveInputMethods;
533 mLimitedAlphaCompositing = context.getResources().getBoolean(
534 com.android.internal.R.bool.config_sf_limitedAlpha);
Romain Guy06882f82009-06-10 13:36:04 -0700535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 mPowerManager = pm;
537 mPowerManager.setPolicy(mPolicy);
538 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
539 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
540 "SCREEN_FROZEN");
541 mScreenFrozenLock.setReferenceCounted(false);
542
543 mActivityManager = ActivityManagerNative.getDefault();
544 mBatteryStats = BatteryStatsService.getService();
545
546 // Get persisted window scale setting
547 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
548 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
549 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
550 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
Romain Guy06882f82009-06-10 13:36:04 -0700551
Michael Chan9f028e62009-08-04 17:37:46 -0700552 int max_events_per_sec = 35;
553 try {
554 max_events_per_sec = Integer.parseInt(SystemProperties
555 .get("windowsmgr.max_events_per_sec"));
556 if (max_events_per_sec < 1) {
557 max_events_per_sec = 35;
558 }
559 } catch (NumberFormatException e) {
560 }
561 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 mQueue = new KeyQ();
564
565 mInputThread = new InputDispatcherThread();
Romain Guy06882f82009-06-10 13:36:04 -0700566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
568 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 synchronized (thr) {
571 while (!thr.mRunning) {
572 try {
573 thr.wait();
574 } catch (InterruptedException e) {
575 }
576 }
577 }
Romain Guy06882f82009-06-10 13:36:04 -0700578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 mInputThread.start();
Romain Guy06882f82009-06-10 13:36:04 -0700580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 // Add ourself to the Watchdog monitors.
582 Watchdog.getInstance().addMonitor(this);
583 }
584
585 @Override
586 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
587 throws RemoteException {
588 try {
589 return super.onTransact(code, data, reply, flags);
590 } catch (RuntimeException e) {
591 // The window manager only throws security exceptions, so let's
592 // log all others.
593 if (!(e instanceof SecurityException)) {
594 Log.e(TAG, "Window Manager Crash", e);
595 }
596 throw e;
597 }
598 }
599
600 private void placeWindowAfter(Object pos, WindowState window) {
601 final int i = mWindows.indexOf(pos);
602 if (localLOGV || DEBUG_FOCUS) Log.v(
603 TAG, "Adding window " + window + " at "
604 + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
605 mWindows.add(i+1, window);
606 }
607
608 private void placeWindowBefore(Object pos, WindowState window) {
609 final int i = mWindows.indexOf(pos);
610 if (localLOGV || DEBUG_FOCUS) Log.v(
611 TAG, "Adding window " + window + " at "
612 + i + " of " + mWindows.size() + " (before " + pos + ")");
613 mWindows.add(i, window);
614 }
615
616 //This method finds out the index of a window that has the same app token as
617 //win. used for z ordering the windows in mWindows
618 private int findIdxBasedOnAppTokens(WindowState win) {
619 //use a local variable to cache mWindows
620 ArrayList localmWindows = mWindows;
621 int jmax = localmWindows.size();
622 if(jmax == 0) {
623 return -1;
624 }
625 for(int j = (jmax-1); j >= 0; j--) {
626 WindowState wentry = (WindowState)localmWindows.get(j);
627 if(wentry.mAppToken == win.mAppToken) {
628 return j;
629 }
630 }
631 return -1;
632 }
Romain Guy06882f82009-06-10 13:36:04 -0700633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
635 final IWindow client = win.mClient;
636 final WindowToken token = win.mToken;
637 final ArrayList localmWindows = mWindows;
Romain Guy06882f82009-06-10 13:36:04 -0700638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 final int N = localmWindows.size();
640 final WindowState attached = win.mAttachedWindow;
641 int i;
642 if (attached == null) {
643 int tokenWindowsPos = token.windows.size();
644 if (token.appWindowToken != null) {
645 int index = tokenWindowsPos-1;
646 if (index >= 0) {
647 // If this application has existing windows, we
648 // simply place the new window on top of them... but
649 // keep the starting window on top.
650 if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
651 // Base windows go behind everything else.
652 placeWindowBefore(token.windows.get(0), win);
653 tokenWindowsPos = 0;
654 } else {
655 AppWindowToken atoken = win.mAppToken;
656 if (atoken != null &&
657 token.windows.get(index) == atoken.startingWindow) {
658 placeWindowBefore(token.windows.get(index), win);
659 tokenWindowsPos--;
660 } else {
661 int newIdx = findIdxBasedOnAppTokens(win);
662 if(newIdx != -1) {
Romain Guy06882f82009-06-10 13:36:04 -0700663 //there is a window above this one associated with the same
664 //apptoken note that the window could be a floating window
665 //that was created later or a window at the top of the list of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 //windows associated with this token.
667 localmWindows.add(newIdx+1, win);
Romain Guy06882f82009-06-10 13:36:04 -0700668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 }
670 }
671 } else {
672 if (localLOGV) Log.v(
673 TAG, "Figuring out where to add app window "
674 + client.asBinder() + " (token=" + token + ")");
675 // Figure out where the window should go, based on the
676 // order of applications.
677 final int NA = mAppTokens.size();
678 Object pos = null;
679 for (i=NA-1; i>=0; i--) {
680 AppWindowToken t = mAppTokens.get(i);
681 if (t == token) {
682 i--;
683 break;
684 }
685 if (t.windows.size() > 0) {
686 pos = t.windows.get(0);
687 }
688 }
689 // We now know the index into the apps. If we found
690 // an app window above, that gives us the position; else
691 // we need to look some more.
692 if (pos != null) {
693 // Move behind any windows attached to this one.
Romain Guy06882f82009-06-10 13:36:04 -0700694 WindowToken atoken =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 mTokenMap.get(((WindowState)pos).mClient.asBinder());
696 if (atoken != null) {
697 final int NC = atoken.windows.size();
698 if (NC > 0) {
699 WindowState bottom = atoken.windows.get(0);
700 if (bottom.mSubLayer < 0) {
701 pos = bottom;
702 }
703 }
704 }
705 placeWindowBefore(pos, win);
706 } else {
707 while (i >= 0) {
708 AppWindowToken t = mAppTokens.get(i);
709 final int NW = t.windows.size();
710 if (NW > 0) {
711 pos = t.windows.get(NW-1);
712 break;
713 }
714 i--;
715 }
716 if (pos != null) {
717 // Move in front of any windows attached to this
718 // one.
719 WindowToken atoken =
720 mTokenMap.get(((WindowState)pos).mClient.asBinder());
721 if (atoken != null) {
722 final int NC = atoken.windows.size();
723 if (NC > 0) {
724 WindowState top = atoken.windows.get(NC-1);
725 if (top.mSubLayer >= 0) {
726 pos = top;
727 }
728 }
729 }
730 placeWindowAfter(pos, win);
731 } else {
732 // Just search for the start of this layer.
733 final int myLayer = win.mBaseLayer;
734 for (i=0; i<N; i++) {
735 WindowState w = (WindowState)localmWindows.get(i);
736 if (w.mBaseLayer > myLayer) {
737 break;
738 }
739 }
740 if (localLOGV || DEBUG_FOCUS) Log.v(
741 TAG, "Adding window " + win + " at "
742 + i + " of " + N);
743 localmWindows.add(i, win);
744 }
745 }
746 }
747 } else {
748 // Figure out where window should go, based on layer.
749 final int myLayer = win.mBaseLayer;
750 for (i=N-1; i>=0; i--) {
751 if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
752 i++;
753 break;
754 }
755 }
756 if (i < 0) i = 0;
757 if (localLOGV || DEBUG_FOCUS) Log.v(
758 TAG, "Adding window " + win + " at "
759 + i + " of " + N);
760 localmWindows.add(i, win);
761 }
762 if (addToToken) {
763 token.windows.add(tokenWindowsPos, win);
764 }
765
766 } else {
767 // Figure out this window's ordering relative to the window
768 // it is attached to.
769 final int NA = token.windows.size();
770 final int sublayer = win.mSubLayer;
771 int largestSublayer = Integer.MIN_VALUE;
772 WindowState windowWithLargestSublayer = null;
773 for (i=0; i<NA; i++) {
774 WindowState w = token.windows.get(i);
775 final int wSublayer = w.mSubLayer;
776 if (wSublayer >= largestSublayer) {
777 largestSublayer = wSublayer;
778 windowWithLargestSublayer = w;
779 }
780 if (sublayer < 0) {
781 // For negative sublayers, we go below all windows
782 // in the same sublayer.
783 if (wSublayer >= sublayer) {
784 if (addToToken) {
785 token.windows.add(i, win);
786 }
787 placeWindowBefore(
788 wSublayer >= 0 ? attached : w, win);
789 break;
790 }
791 } else {
792 // For positive sublayers, we go above all windows
793 // in the same sublayer.
794 if (wSublayer > sublayer) {
795 if (addToToken) {
796 token.windows.add(i, win);
797 }
798 placeWindowBefore(w, win);
799 break;
800 }
801 }
802 }
803 if (i >= NA) {
804 if (addToToken) {
805 token.windows.add(win);
806 }
807 if (sublayer < 0) {
808 placeWindowBefore(attached, win);
809 } else {
810 placeWindowAfter(largestSublayer >= 0
811 ? windowWithLargestSublayer
812 : attached,
813 win);
814 }
815 }
816 }
Romain Guy06882f82009-06-10 13:36:04 -0700817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 if (win.mAppToken != null && addToToken) {
819 win.mAppToken.allAppWindows.add(win);
820 }
821 }
Romain Guy06882f82009-06-10 13:36:04 -0700822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 static boolean canBeImeTarget(WindowState w) {
824 final int fl = w.mAttrs.flags
825 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
826 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
827 return w.isVisibleOrAdding();
828 }
829 return false;
830 }
Romain Guy06882f82009-06-10 13:36:04 -0700831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
833 final ArrayList localmWindows = mWindows;
834 final int N = localmWindows.size();
835 WindowState w = null;
836 int i = N;
837 while (i > 0) {
838 i--;
839 w = (WindowState)localmWindows.get(i);
Romain Guy06882f82009-06-10 13:36:04 -0700840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
842 // + Integer.toHexString(w.mAttrs.flags));
843 if (canBeImeTarget(w)) {
844 //Log.i(TAG, "Putting input method here!");
Romain Guy06882f82009-06-10 13:36:04 -0700845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 // Yet more tricksyness! If this window is a "starting"
847 // window, we do actually want to be on top of it, but
848 // it is not -really- where input will go. So if the caller
849 // is not actually looking to move the IME, look down below
850 // for a real window to target...
851 if (!willMove
852 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
853 && i > 0) {
854 WindowState wb = (WindowState)localmWindows.get(i-1);
855 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
856 i--;
857 w = wb;
858 }
859 }
860 break;
861 }
862 }
Romain Guy06882f82009-06-10 13:36:04 -0700863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 mUpcomingInputMethodTarget = w;
Romain Guy06882f82009-06-10 13:36:04 -0700865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
867 + w + " willMove=" + willMove);
Romain Guy06882f82009-06-10 13:36:04 -0700868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 if (willMove && w != null) {
870 final WindowState curTarget = mInputMethodTarget;
871 if (curTarget != null && curTarget.mAppToken != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 // Now some fun for dealing with window animations that
874 // modify the Z order. We need to look at all windows below
875 // the current target that are in this app, finding the highest
876 // visible one in layering.
877 AppWindowToken token = curTarget.mAppToken;
878 WindowState highestTarget = null;
879 int highestPos = 0;
880 if (token.animating || token.animation != null) {
881 int pos = 0;
882 pos = localmWindows.indexOf(curTarget);
883 while (pos >= 0) {
884 WindowState win = (WindowState)localmWindows.get(pos);
885 if (win.mAppToken != token) {
886 break;
887 }
888 if (!win.mRemoved) {
889 if (highestTarget == null || win.mAnimLayer >
890 highestTarget.mAnimLayer) {
891 highestTarget = win;
892 highestPos = pos;
893 }
894 }
895 pos--;
896 }
897 }
Romain Guy06882f82009-06-10 13:36:04 -0700898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 if (highestTarget != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700900 if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 + mNextAppTransition + " " + highestTarget
902 + " animating=" + highestTarget.isAnimating()
903 + " layer=" + highestTarget.mAnimLayer
904 + " new layer=" + w.mAnimLayer);
Romain Guy06882f82009-06-10 13:36:04 -0700905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
907 // If we are currently setting up for an animation,
908 // hold everything until we can find out what will happen.
909 mInputMethodTargetWaitingAnim = true;
910 mInputMethodTarget = highestTarget;
911 return highestPos + 1;
912 } else if (highestTarget.isAnimating() &&
913 highestTarget.mAnimLayer > w.mAnimLayer) {
914 // If the window we are currently targeting is involved
915 // with an animation, and it is on top of the next target
916 // we will be over, then hold off on moving until
917 // that is done.
918 mInputMethodTarget = highestTarget;
919 return highestPos + 1;
920 }
921 }
922 }
923 }
Romain Guy06882f82009-06-10 13:36:04 -0700924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 //Log.i(TAG, "Placing input method @" + (i+1));
926 if (w != null) {
927 if (willMove) {
928 RuntimeException e = new RuntimeException();
929 e.fillInStackTrace();
930 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
931 + mInputMethodTarget + " to " + w, e);
932 mInputMethodTarget = w;
933 if (w.mAppToken != null) {
934 setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
935 } else {
936 setInputMethodAnimLayerAdjustment(0);
937 }
938 }
939 return i+1;
940 }
941 if (willMove) {
942 RuntimeException e = new RuntimeException();
943 e.fillInStackTrace();
944 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
945 + mInputMethodTarget + " to null", e);
946 mInputMethodTarget = null;
947 setInputMethodAnimLayerAdjustment(0);
948 }
949 return -1;
950 }
Romain Guy06882f82009-06-10 13:36:04 -0700951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 void addInputMethodWindowToListLocked(WindowState win) {
953 int pos = findDesiredInputMethodWindowIndexLocked(true);
954 if (pos >= 0) {
955 win.mTargetAppToken = mInputMethodTarget.mAppToken;
956 mWindows.add(pos, win);
957 moveInputMethodDialogsLocked(pos+1);
958 return;
959 }
960 win.mTargetAppToken = null;
961 addWindowToListInOrderLocked(win, true);
962 moveInputMethodDialogsLocked(pos);
963 }
Romain Guy06882f82009-06-10 13:36:04 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 void setInputMethodAnimLayerAdjustment(int adj) {
966 if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
967 mInputMethodAnimLayerAdjustment = adj;
968 WindowState imw = mInputMethodWindow;
969 if (imw != null) {
970 imw.mAnimLayer = imw.mLayer + adj;
971 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
972 + " anim layer: " + imw.mAnimLayer);
973 int wi = imw.mChildWindows.size();
974 while (wi > 0) {
975 wi--;
976 WindowState cw = (WindowState)imw.mChildWindows.get(wi);
977 cw.mAnimLayer = cw.mLayer + adj;
978 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
979 + " anim layer: " + cw.mAnimLayer);
980 }
981 }
982 int di = mInputMethodDialogs.size();
983 while (di > 0) {
984 di --;
985 imw = mInputMethodDialogs.get(di);
986 imw.mAnimLayer = imw.mLayer + adj;
987 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
988 + " anim layer: " + imw.mAnimLayer);
989 }
990 }
Romain Guy06882f82009-06-10 13:36:04 -0700991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
993 int wpos = mWindows.indexOf(win);
994 if (wpos >= 0) {
995 if (wpos < interestingPos) interestingPos--;
996 mWindows.remove(wpos);
997 int NC = win.mChildWindows.size();
998 while (NC > 0) {
999 NC--;
1000 WindowState cw = (WindowState)win.mChildWindows.get(NC);
1001 int cpos = mWindows.indexOf(cw);
1002 if (cpos >= 0) {
1003 if (cpos < interestingPos) interestingPos--;
1004 mWindows.remove(cpos);
1005 }
1006 }
1007 }
1008 return interestingPos;
1009 }
Romain Guy06882f82009-06-10 13:36:04 -07001010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 private void reAddWindowToListInOrderLocked(WindowState win) {
1012 addWindowToListInOrderLocked(win, false);
1013 // This is a hack to get all of the child windows added as well
1014 // at the right position. Child windows should be rare and
1015 // this case should be rare, so it shouldn't be that big a deal.
1016 int wpos = mWindows.indexOf(win);
1017 if (wpos >= 0) {
1018 mWindows.remove(wpos);
1019 reAddWindowLocked(wpos, win);
1020 }
1021 }
Romain Guy06882f82009-06-10 13:36:04 -07001022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 void logWindowList(String prefix) {
1024 int N = mWindows.size();
1025 while (N > 0) {
1026 N--;
1027 Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
1028 }
1029 }
Romain Guy06882f82009-06-10 13:36:04 -07001030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 void moveInputMethodDialogsLocked(int pos) {
1032 ArrayList<WindowState> dialogs = mInputMethodDialogs;
Romain Guy06882f82009-06-10 13:36:04 -07001033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 final int N = dialogs.size();
1035 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
1036 for (int i=0; i<N; i++) {
1037 pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
1038 }
1039 if (DEBUG_INPUT_METHOD) {
1040 Log.v(TAG, "Window list w/pos=" + pos);
1041 logWindowList(" ");
1042 }
Romain Guy06882f82009-06-10 13:36:04 -07001043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 if (pos >= 0) {
1045 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
1046 if (pos < mWindows.size()) {
1047 WindowState wp = (WindowState)mWindows.get(pos);
1048 if (wp == mInputMethodWindow) {
1049 pos++;
1050 }
1051 }
1052 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
1053 for (int i=0; i<N; i++) {
1054 WindowState win = dialogs.get(i);
1055 win.mTargetAppToken = targetAppToken;
1056 pos = reAddWindowLocked(pos, win);
1057 }
1058 if (DEBUG_INPUT_METHOD) {
1059 Log.v(TAG, "Final window list:");
1060 logWindowList(" ");
1061 }
1062 return;
1063 }
1064 for (int i=0; i<N; i++) {
1065 WindowState win = dialogs.get(i);
1066 win.mTargetAppToken = null;
1067 reAddWindowToListInOrderLocked(win);
1068 if (DEBUG_INPUT_METHOD) {
1069 Log.v(TAG, "No IM target, final list:");
1070 logWindowList(" ");
1071 }
1072 }
1073 }
Romain Guy06882f82009-06-10 13:36:04 -07001074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
1076 final WindowState imWin = mInputMethodWindow;
1077 final int DN = mInputMethodDialogs.size();
1078 if (imWin == null && DN == 0) {
1079 return false;
1080 }
Romain Guy06882f82009-06-10 13:36:04 -07001081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 int imPos = findDesiredInputMethodWindowIndexLocked(true);
1083 if (imPos >= 0) {
1084 // In this case, the input method windows are to be placed
1085 // immediately above the window they are targeting.
Romain Guy06882f82009-06-10 13:36:04 -07001086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 // First check to see if the input method windows are already
1088 // located here, and contiguous.
1089 final int N = mWindows.size();
1090 WindowState firstImWin = imPos < N
1091 ? (WindowState)mWindows.get(imPos) : null;
Romain Guy06882f82009-06-10 13:36:04 -07001092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 // Figure out the actual input method window that should be
1094 // at the bottom of their stack.
1095 WindowState baseImWin = imWin != null
1096 ? imWin : mInputMethodDialogs.get(0);
1097 if (baseImWin.mChildWindows.size() > 0) {
1098 WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
1099 if (cw.mSubLayer < 0) baseImWin = cw;
1100 }
Romain Guy06882f82009-06-10 13:36:04 -07001101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 if (firstImWin == baseImWin) {
1103 // The windows haven't moved... but are they still contiguous?
1104 // First find the top IM window.
1105 int pos = imPos+1;
1106 while (pos < N) {
1107 if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
1108 break;
1109 }
1110 pos++;
1111 }
1112 pos++;
1113 // Now there should be no more input method windows above.
1114 while (pos < N) {
1115 if (((WindowState)mWindows.get(pos)).mIsImWindow) {
1116 break;
1117 }
1118 pos++;
1119 }
1120 if (pos >= N) {
1121 // All is good!
1122 return false;
1123 }
1124 }
Romain Guy06882f82009-06-10 13:36:04 -07001125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 if (imWin != null) {
1127 if (DEBUG_INPUT_METHOD) {
1128 Log.v(TAG, "Moving IM from " + imPos);
1129 logWindowList(" ");
1130 }
1131 imPos = tmpRemoveWindowLocked(imPos, imWin);
1132 if (DEBUG_INPUT_METHOD) {
1133 Log.v(TAG, "List after moving with new pos " + imPos + ":");
1134 logWindowList(" ");
1135 }
1136 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
1137 reAddWindowLocked(imPos, imWin);
1138 if (DEBUG_INPUT_METHOD) {
1139 Log.v(TAG, "List after moving IM to " + imPos + ":");
1140 logWindowList(" ");
1141 }
1142 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
1143 } else {
1144 moveInputMethodDialogsLocked(imPos);
1145 }
Romain Guy06882f82009-06-10 13:36:04 -07001146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 } else {
1148 // In this case, the input method windows go in a fixed layer,
1149 // because they aren't currently associated with a focus window.
Romain Guy06882f82009-06-10 13:36:04 -07001150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 if (imWin != null) {
1152 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
1153 tmpRemoveWindowLocked(0, imWin);
1154 imWin.mTargetAppToken = null;
1155 reAddWindowToListInOrderLocked(imWin);
1156 if (DEBUG_INPUT_METHOD) {
1157 Log.v(TAG, "List with no IM target:");
1158 logWindowList(" ");
1159 }
1160 if (DN > 0) moveInputMethodDialogsLocked(-1);;
1161 } else {
1162 moveInputMethodDialogsLocked(-1);;
1163 }
Romain Guy06882f82009-06-10 13:36:04 -07001164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 }
Romain Guy06882f82009-06-10 13:36:04 -07001166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 if (needAssignLayers) {
1168 assignLayersLocked();
1169 }
Romain Guy06882f82009-06-10 13:36:04 -07001170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 return true;
1172 }
Romain Guy06882f82009-06-10 13:36:04 -07001173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 void adjustInputMethodDialogsLocked() {
1175 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
1176 }
Romain Guy06882f82009-06-10 13:36:04 -07001177
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001178 boolean adjustWallpaperWindowsLocked() {
1179 boolean changed = false;
1180
1181 // First find top-most window that has asked to be on top of the
1182 // wallpaper; all wallpapers go behind it.
1183 final ArrayList localmWindows = mWindows;
1184 int N = localmWindows.size();
1185 WindowState w = null;
1186 int i = N;
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001187 boolean visible = false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001188 while (i > 0) {
1189 i--;
1190 w = (WindowState)localmWindows.get(i);
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001191 if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
1192 && !w.mDrawPending && !w.mCommitDrawPending) {
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001193 visible = true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001194 break;
1195 }
1196 }
1197
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001198 if (!visible) w = null;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001199 if (DEBUG_WALLPAPER && mWallpaperTarget != w) {
1200 Log.v(TAG, "New wallpaper target: " + w);
1201 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001202 mWallpaperTarget = w;
1203
1204 if (visible) {
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001205 // The window is visible to the compositor... but is it visible
1206 // to the user? That is what the wallpaper cares about.
1207 visible = !w.mObscured;
1208
1209 // If the wallpaper target is animating, we may need to copy
1210 // its layer adjustment.
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001211 mWallpaperAnimLayerAdjustment = w.mAppToken != null
1212 ? w.mAppToken.animLayerAdjustment : 0;
1213
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001214 // Now w is the window we are supposed to be behind... but we
1215 // need to be sure to also be behind any of its attached windows,
1216 // AND any starting window associated with it.
1217 while (i > 0) {
1218 WindowState wb = (WindowState)localmWindows.get(i-1);
1219 if (wb.mAttachedWindow != w &&
1220 (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
1221 wb.mToken != w.mToken)) {
1222 // This window is not related to the previous one in any
1223 // interesting way, so stop here.
1224 break;
1225 }
1226 w = wb;
1227 i--;
1228 }
1229 }
1230
1231 // Okay i is the position immediately above the wallpaper. Look at
1232 // what is below it for later.
1233 w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
1234
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001235 final int dw = mDisplay.getWidth();
1236 final int dh = mDisplay.getHeight();
1237
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001238 // Start stepping backwards from here, ensuring that our wallpaper windows
1239 // are correctly placed.
1240 int curTokenIndex = mWallpaperTokens.size();
1241 while (curTokenIndex > 0) {
1242 curTokenIndex--;
1243 WindowToken token = mWallpaperTokens.get(curTokenIndex);
1244 int curWallpaperIndex = token.windows.size();
1245 while (curWallpaperIndex > 0) {
1246 curWallpaperIndex--;
1247 WindowState wallpaper = token.windows.get(curWallpaperIndex);
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001248
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001249 if (visible) {
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001250 updateWallpaperOffsetLocked(w, wallpaper, dw, dh);
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001251 }
1252
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001253 // First, make sure the client has the current visibility
1254 // state.
1255 if (wallpaper.mWallpaperVisible != visible) {
1256 wallpaper.mWallpaperVisible = visible;
1257 try {
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001258 if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001259 "Setting visibility of wallpaper " + wallpaper
1260 + ": " + visible);
1261 wallpaper.mClient.dispatchAppVisibility(visible);
1262 } catch (RemoteException e) {
1263 }
1264 }
1265
1266 wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001267 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
1268 + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001269
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001270 // First, if this window is at the current index, then all
1271 // is well.
1272 if (wallpaper == w) {
1273 i--;
1274 w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
1275 continue;
1276 }
1277
1278 // The window didn't match... the current wallpaper window,
1279 // wherever it is, is in the wrong place, so make sure it is
1280 // not in the list.
1281 int oldIndex = localmWindows.indexOf(wallpaper);
1282 if (oldIndex >= 0) {
1283 localmWindows.remove(oldIndex);
1284 if (oldIndex < i) {
1285 i--;
1286 }
1287 }
1288
1289 // Now stick it in.
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001290 if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
1291 + " from " + oldIndex + " to " + i);
1292
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001293 localmWindows.add(i, wallpaper);
1294 changed = true;
1295 }
1296 }
1297
1298 return changed;
1299 }
1300
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001301 void setWallpaperAnimLayerAdjustmentLocked(int adj) {
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001302 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG,
1303 "Setting wallpaper layer adj to " + adj);
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001304 mWallpaperAnimLayerAdjustment = adj;
1305 int curTokenIndex = mWallpaperTokens.size();
1306 while (curTokenIndex > 0) {
1307 curTokenIndex--;
1308 WindowToken token = mWallpaperTokens.get(curTokenIndex);
1309 int curWallpaperIndex = token.windows.size();
1310 while (curWallpaperIndex > 0) {
1311 curWallpaperIndex--;
1312 WindowState wallpaper = token.windows.get(curWallpaperIndex);
1313 wallpaper.mAnimLayer = wallpaper.mLayer + adj;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001314 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
1315 + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
Dianne Hackborn759a39e2009-08-09 17:20:27 -07001316 }
1317 }
1318 }
1319
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001320 boolean updateWallpaperOffsetLocked(WindowState target,
1321 WindowState wallpaperWin, int dw, int dh) {
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001322 boolean changed = false;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001323 boolean rawChanged = false;
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001324 if (target.mWallpaperX >= 0) {
1325 int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
1326 int offset = availw > 0 ? -(int)(availw*target.mWallpaperX+.5f) : 0;
1327 changed = wallpaperWin.mXOffset != offset;
1328 if (changed) {
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001329 if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
1330 + wallpaperWin + " x: " + offset);
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001331 wallpaperWin.mXOffset = offset;
1332 }
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001333 if (wallpaperWin.mWallpaperX != target.mWallpaperX) {
1334 wallpaperWin.mWallpaperX = target.mWallpaperX;
1335 rawChanged = true;
1336 }
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001337 }
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001338
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001339 if (target.mWallpaperY >= 0) {
1340 int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
1341 int offset = availh > 0 ? -(int)(availh*target.mWallpaperY+.5f) : 0;
1342 if (wallpaperWin.mYOffset != offset) {
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001343 if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
1344 + wallpaperWin + " y: " + offset);
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001345 changed = true;
1346 wallpaperWin.mYOffset = offset;
1347 }
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001348 if (wallpaperWin.mWallpaperY != target.mWallpaperY) {
1349 wallpaperWin.mWallpaperY = target.mWallpaperY;
1350 rawChanged = true;
1351 }
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001352 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001353
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001354 if (rawChanged) {
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001355 try {
1356 wallpaperWin.mClient.dispatchWallpaperOffsets(
1357 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
1358 } catch (RemoteException e) {
1359 }
1360 }
1361
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001362 return changed;
1363 }
1364
1365 boolean updateWallpaperOffsetLocked() {
1366 final int dw = mDisplay.getWidth();
1367 final int dh = mDisplay.getHeight();
1368
1369 boolean changed = false;
1370
1371 WindowState target = mWallpaperTarget;
1372 if (target != null) {
1373 int curTokenIndex = mWallpaperTokens.size();
1374 while (curTokenIndex > 0) {
1375 curTokenIndex--;
1376 WindowToken token = mWallpaperTokens.get(curTokenIndex);
1377 int curWallpaperIndex = token.windows.size();
1378 while (curWallpaperIndex > 0) {
1379 curWallpaperIndex--;
1380 WindowState wallpaper = token.windows.get(curWallpaperIndex);
1381 if (updateWallpaperOffsetLocked(target, wallpaper, dw, dh)) {
1382 wallpaper.computeShownFrameLocked();
1383 changed = true;
1384 }
1385 }
1386 }
1387 }
1388
1389 return changed;
1390 }
1391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 public int addWindow(Session session, IWindow client,
1393 WindowManager.LayoutParams attrs, int viewVisibility,
1394 Rect outContentInsets) {
1395 int res = mPolicy.checkAddPermission(attrs);
1396 if (res != WindowManagerImpl.ADD_OKAY) {
1397 return res;
1398 }
Romain Guy06882f82009-06-10 13:36:04 -07001399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 boolean reportNewConfig = false;
1401 WindowState attachedWindow = null;
1402 WindowState win = null;
Romain Guy06882f82009-06-10 13:36:04 -07001403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 synchronized(mWindowMap) {
1405 // Instantiating a Display requires talking with the simulator,
1406 // so don't do it until we know the system is mostly up and
1407 // running.
1408 if (mDisplay == null) {
1409 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1410 mDisplay = wm.getDefaultDisplay();
1411 mQueue.setDisplay(mDisplay);
1412 reportNewConfig = true;
1413 }
Romain Guy06882f82009-06-10 13:36:04 -07001414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 if (mWindowMap.containsKey(client.asBinder())) {
1416 Log.w(TAG, "Window " + client + " is already added");
1417 return WindowManagerImpl.ADD_DUPLICATE_ADD;
1418 }
1419
1420 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
Romain Guy06882f82009-06-10 13:36:04 -07001421 attachedWindow = windowForClientLocked(null, attrs.token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 if (attachedWindow == null) {
1423 Log.w(TAG, "Attempted to add window with token that is not a window: "
1424 + attrs.token + ". Aborting.");
1425 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1426 }
1427 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
1428 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1429 Log.w(TAG, "Attempted to add window with token that is a sub-window: "
1430 + attrs.token + ". Aborting.");
1431 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1432 }
1433 }
1434
1435 boolean addToken = false;
1436 WindowToken token = mTokenMap.get(attrs.token);
1437 if (token == null) {
1438 if (attrs.type >= FIRST_APPLICATION_WINDOW
1439 && attrs.type <= LAST_APPLICATION_WINDOW) {
1440 Log.w(TAG, "Attempted to add application window with unknown token "
1441 + attrs.token + ". Aborting.");
1442 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1443 }
1444 if (attrs.type == TYPE_INPUT_METHOD) {
1445 Log.w(TAG, "Attempted to add input method window with unknown token "
1446 + attrs.token + ". Aborting.");
1447 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1448 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001449 if (attrs.type == TYPE_WALLPAPER) {
1450 Log.w(TAG, "Attempted to add wallpaper window with unknown token "
1451 + attrs.token + ". Aborting.");
1452 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 token = new WindowToken(attrs.token, -1, false);
1455 addToken = true;
1456 } else if (attrs.type >= FIRST_APPLICATION_WINDOW
1457 && attrs.type <= LAST_APPLICATION_WINDOW) {
1458 AppWindowToken atoken = token.appWindowToken;
1459 if (atoken == null) {
1460 Log.w(TAG, "Attempted to add window with non-application token "
1461 + token + ". Aborting.");
1462 return WindowManagerImpl.ADD_NOT_APP_TOKEN;
1463 } else if (atoken.removed) {
1464 Log.w(TAG, "Attempted to add window with exiting application token "
1465 + token + ". Aborting.");
1466 return WindowManagerImpl.ADD_APP_EXITING;
1467 }
1468 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
1469 // No need for this guy!
1470 if (localLOGV) Log.v(
1471 TAG, "**** NO NEED TO START: " + attrs.getTitle());
1472 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
1473 }
1474 } else if (attrs.type == TYPE_INPUT_METHOD) {
1475 if (token.windowType != TYPE_INPUT_METHOD) {
1476 Log.w(TAG, "Attempted to add input method window with bad token "
1477 + attrs.token + ". Aborting.");
1478 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1479 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001480 } else if (attrs.type == TYPE_WALLPAPER) {
1481 if (token.windowType != TYPE_WALLPAPER) {
1482 Log.w(TAG, "Attempted to add wallpaper window with bad token "
1483 + attrs.token + ". Aborting.");
1484 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 }
1487
1488 win = new WindowState(session, client, token,
1489 attachedWindow, attrs, viewVisibility);
1490 if (win.mDeathRecipient == null) {
1491 // Client has apparently died, so there is no reason to
1492 // continue.
1493 Log.w(TAG, "Adding window client " + client.asBinder()
1494 + " that is dead, aborting.");
1495 return WindowManagerImpl.ADD_APP_EXITING;
1496 }
1497
1498 mPolicy.adjustWindowParamsLw(win.mAttrs);
Romain Guy06882f82009-06-10 13:36:04 -07001499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 res = mPolicy.prepareAddWindowLw(win, attrs);
1501 if (res != WindowManagerImpl.ADD_OKAY) {
1502 return res;
1503 }
1504
1505 // From now on, no exceptions or errors allowed!
1506
1507 res = WindowManagerImpl.ADD_OKAY;
Romain Guy06882f82009-06-10 13:36:04 -07001508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 if (addToken) {
1512 mTokenMap.put(attrs.token, token);
1513 mTokenList.add(token);
1514 }
1515 win.attach();
1516 mWindowMap.put(client.asBinder(), win);
1517
1518 if (attrs.type == TYPE_APPLICATION_STARTING &&
1519 token.appWindowToken != null) {
1520 token.appWindowToken.startingWindow = win;
1521 }
1522
1523 boolean imMayMove = true;
Romain Guy06882f82009-06-10 13:36:04 -07001524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 if (attrs.type == TYPE_INPUT_METHOD) {
1526 mInputMethodWindow = win;
1527 addInputMethodWindowToListLocked(win);
1528 imMayMove = false;
1529 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
1530 mInputMethodDialogs.add(win);
1531 addWindowToListInOrderLocked(win, true);
1532 adjustInputMethodDialogsLocked();
1533 imMayMove = false;
1534 } else {
1535 addWindowToListInOrderLocked(win, true);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001536 if (attrs.type == TYPE_WALLPAPER ||
1537 (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
1538 adjustWallpaperWindowsLocked();
1539 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 }
Romain Guy06882f82009-06-10 13:36:04 -07001541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 win.mEnterAnimationPending = true;
Romain Guy06882f82009-06-10 13:36:04 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
Romain Guy06882f82009-06-10 13:36:04 -07001545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 if (mInTouchMode) {
1547 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
1548 }
1549 if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
1550 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
1551 }
Romain Guy06882f82009-06-10 13:36:04 -07001552
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001553 boolean focusChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (win.canReceiveKeys()) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001555 if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
1556 == true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 imMayMove = false;
1558 }
1559 }
Romain Guy06882f82009-06-10 13:36:04 -07001560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 if (imMayMove) {
Romain Guy06882f82009-06-10 13:36:04 -07001562 moveInputMethodWindowsIfNeededLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 }
Romain Guy06882f82009-06-10 13:36:04 -07001564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 assignLayersLocked();
1566 // Don't do layout here, the window must call
1567 // relayout to be displayed, so we'll do it there.
Romain Guy06882f82009-06-10 13:36:04 -07001568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 //dump();
1570
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001571 if (focusChanged) {
1572 if (mCurrentFocus != null) {
1573 mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
1574 }
1575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 if (localLOGV) Log.v(
1577 TAG, "New client " + client.asBinder()
1578 + ": window=" + win);
1579 }
1580
1581 // sendNewConfiguration() checks caller permissions so we must call it with
1582 // privilege. updateOrientationFromAppTokens() clears and resets the caller
1583 // identity anyway, so it's safe to just clear & restore around this whole
1584 // block.
1585 final long origId = Binder.clearCallingIdentity();
1586 if (reportNewConfig) {
1587 sendNewConfiguration();
1588 } else {
1589 // Update Orientation after adding a window, only if the window needs to be
1590 // displayed right away
1591 if (win.isVisibleOrAdding()) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001592 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 sendNewConfiguration();
1594 }
1595 }
1596 }
1597 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 return res;
1600 }
Romain Guy06882f82009-06-10 13:36:04 -07001601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 public void removeWindow(Session session, IWindow client) {
1603 synchronized(mWindowMap) {
1604 WindowState win = windowForClientLocked(session, client);
1605 if (win == null) {
1606 return;
1607 }
1608 removeWindowLocked(session, win);
1609 }
1610 }
Romain Guy06882f82009-06-10 13:36:04 -07001611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 public void removeWindowLocked(Session session, WindowState win) {
1613
1614 if (localLOGV || DEBUG_FOCUS) Log.v(
1615 TAG, "Remove " + win + " client="
1616 + Integer.toHexString(System.identityHashCode(
1617 win.mClient.asBinder()))
1618 + ", surface=" + win.mSurface);
1619
1620 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 if (DEBUG_APP_TRANSITIONS) Log.v(
1623 TAG, "Remove " + win + ": mSurface=" + win.mSurface
1624 + " mExiting=" + win.mExiting
1625 + " isAnimating=" + win.isAnimating()
1626 + " app-animation="
1627 + (win.mAppToken != null ? win.mAppToken.animation : null)
1628 + " inPendingTransaction="
1629 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
1630 + " mDisplayFrozen=" + mDisplayFrozen);
1631 // Visibility of the removed window. Will be used later to update orientation later on.
1632 boolean wasVisible = false;
1633 // First, see if we need to run an animation. If we do, we have
1634 // to hold off on removing the window until the animation is done.
1635 // If the display is frozen, just remove immediately, since the
1636 // animation wouldn't be seen.
1637 if (win.mSurface != null && !mDisplayFrozen) {
1638 // If we are not currently running the exit animation, we
1639 // need to see about starting one.
1640 if (wasVisible=win.isWinVisibleLw()) {
Romain Guy06882f82009-06-10 13:36:04 -07001641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1643 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1644 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1645 }
1646 // Try starting an animation.
1647 if (applyAnimationLocked(win, transit, false)) {
1648 win.mExiting = true;
1649 }
1650 }
1651 if (win.mExiting || win.isAnimating()) {
1652 // The exit animation is running... wait for it!
1653 //Log.i(TAG, "*** Running exit animation...");
1654 win.mExiting = true;
1655 win.mRemoveOnExit = true;
1656 mLayoutNeeded = true;
1657 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
1658 performLayoutAndPlaceSurfacesLocked();
1659 if (win.mAppToken != null) {
1660 win.mAppToken.updateReportedVisibilityLocked();
1661 }
1662 //dump();
1663 Binder.restoreCallingIdentity(origId);
1664 return;
1665 }
1666 }
1667
1668 removeWindowInnerLocked(session, win);
1669 // Removing a visible window will effect the computed orientation
1670 // So just update orientation if needed.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001671 if (wasVisible && computeForcedAppOrientationLocked()
1672 != mForcedAppOrientation) {
1673 mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 }
1675 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1676 Binder.restoreCallingIdentity(origId);
1677 }
Romain Guy06882f82009-06-10 13:36:04 -07001678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 private void removeWindowInnerLocked(Session session, WindowState win) {
1680 mKeyWaiter.releasePendingPointerLocked(win.mSession);
1681 mKeyWaiter.releasePendingTrackballLocked(win.mSession);
Romain Guy06882f82009-06-10 13:36:04 -07001682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 win.mRemoved = true;
Romain Guy06882f82009-06-10 13:36:04 -07001684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 if (mInputMethodTarget == win) {
1686 moveInputMethodWindowsIfNeededLocked(false);
1687 }
Romain Guy06882f82009-06-10 13:36:04 -07001688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 mPolicy.removeWindowLw(win);
1690 win.removeLocked();
1691
1692 mWindowMap.remove(win.mClient.asBinder());
1693 mWindows.remove(win);
1694
1695 if (mInputMethodWindow == win) {
1696 mInputMethodWindow = null;
1697 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
1698 mInputMethodDialogs.remove(win);
1699 }
Romain Guy06882f82009-06-10 13:36:04 -07001700
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001701 if (win.mAttrs.type == TYPE_WALLPAPER ||
1702 (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
1703 adjustWallpaperWindowsLocked();
1704 }
1705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 final WindowToken token = win.mToken;
1707 final AppWindowToken atoken = win.mAppToken;
1708 token.windows.remove(win);
1709 if (atoken != null) {
1710 atoken.allAppWindows.remove(win);
1711 }
1712 if (localLOGV) Log.v(
1713 TAG, "**** Removing window " + win + ": count="
1714 + token.windows.size());
1715 if (token.windows.size() == 0) {
1716 if (!token.explicit) {
1717 mTokenMap.remove(token.token);
1718 mTokenList.remove(token);
1719 } else if (atoken != null) {
1720 atoken.firstWindowDrawn = false;
1721 }
1722 }
1723
1724 if (atoken != null) {
1725 if (atoken.startingWindow == win) {
1726 atoken.startingWindow = null;
1727 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
1728 // If this is the last window and we had requested a starting
1729 // transition window, well there is no point now.
1730 atoken.startingData = null;
1731 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
1732 // If this is the last window except for a starting transition
1733 // window, we need to get rid of the starting transition.
1734 if (DEBUG_STARTING_WINDOW) {
1735 Log.v(TAG, "Schedule remove starting " + token
1736 + ": no more real windows");
1737 }
1738 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
1739 mH.sendMessage(m);
1740 }
1741 }
Romain Guy06882f82009-06-10 13:36:04 -07001742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 if (!mInLayout) {
1744 assignLayersLocked();
1745 mLayoutNeeded = true;
1746 performLayoutAndPlaceSurfacesLocked();
1747 if (win.mAppToken != null) {
1748 win.mAppToken.updateReportedVisibilityLocked();
1749 }
1750 }
1751 }
1752
1753 private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
1754 long origId = Binder.clearCallingIdentity();
1755 try {
1756 synchronized (mWindowMap) {
1757 WindowState w = windowForClientLocked(session, client);
1758 if ((w != null) && (w.mSurface != null)) {
1759 Surface.openTransaction();
1760 try {
1761 w.mSurface.setTransparentRegionHint(region);
1762 } finally {
1763 Surface.closeTransaction();
1764 }
1765 }
1766 }
1767 } finally {
1768 Binder.restoreCallingIdentity(origId);
1769 }
1770 }
1771
1772 void setInsetsWindow(Session session, IWindow client,
Romain Guy06882f82009-06-10 13:36:04 -07001773 int touchableInsets, Rect contentInsets,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 Rect visibleInsets) {
1775 long origId = Binder.clearCallingIdentity();
1776 try {
1777 synchronized (mWindowMap) {
1778 WindowState w = windowForClientLocked(session, client);
1779 if (w != null) {
1780 w.mGivenInsetsPending = false;
1781 w.mGivenContentInsets.set(contentInsets);
1782 w.mGivenVisibleInsets.set(visibleInsets);
1783 w.mTouchableInsets = touchableInsets;
1784 mLayoutNeeded = true;
1785 performLayoutAndPlaceSurfacesLocked();
1786 }
1787 }
1788 } finally {
1789 Binder.restoreCallingIdentity(origId);
1790 }
1791 }
Romain Guy06882f82009-06-10 13:36:04 -07001792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 public void getWindowDisplayFrame(Session session, IWindow client,
1794 Rect outDisplayFrame) {
1795 synchronized(mWindowMap) {
1796 WindowState win = windowForClientLocked(session, client);
1797 if (win == null) {
1798 outDisplayFrame.setEmpty();
1799 return;
1800 }
1801 outDisplayFrame.set(win.mDisplayFrame);
1802 }
1803 }
1804
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001805 public void setWindowWallpaperPositionLocked(WindowState window, float x, float y) {
1806 if (window.mWallpaperX != x || window.mWallpaperY != y) {
1807 window.mWallpaperX = x;
1808 window.mWallpaperY = y;
1809
1810 if (mWallpaperTarget == window) {
1811 if (updateWallpaperOffsetLocked()) {
1812 performLayoutAndPlaceSurfacesLocked();
1813 }
1814 }
1815 }
1816 }
1817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 public int relayoutWindow(Session session, IWindow client,
1819 WindowManager.LayoutParams attrs, int requestedWidth,
1820 int requestedHeight, int viewVisibility, boolean insetsPending,
1821 Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
1822 Surface outSurface) {
1823 boolean displayed = false;
1824 boolean inTouchMode;
1825 Configuration newConfig = null;
1826 long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 synchronized(mWindowMap) {
1829 WindowState win = windowForClientLocked(session, client);
1830 if (win == null) {
1831 return 0;
1832 }
1833 win.mRequestedWidth = requestedWidth;
1834 win.mRequestedHeight = requestedHeight;
1835
1836 if (attrs != null) {
1837 mPolicy.adjustWindowParamsLw(attrs);
1838 }
Romain Guy06882f82009-06-10 13:36:04 -07001839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 int attrChanges = 0;
1841 int flagChanges = 0;
1842 if (attrs != null) {
1843 flagChanges = win.mAttrs.flags ^= attrs.flags;
1844 attrChanges = win.mAttrs.copyFrom(attrs);
1845 }
1846
1847 if (localLOGV) Log.v(
1848 TAG, "Relayout given client " + client.asBinder()
1849 + " (" + win.mAttrs.getTitle() + ")");
1850
1851
1852 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
1853 win.mAlpha = attrs.alpha;
1854 }
1855
1856 final boolean scaledWindow =
1857 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
1858
1859 if (scaledWindow) {
1860 // requested{Width|Height} Surface's physical size
1861 // attrs.{width|height} Size on screen
1862 win.mHScale = (attrs.width != requestedWidth) ?
1863 (attrs.width / (float)requestedWidth) : 1.0f;
1864 win.mVScale = (attrs.height != requestedHeight) ?
1865 (attrs.height / (float)requestedHeight) : 1.0f;
1866 }
1867
1868 boolean imMayMove = (flagChanges&(
1869 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
1870 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07001871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 boolean focusMayChange = win.mViewVisibility != viewVisibility
1873 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
1874 || (!win.mRelayoutCalled);
Romain Guy06882f82009-06-10 13:36:04 -07001875
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001876 boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
1877 && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
1878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 win.mRelayoutCalled = true;
1880 final int oldVisibility = win.mViewVisibility;
1881 win.mViewVisibility = viewVisibility;
1882 if (viewVisibility == View.VISIBLE &&
1883 (win.mAppToken == null || !win.mAppToken.clientHidden)) {
1884 displayed = !win.isVisibleLw();
1885 if (win.mExiting) {
1886 win.mExiting = false;
1887 win.mAnimation = null;
1888 }
1889 if (win.mDestroying) {
1890 win.mDestroying = false;
1891 mDestroySurface.remove(win);
1892 }
1893 if (oldVisibility == View.GONE) {
1894 win.mEnterAnimationPending = true;
1895 }
1896 if (displayed && win.mSurface != null && !win.mDrawPending
1897 && !win.mCommitDrawPending && !mDisplayFrozen) {
1898 applyEnterAnimationLocked(win);
1899 }
1900 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
1901 // To change the format, we need to re-build the surface.
1902 win.destroySurfaceLocked();
1903 displayed = true;
1904 }
1905 try {
1906 Surface surface = win.createSurfaceLocked();
1907 if (surface != null) {
1908 outSurface.copyFrom(surface);
1909 } else {
1910 outSurface.clear();
1911 }
1912 } catch (Exception e) {
1913 Log.w(TAG, "Exception thrown when creating surface for client "
1914 + client + " (" + win.mAttrs.getTitle() + ")",
1915 e);
1916 Binder.restoreCallingIdentity(origId);
1917 return 0;
1918 }
1919 if (displayed) {
1920 focusMayChange = true;
1921 }
1922 if (win.mAttrs.type == TYPE_INPUT_METHOD
1923 && mInputMethodWindow == null) {
1924 mInputMethodWindow = win;
1925 imMayMove = true;
1926 }
1927 } else {
1928 win.mEnterAnimationPending = false;
1929 if (win.mSurface != null) {
1930 // If we are not currently running the exit animation, we
1931 // need to see about starting one.
1932 if (!win.mExiting) {
1933 // Try starting an animation; if there isn't one, we
1934 // can destroy the surface right away.
1935 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1936 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1937 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1938 }
1939 if (win.isWinVisibleLw() &&
1940 applyAnimationLocked(win, transit, false)) {
1941 win.mExiting = true;
1942 mKeyWaiter.finishedKey(session, client, true,
1943 KeyWaiter.RETURN_NOTHING);
1944 } else if (win.isAnimating()) {
1945 // Currently in a hide animation... turn this into
1946 // an exit.
1947 win.mExiting = true;
1948 } else {
1949 if (mInputMethodWindow == win) {
1950 mInputMethodWindow = null;
1951 }
1952 win.destroySurfaceLocked();
1953 }
1954 }
1955 }
1956 outSurface.clear();
1957 }
1958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 if (focusMayChange) {
1960 //System.out.println("Focus may change: " + win.mAttrs.getTitle());
1961 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 imMayMove = false;
1963 }
1964 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
1965 }
Romain Guy06882f82009-06-10 13:36:04 -07001966
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001967 // updateFocusedWindowLocked() already assigned layers so we only need to
1968 // reassign them at this point if the IM window state gets shuffled
1969 boolean assignLayers = false;
Romain Guy06882f82009-06-10 13:36:04 -07001970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 if (imMayMove) {
1972 if (moveInputMethodWindowsIfNeededLocked(false)) {
1973 assignLayers = true;
1974 }
1975 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001976 if (wallpaperMayMove) {
1977 if (adjustWallpaperWindowsLocked()) {
1978 assignLayers = true;
1979 }
1980 }
Romain Guy06882f82009-06-10 13:36:04 -07001981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 mLayoutNeeded = true;
1983 win.mGivenInsetsPending = insetsPending;
1984 if (assignLayers) {
1985 assignLayersLocked();
1986 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001987 newConfig = updateOrientationFromAppTokensLocked(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 performLayoutAndPlaceSurfacesLocked();
1989 if (win.mAppToken != null) {
1990 win.mAppToken.updateReportedVisibilityLocked();
1991 }
1992 outFrame.set(win.mFrame);
1993 outContentInsets.set(win.mContentInsets);
1994 outVisibleInsets.set(win.mVisibleInsets);
1995 if (localLOGV) Log.v(
1996 TAG, "Relayout given client " + client.asBinder()
Romain Guy06882f82009-06-10 13:36:04 -07001997 + ", requestedWidth=" + requestedWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 + ", requestedHeight=" + requestedHeight
1999 + ", viewVisibility=" + viewVisibility
2000 + "\nRelayout returning frame=" + outFrame
2001 + ", surface=" + outSurface);
2002
2003 if (localLOGV || DEBUG_FOCUS) Log.v(
2004 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
2005
2006 inTouchMode = mInTouchMode;
2007 }
2008
2009 if (newConfig != null) {
2010 sendNewConfiguration();
2011 }
Romain Guy06882f82009-06-10 13:36:04 -07002012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07002014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
2016 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
2017 }
2018
2019 public void finishDrawingWindow(Session session, IWindow client) {
2020 final long origId = Binder.clearCallingIdentity();
2021 synchronized(mWindowMap) {
2022 WindowState win = windowForClientLocked(session, client);
2023 if (win != null && win.finishDrawingLocked()) {
Dianne Hackborn759a39e2009-08-09 17:20:27 -07002024 if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
2025 adjustWallpaperWindowsLocked();
2026 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 mLayoutNeeded = true;
2028 performLayoutAndPlaceSurfacesLocked();
2029 }
2030 }
2031 Binder.restoreCallingIdentity(origId);
2032 }
2033
2034 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
2035 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
2036 + (lp != null ? lp.packageName : null)
2037 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
2038 if (lp != null && lp.windowAnimations != 0) {
2039 // If this is a system resource, don't try to load it from the
2040 // application resources. It is nice to avoid loading application
2041 // resources if we can.
2042 String packageName = lp.packageName != null ? lp.packageName : "android";
2043 int resId = lp.windowAnimations;
2044 if ((resId&0xFF000000) == 0x01000000) {
2045 packageName = "android";
2046 }
2047 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
2048 + packageName);
2049 return AttributeCache.instance().get(packageName, resId,
2050 com.android.internal.R.styleable.WindowAnimation);
2051 }
2052 return null;
2053 }
Romain Guy06882f82009-06-10 13:36:04 -07002054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 private void applyEnterAnimationLocked(WindowState win) {
2056 int transit = WindowManagerPolicy.TRANSIT_SHOW;
2057 if (win.mEnterAnimationPending) {
2058 win.mEnterAnimationPending = false;
2059 transit = WindowManagerPolicy.TRANSIT_ENTER;
2060 }
2061
2062 applyAnimationLocked(win, transit, true);
2063 }
2064
2065 private boolean applyAnimationLocked(WindowState win,
2066 int transit, boolean isEntrance) {
2067 if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
2068 // If we are trying to apply an animation, but already running
2069 // an animation of the same type, then just leave that one alone.
2070 return true;
2071 }
Romain Guy06882f82009-06-10 13:36:04 -07002072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 // Only apply an animation if the display isn't frozen. If it is
2074 // frozen, there is no reason to animate and it can cause strange
2075 // artifacts when we unfreeze the display if some different animation
2076 // is running.
2077 if (!mDisplayFrozen) {
2078 int anim = mPolicy.selectAnimationLw(win, transit);
2079 int attr = -1;
2080 Animation a = null;
2081 if (anim != 0) {
2082 a = AnimationUtils.loadAnimation(mContext, anim);
2083 } else {
2084 switch (transit) {
2085 case WindowManagerPolicy.TRANSIT_ENTER:
2086 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
2087 break;
2088 case WindowManagerPolicy.TRANSIT_EXIT:
2089 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
2090 break;
2091 case WindowManagerPolicy.TRANSIT_SHOW:
2092 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
2093 break;
2094 case WindowManagerPolicy.TRANSIT_HIDE:
2095 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
2096 break;
2097 }
2098 if (attr >= 0) {
2099 a = loadAnimation(win.mAttrs, attr);
2100 }
2101 }
2102 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
2103 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
2104 + " mAnimation=" + win.mAnimation
2105 + " isEntrance=" + isEntrance);
2106 if (a != null) {
2107 if (DEBUG_ANIM) {
2108 RuntimeException e = new RuntimeException();
2109 e.fillInStackTrace();
2110 Log.v(TAG, "Loaded animation " + a + " for " + win, e);
2111 }
2112 win.setAnimation(a);
2113 win.mAnimationIsEntrance = isEntrance;
2114 }
2115 } else {
2116 win.clearAnimation();
2117 }
2118
2119 return win.mAnimation != null;
2120 }
2121
2122 private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
2123 int anim = 0;
2124 Context context = mContext;
2125 if (animAttr >= 0) {
2126 AttributeCache.Entry ent = getCachedAnimations(lp);
2127 if (ent != null) {
2128 context = ent.context;
2129 anim = ent.array.getResourceId(animAttr, 0);
2130 }
2131 }
2132 if (anim != 0) {
2133 return AnimationUtils.loadAnimation(context, anim);
2134 }
2135 return null;
2136 }
Romain Guy06882f82009-06-10 13:36:04 -07002137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 private boolean applyAnimationLocked(AppWindowToken wtoken,
2139 WindowManager.LayoutParams lp, int transit, boolean enter) {
2140 // Only apply an animation if the display isn't frozen. If it is
2141 // frozen, there is no reason to animate and it can cause strange
2142 // artifacts when we unfreeze the display if some different animation
2143 // is running.
2144 if (!mDisplayFrozen) {
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07002145 Animation a;
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07002146 if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07002147 a = new FadeInOutAnimation(enter);
2148 if (DEBUG_ANIM) Log.v(TAG,
2149 "applying FadeInOutAnimation for a window in compatibility mode");
2150 } else {
2151 int animAttr = 0;
2152 switch (transit) {
2153 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
2154 animAttr = enter
2155 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
2156 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
2157 break;
2158 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
2159 animAttr = enter
2160 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
2161 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
2162 break;
2163 case WindowManagerPolicy.TRANSIT_TASK_OPEN:
2164 animAttr = enter
2165 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
2166 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
2167 break;
2168 case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
2169 animAttr = enter
2170 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
2171 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
2172 break;
2173 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
2174 animAttr = enter
2175 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
2176 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
2177 break;
2178 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
2179 animAttr = enter
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07002180 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07002181 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
2182 break;
2183 }
2184 a = loadAnimation(lp, animAttr);
2185 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
2186 + " anim=" + a
2187 + " animAttr=0x" + Integer.toHexString(animAttr)
2188 + " transit=" + transit);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 if (a != null) {
2191 if (DEBUG_ANIM) {
2192 RuntimeException e = new RuntimeException();
2193 e.fillInStackTrace();
2194 Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
2195 }
2196 wtoken.setAnimation(a);
2197 }
2198 } else {
2199 wtoken.clearAnimation();
2200 }
2201
2202 return wtoken.animation != null;
2203 }
2204
2205 // -------------------------------------------------------------
2206 // Application Window Tokens
2207 // -------------------------------------------------------------
2208
2209 public void validateAppTokens(List tokens) {
2210 int v = tokens.size()-1;
2211 int m = mAppTokens.size()-1;
2212 while (v >= 0 && m >= 0) {
2213 AppWindowToken wtoken = mAppTokens.get(m);
2214 if (wtoken.removed) {
2215 m--;
2216 continue;
2217 }
2218 if (tokens.get(v) != wtoken.token) {
2219 Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
2220 + " @ " + v + ", internal is " + wtoken.token + " @ " + m);
2221 }
2222 v--;
2223 m--;
2224 }
2225 while (v >= 0) {
2226 Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
2227 v--;
2228 }
2229 while (m >= 0) {
2230 AppWindowToken wtoken = mAppTokens.get(m);
2231 if (!wtoken.removed) {
2232 Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
2233 }
2234 m--;
2235 }
2236 }
2237
2238 boolean checkCallingPermission(String permission, String func) {
2239 // Quick check: if the calling permission is me, it's all okay.
2240 if (Binder.getCallingPid() == Process.myPid()) {
2241 return true;
2242 }
Romain Guy06882f82009-06-10 13:36:04 -07002243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 if (mContext.checkCallingPermission(permission)
2245 == PackageManager.PERMISSION_GRANTED) {
2246 return true;
2247 }
2248 String msg = "Permission Denial: " + func + " from pid="
2249 + Binder.getCallingPid()
2250 + ", uid=" + Binder.getCallingUid()
2251 + " requires " + permission;
2252 Log.w(TAG, msg);
2253 return false;
2254 }
Romain Guy06882f82009-06-10 13:36:04 -07002255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002256 AppWindowToken findAppWindowToken(IBinder token) {
2257 WindowToken wtoken = mTokenMap.get(token);
2258 if (wtoken == null) {
2259 return null;
2260 }
2261 return wtoken.appWindowToken;
2262 }
Romain Guy06882f82009-06-10 13:36:04 -07002263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 public void addWindowToken(IBinder token, int type) {
2265 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2266 "addWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002267 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002268 }
Romain Guy06882f82009-06-10 13:36:04 -07002269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 synchronized(mWindowMap) {
2271 WindowToken wtoken = mTokenMap.get(token);
2272 if (wtoken != null) {
2273 Log.w(TAG, "Attempted to add existing input method token: " + token);
2274 return;
2275 }
2276 wtoken = new WindowToken(token, type, true);
2277 mTokenMap.put(token, wtoken);
2278 mTokenList.add(wtoken);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002279 if (type == TYPE_WALLPAPER) {
2280 mWallpaperTokens.add(wtoken);
2281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002282 }
2283 }
Romain Guy06882f82009-06-10 13:36:04 -07002284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 public void removeWindowToken(IBinder token) {
2286 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2287 "removeWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002288 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 }
2290
2291 final long origId = Binder.clearCallingIdentity();
2292 synchronized(mWindowMap) {
2293 WindowToken wtoken = mTokenMap.remove(token);
2294 mTokenList.remove(wtoken);
2295 if (wtoken != null) {
2296 boolean delayed = false;
2297 if (!wtoken.hidden) {
2298 wtoken.hidden = true;
Romain Guy06882f82009-06-10 13:36:04 -07002299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 final int N = wtoken.windows.size();
2301 boolean changed = false;
Romain Guy06882f82009-06-10 13:36:04 -07002302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 for (int i=0; i<N; i++) {
2304 WindowState win = wtoken.windows.get(i);
2305
2306 if (win.isAnimating()) {
2307 delayed = true;
2308 }
Romain Guy06882f82009-06-10 13:36:04 -07002309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 if (win.isVisibleNow()) {
2311 applyAnimationLocked(win,
2312 WindowManagerPolicy.TRANSIT_EXIT, false);
2313 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2314 KeyWaiter.RETURN_NOTHING);
2315 changed = true;
2316 }
2317 }
2318
2319 if (changed) {
2320 mLayoutNeeded = true;
2321 performLayoutAndPlaceSurfacesLocked();
2322 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2323 }
Romain Guy06882f82009-06-10 13:36:04 -07002324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002325 if (delayed) {
2326 mExitingTokens.add(wtoken);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002327 } else if (wtoken.windowType == TYPE_WALLPAPER) {
2328 mWallpaperTokens.remove(wtoken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 }
2330 }
Romain Guy06882f82009-06-10 13:36:04 -07002331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002332 } else {
2333 Log.w(TAG, "Attempted to remove non-existing token: " + token);
2334 }
2335 }
2336 Binder.restoreCallingIdentity(origId);
2337 }
2338
2339 public void addAppToken(int addPos, IApplicationToken token,
2340 int groupId, int requestedOrientation, boolean fullscreen) {
2341 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2342 "addAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002343 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 }
Romain Guy06882f82009-06-10 13:36:04 -07002345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002346 synchronized(mWindowMap) {
2347 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2348 if (wtoken != null) {
2349 Log.w(TAG, "Attempted to add existing app token: " + token);
2350 return;
2351 }
2352 wtoken = new AppWindowToken(token);
2353 wtoken.groupId = groupId;
2354 wtoken.appFullscreen = fullscreen;
2355 wtoken.requestedOrientation = requestedOrientation;
2356 mAppTokens.add(addPos, wtoken);
Dave Bortcfe65242009-04-09 14:51:04 -07002357 if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 mTokenMap.put(token.asBinder(), wtoken);
2359 mTokenList.add(wtoken);
Romain Guy06882f82009-06-10 13:36:04 -07002360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 // Application tokens start out hidden.
2362 wtoken.hidden = true;
2363 wtoken.hiddenRequested = true;
Romain Guy06882f82009-06-10 13:36:04 -07002364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 //dump();
2366 }
2367 }
Romain Guy06882f82009-06-10 13:36:04 -07002368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002369 public void setAppGroupId(IBinder token, int groupId) {
2370 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2371 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002372 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002373 }
2374
2375 synchronized(mWindowMap) {
2376 AppWindowToken wtoken = findAppWindowToken(token);
2377 if (wtoken == null) {
2378 Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
2379 return;
2380 }
2381 wtoken.groupId = groupId;
2382 }
2383 }
Romain Guy06882f82009-06-10 13:36:04 -07002384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002385 public int getOrientationFromWindowsLocked() {
2386 int pos = mWindows.size() - 1;
2387 while (pos >= 0) {
2388 WindowState wtoken = (WindowState) mWindows.get(pos);
2389 pos--;
2390 if (wtoken.mAppToken != null) {
2391 // We hit an application window. so the orientation will be determined by the
2392 // app window. No point in continuing further.
2393 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2394 }
2395 if (!wtoken.isVisibleLw()) {
2396 continue;
2397 }
2398 int req = wtoken.mAttrs.screenOrientation;
2399 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
2400 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
2401 continue;
2402 } else {
2403 return req;
2404 }
2405 }
2406 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2407 }
Romain Guy06882f82009-06-10 13:36:04 -07002408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002409 public int getOrientationFromAppTokensLocked() {
2410 int pos = mAppTokens.size() - 1;
2411 int curGroup = 0;
2412 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Owen Lin3413b892009-05-01 17:12:32 -07002413 boolean findingBehind = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 boolean haveGroup = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002415 boolean lastFullscreen = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002416 while (pos >= 0) {
2417 AppWindowToken wtoken = mAppTokens.get(pos);
2418 pos--;
Owen Lin3413b892009-05-01 17:12:32 -07002419 // if we're about to tear down this window and not seek for
2420 // the behind activity, don't use it for orientation
2421 if (!findingBehind
2422 && (!wtoken.hidden && wtoken.hiddenRequested)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002423 continue;
2424 }
2425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002426 if (!haveGroup) {
2427 // We ignore any hidden applications on the top.
2428 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
2429 continue;
2430 }
2431 haveGroup = true;
2432 curGroup = wtoken.groupId;
2433 lastOrientation = wtoken.requestedOrientation;
2434 } else if (curGroup != wtoken.groupId) {
2435 // If we have hit a new application group, and the bottom
2436 // of the previous group didn't explicitly say to use
The Android Open Source Project4df24232009-03-05 14:34:35 -08002437 // the orientation behind it, and the last app was
2438 // full screen, then we'll stick with the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002439 // user's orientation.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002440 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
2441 && lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002442 return lastOrientation;
2443 }
2444 }
2445 int or = wtoken.requestedOrientation;
Owen Lin3413b892009-05-01 17:12:32 -07002446 // If this application is fullscreen, and didn't explicitly say
2447 // to use the orientation behind it, then just take whatever
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 // orientation it has and ignores whatever is under it.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002449 lastFullscreen = wtoken.appFullscreen;
Romain Guy06882f82009-06-10 13:36:04 -07002450 if (lastFullscreen
Owen Lin3413b892009-05-01 17:12:32 -07002451 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002452 return or;
2453 }
2454 // If this application has requested an explicit orientation,
2455 // then use it.
2456 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
2457 or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
2458 or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
2459 or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
2460 or == ActivityInfo.SCREEN_ORIENTATION_USER) {
2461 return or;
2462 }
Owen Lin3413b892009-05-01 17:12:32 -07002463 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002464 }
2465 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2466 }
Romain Guy06882f82009-06-10 13:36:04 -07002467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002468 public Configuration updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002469 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002470 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2471 "updateOrientationFromAppTokens()")) {
2472 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
2473 }
2474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 Configuration config;
2476 long ident = Binder.clearCallingIdentity();
Dianne Hackborncfaef692009-06-15 14:24:44 -07002477 config = updateOrientationFromAppTokensUnchecked(currentConfig,
2478 freezeThisOneIfNeeded);
2479 Binder.restoreCallingIdentity(ident);
2480 return config;
2481 }
2482
2483 Configuration updateOrientationFromAppTokensUnchecked(
2484 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
2485 Configuration config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486 synchronized(mWindowMap) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002487 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002488 }
2489 if (config != null) {
2490 mLayoutNeeded = true;
2491 performLayoutAndPlaceSurfacesLocked();
2492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 return config;
2494 }
Romain Guy06882f82009-06-10 13:36:04 -07002495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 /*
2497 * The orientation is computed from non-application windows first. If none of
2498 * the non-application windows specify orientation, the orientation is computed from
Romain Guy06882f82009-06-10 13:36:04 -07002499 * application tokens.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002500 * @see android.view.IWindowManager#updateOrientationFromAppTokens(
2501 * android.os.IBinder)
2502 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002503 Configuration updateOrientationFromAppTokensLocked(
The Android Open Source Project10592532009-03-18 17:39:46 -07002504 Configuration appConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002505 boolean changed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 long ident = Binder.clearCallingIdentity();
2507 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002508 int req = computeForcedAppOrientationLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 if (req != mForcedAppOrientation) {
2511 changed = true;
2512 mForcedAppOrientation = req;
2513 //send a message to Policy indicating orientation change to take
2514 //action like disabling/enabling sensors etc.,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002515 mPolicy.setCurrentOrientationLw(req);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 }
Romain Guy06882f82009-06-10 13:36:04 -07002517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 if (changed) {
2519 changed = setRotationUncheckedLocked(
Dianne Hackborn321ae682009-03-27 16:16:03 -07002520 WindowManagerPolicy.USE_LAST_ROTATION,
2521 mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002522 if (changed) {
2523 if (freezeThisOneIfNeeded != null) {
2524 AppWindowToken wtoken = findAppWindowToken(
2525 freezeThisOneIfNeeded);
2526 if (wtoken != null) {
2527 startAppFreezingScreenLocked(wtoken,
2528 ActivityInfo.CONFIG_ORIENTATION);
2529 }
2530 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07002531 return computeNewConfigurationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 }
2533 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002534
2535 // No obvious action we need to take, but if our current
2536 // state mismatches the activity maanager's, update it
2537 if (appConfig != null) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07002538 mTempConfiguration.setToDefaults();
2539 if (computeNewConfigurationLocked(mTempConfiguration)) {
2540 if (appConfig.diff(mTempConfiguration) != 0) {
2541 Log.i(TAG, "Config changed: " + mTempConfiguration);
2542 return new Configuration(mTempConfiguration);
2543 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002544 }
2545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 } finally {
2547 Binder.restoreCallingIdentity(ident);
2548 }
Romain Guy06882f82009-06-10 13:36:04 -07002549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 return null;
2551 }
Romain Guy06882f82009-06-10 13:36:04 -07002552
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002553 int computeForcedAppOrientationLocked() {
2554 int req = getOrientationFromWindowsLocked();
2555 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
2556 req = getOrientationFromAppTokensLocked();
2557 }
2558 return req;
2559 }
Romain Guy06882f82009-06-10 13:36:04 -07002560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
2562 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2563 "setAppOrientation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002564 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 }
Romain Guy06882f82009-06-10 13:36:04 -07002566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567 synchronized(mWindowMap) {
2568 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2569 if (wtoken == null) {
2570 Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
2571 return;
2572 }
Romain Guy06882f82009-06-10 13:36:04 -07002573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 wtoken.requestedOrientation = requestedOrientation;
2575 }
2576 }
Romain Guy06882f82009-06-10 13:36:04 -07002577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002578 public int getAppOrientation(IApplicationToken token) {
2579 synchronized(mWindowMap) {
2580 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2581 if (wtoken == null) {
2582 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2583 }
Romain Guy06882f82009-06-10 13:36:04 -07002584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 return wtoken.requestedOrientation;
2586 }
2587 }
Romain Guy06882f82009-06-10 13:36:04 -07002588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 public void setFocusedApp(IBinder token, boolean moveFocusNow) {
2590 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2591 "setFocusedApp()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002592 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002593 }
2594
2595 synchronized(mWindowMap) {
2596 boolean changed = false;
2597 if (token == null) {
2598 if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
2599 changed = mFocusedApp != null;
2600 mFocusedApp = null;
2601 mKeyWaiter.tickle();
2602 } else {
2603 AppWindowToken newFocus = findAppWindowToken(token);
2604 if (newFocus == null) {
2605 Log.w(TAG, "Attempted to set focus to non-existing app token: " + token);
2606 return;
2607 }
2608 changed = mFocusedApp != newFocus;
2609 mFocusedApp = newFocus;
2610 if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp);
2611 mKeyWaiter.tickle();
2612 }
2613
2614 if (moveFocusNow && changed) {
2615 final long origId = Binder.clearCallingIdentity();
2616 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2617 Binder.restoreCallingIdentity(origId);
2618 }
2619 }
2620 }
2621
2622 public void prepareAppTransition(int transit) {
2623 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2624 "prepareAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002625 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002626 }
Romain Guy06882f82009-06-10 13:36:04 -07002627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 synchronized(mWindowMap) {
2629 if (DEBUG_APP_TRANSITIONS) Log.v(
2630 TAG, "Prepare app transition: transit=" + transit
2631 + " mNextAppTransition=" + mNextAppTransition);
2632 if (!mDisplayFrozen) {
2633 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
2634 mNextAppTransition = transit;
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002635 } else if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
2636 && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
2637 // Opening a new task always supersedes a close for the anim.
2638 mNextAppTransition = transit;
2639 } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2640 && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
2641 // Opening a new activity always supersedes a close for the anim.
2642 mNextAppTransition = transit;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 }
2644 mAppTransitionReady = false;
2645 mAppTransitionTimeout = false;
2646 mStartingIconInTransition = false;
2647 mSkipAppTransitionAnimation = false;
2648 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2649 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
2650 5000);
2651 }
2652 }
2653 }
2654
2655 public int getPendingAppTransition() {
2656 return mNextAppTransition;
2657 }
Romain Guy06882f82009-06-10 13:36:04 -07002658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 public void executeAppTransition() {
2660 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2661 "executeAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002662 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 }
Romain Guy06882f82009-06-10 13:36:04 -07002664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002665 synchronized(mWindowMap) {
2666 if (DEBUG_APP_TRANSITIONS) Log.v(
2667 TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
2668 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2669 mAppTransitionReady = true;
2670 final long origId = Binder.clearCallingIdentity();
2671 performLayoutAndPlaceSurfacesLocked();
2672 Binder.restoreCallingIdentity(origId);
2673 }
2674 }
2675 }
2676
2677 public void setAppStartingWindow(IBinder token, String pkg,
2678 int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
2679 IBinder transferFrom, boolean createIfNeeded) {
2680 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2681 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002682 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 }
2684
2685 synchronized(mWindowMap) {
2686 if (DEBUG_STARTING_WINDOW) Log.v(
2687 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
2688 + " transferFrom=" + transferFrom);
Romain Guy06882f82009-06-10 13:36:04 -07002689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002690 AppWindowToken wtoken = findAppWindowToken(token);
2691 if (wtoken == null) {
2692 Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
2693 return;
2694 }
2695
2696 // If the display is frozen, we won't do anything until the
2697 // actual window is displayed so there is no reason to put in
2698 // the starting window.
2699 if (mDisplayFrozen) {
2700 return;
2701 }
Romain Guy06882f82009-06-10 13:36:04 -07002702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 if (wtoken.startingData != null) {
2704 return;
2705 }
Romain Guy06882f82009-06-10 13:36:04 -07002706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 if (transferFrom != null) {
2708 AppWindowToken ttoken = findAppWindowToken(transferFrom);
2709 if (ttoken != null) {
2710 WindowState startingWindow = ttoken.startingWindow;
2711 if (startingWindow != null) {
2712 if (mStartingIconInTransition) {
2713 // In this case, the starting icon has already
2714 // been displayed, so start letting windows get
2715 // shown immediately without any more transitions.
2716 mSkipAppTransitionAnimation = true;
2717 }
2718 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2719 "Moving existing starting from " + ttoken
2720 + " to " + wtoken);
2721 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07002722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002723 // Transfer the starting window over to the new
2724 // token.
2725 wtoken.startingData = ttoken.startingData;
2726 wtoken.startingView = ttoken.startingView;
2727 wtoken.startingWindow = startingWindow;
2728 ttoken.startingData = null;
2729 ttoken.startingView = null;
2730 ttoken.startingWindow = null;
2731 ttoken.startingMoved = true;
2732 startingWindow.mToken = wtoken;
Dianne Hackbornef49c572009-03-24 19:27:32 -07002733 startingWindow.mRootToken = wtoken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002734 startingWindow.mAppToken = wtoken;
2735 mWindows.remove(startingWindow);
2736 ttoken.windows.remove(startingWindow);
2737 ttoken.allAppWindows.remove(startingWindow);
2738 addWindowToListInOrderLocked(startingWindow, true);
2739 wtoken.allAppWindows.add(startingWindow);
Romain Guy06882f82009-06-10 13:36:04 -07002740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 // Propagate other interesting state between the
2742 // tokens. If the old token is displayed, we should
2743 // immediately force the new one to be displayed. If
2744 // it is animating, we need to move that animation to
2745 // the new one.
2746 if (ttoken.allDrawn) {
2747 wtoken.allDrawn = true;
2748 }
2749 if (ttoken.firstWindowDrawn) {
2750 wtoken.firstWindowDrawn = true;
2751 }
2752 if (!ttoken.hidden) {
2753 wtoken.hidden = false;
2754 wtoken.hiddenRequested = false;
2755 wtoken.willBeHidden = false;
2756 }
2757 if (wtoken.clientHidden != ttoken.clientHidden) {
2758 wtoken.clientHidden = ttoken.clientHidden;
2759 wtoken.sendAppVisibilityToClients();
2760 }
2761 if (ttoken.animation != null) {
2762 wtoken.animation = ttoken.animation;
2763 wtoken.animating = ttoken.animating;
2764 wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
2765 ttoken.animation = null;
2766 ttoken.animLayerAdjustment = 0;
2767 wtoken.updateLayers();
2768 ttoken.updateLayers();
2769 }
Romain Guy06882f82009-06-10 13:36:04 -07002770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002771 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002772 mLayoutNeeded = true;
2773 performLayoutAndPlaceSurfacesLocked();
2774 Binder.restoreCallingIdentity(origId);
2775 return;
2776 } else if (ttoken.startingData != null) {
2777 // The previous app was getting ready to show a
2778 // starting window, but hasn't yet done so. Steal it!
2779 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2780 "Moving pending starting from " + ttoken
2781 + " to " + wtoken);
2782 wtoken.startingData = ttoken.startingData;
2783 ttoken.startingData = null;
2784 ttoken.startingMoved = true;
2785 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2786 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2787 // want to process the message ASAP, before any other queued
2788 // messages.
2789 mH.sendMessageAtFrontOfQueue(m);
2790 return;
2791 }
2792 }
2793 }
2794
2795 // There is no existing starting window, and the caller doesn't
2796 // want us to create one, so that's it!
2797 if (!createIfNeeded) {
2798 return;
2799 }
Romain Guy06882f82009-06-10 13:36:04 -07002800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 mStartingIconInTransition = true;
2802 wtoken.startingData = new StartingData(
2803 pkg, theme, nonLocalizedLabel,
2804 labelRes, icon);
2805 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2806 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2807 // want to process the message ASAP, before any other queued
2808 // messages.
2809 mH.sendMessageAtFrontOfQueue(m);
2810 }
2811 }
2812
2813 public void setAppWillBeHidden(IBinder token) {
2814 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2815 "setAppWillBeHidden()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002816 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002817 }
2818
2819 AppWindowToken wtoken;
2820
2821 synchronized(mWindowMap) {
2822 wtoken = findAppWindowToken(token);
2823 if (wtoken == null) {
2824 Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
2825 return;
2826 }
2827 wtoken.willBeHidden = true;
2828 }
2829 }
Romain Guy06882f82009-06-10 13:36:04 -07002830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
2832 boolean visible, int transit, boolean performLayout) {
2833 boolean delayed = false;
2834
2835 if (wtoken.clientHidden == visible) {
2836 wtoken.clientHidden = !visible;
2837 wtoken.sendAppVisibilityToClients();
2838 }
Romain Guy06882f82009-06-10 13:36:04 -07002839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 wtoken.willBeHidden = false;
2841 if (wtoken.hidden == visible) {
2842 final int N = wtoken.allAppWindows.size();
2843 boolean changed = false;
2844 if (DEBUG_APP_TRANSITIONS) Log.v(
2845 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
2846 + " performLayout=" + performLayout);
Romain Guy06882f82009-06-10 13:36:04 -07002847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002848 boolean runningAppAnimation = false;
Romain Guy06882f82009-06-10 13:36:04 -07002849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 if (transit != WindowManagerPolicy.TRANSIT_NONE) {
2851 if (wtoken.animation == sDummyAnimation) {
2852 wtoken.animation = null;
2853 }
2854 applyAnimationLocked(wtoken, lp, transit, visible);
2855 changed = true;
2856 if (wtoken.animation != null) {
2857 delayed = runningAppAnimation = true;
2858 }
2859 }
Romain Guy06882f82009-06-10 13:36:04 -07002860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 for (int i=0; i<N; i++) {
2862 WindowState win = wtoken.allAppWindows.get(i);
2863 if (win == wtoken.startingWindow) {
2864 continue;
2865 }
2866
2867 if (win.isAnimating()) {
2868 delayed = true;
2869 }
Romain Guy06882f82009-06-10 13:36:04 -07002870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002871 //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
2872 //win.dump(" ");
2873 if (visible) {
2874 if (!win.isVisibleNow()) {
2875 if (!runningAppAnimation) {
2876 applyAnimationLocked(win,
2877 WindowManagerPolicy.TRANSIT_ENTER, true);
2878 }
2879 changed = true;
2880 }
2881 } else if (win.isVisibleNow()) {
2882 if (!runningAppAnimation) {
2883 applyAnimationLocked(win,
2884 WindowManagerPolicy.TRANSIT_EXIT, false);
2885 }
2886 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2887 KeyWaiter.RETURN_NOTHING);
2888 changed = true;
2889 }
2890 }
2891
2892 wtoken.hidden = wtoken.hiddenRequested = !visible;
2893 if (!visible) {
2894 unsetAppFreezingScreenLocked(wtoken, true, true);
2895 } else {
2896 // If we are being set visible, and the starting window is
2897 // not yet displayed, then make sure it doesn't get displayed.
2898 WindowState swin = wtoken.startingWindow;
2899 if (swin != null && (swin.mDrawPending
2900 || swin.mCommitDrawPending)) {
2901 swin.mPolicyVisibility = false;
2902 swin.mPolicyVisibilityAfterAnim = false;
2903 }
2904 }
Romain Guy06882f82009-06-10 13:36:04 -07002905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002906 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
2907 + ": hidden=" + wtoken.hidden + " hiddenRequested="
2908 + wtoken.hiddenRequested);
Romain Guy06882f82009-06-10 13:36:04 -07002909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910 if (changed && performLayout) {
2911 mLayoutNeeded = true;
2912 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 performLayoutAndPlaceSurfacesLocked();
2914 }
2915 }
2916
2917 if (wtoken.animation != null) {
2918 delayed = true;
2919 }
Romain Guy06882f82009-06-10 13:36:04 -07002920
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 return delayed;
2922 }
2923
2924 public void setAppVisibility(IBinder token, boolean visible) {
2925 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2926 "setAppVisibility()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002927 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002928 }
2929
2930 AppWindowToken wtoken;
2931
2932 synchronized(mWindowMap) {
2933 wtoken = findAppWindowToken(token);
2934 if (wtoken == null) {
2935 Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
2936 return;
2937 }
2938
2939 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
2940 RuntimeException e = new RuntimeException();
2941 e.fillInStackTrace();
2942 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
2943 + "): mNextAppTransition=" + mNextAppTransition
2944 + " hidden=" + wtoken.hidden
2945 + " hiddenRequested=" + wtoken.hiddenRequested, e);
2946 }
Romain Guy06882f82009-06-10 13:36:04 -07002947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 // If we are preparing an app transition, then delay changing
2949 // the visibility of this token until we execute that transition.
2950 if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2951 // Already in requested state, don't do anything more.
2952 if (wtoken.hiddenRequested != visible) {
2953 return;
2954 }
2955 wtoken.hiddenRequested = !visible;
Romain Guy06882f82009-06-10 13:36:04 -07002956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002957 if (DEBUG_APP_TRANSITIONS) Log.v(
2958 TAG, "Setting dummy animation on: " + wtoken);
2959 wtoken.setDummyAnimation();
2960 mOpeningApps.remove(wtoken);
2961 mClosingApps.remove(wtoken);
2962 wtoken.inPendingTransaction = true;
2963 if (visible) {
2964 mOpeningApps.add(wtoken);
2965 wtoken.allDrawn = false;
2966 wtoken.startingDisplayed = false;
2967 wtoken.startingMoved = false;
Romain Guy06882f82009-06-10 13:36:04 -07002968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 if (wtoken.clientHidden) {
2970 // In the case where we are making an app visible
2971 // but holding off for a transition, we still need
2972 // to tell the client to make its windows visible so
2973 // they get drawn. Otherwise, we will wait on
2974 // performing the transition until all windows have
2975 // been drawn, they never will be, and we are sad.
2976 wtoken.clientHidden = false;
2977 wtoken.sendAppVisibilityToClients();
2978 }
2979 } else {
2980 mClosingApps.add(wtoken);
2981 }
2982 return;
2983 }
Romain Guy06882f82009-06-10 13:36:04 -07002984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 final long origId = Binder.clearCallingIdentity();
2986 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
2987 wtoken.updateReportedVisibilityLocked();
2988 Binder.restoreCallingIdentity(origId);
2989 }
2990 }
2991
2992 void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
2993 boolean unfreezeSurfaceNow, boolean force) {
2994 if (wtoken.freezingScreen) {
2995 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
2996 + " force=" + force);
2997 final int N = wtoken.allAppWindows.size();
2998 boolean unfrozeWindows = false;
2999 for (int i=0; i<N; i++) {
3000 WindowState w = wtoken.allAppWindows.get(i);
3001 if (w.mAppFreezing) {
3002 w.mAppFreezing = false;
3003 if (w.mSurface != null && !w.mOrientationChanging) {
3004 w.mOrientationChanging = true;
3005 }
3006 unfrozeWindows = true;
3007 }
3008 }
3009 if (force || unfrozeWindows) {
3010 if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
3011 wtoken.freezingScreen = false;
3012 mAppsFreezingScreen--;
3013 }
3014 if (unfreezeSurfaceNow) {
3015 if (unfrozeWindows) {
3016 mLayoutNeeded = true;
3017 performLayoutAndPlaceSurfacesLocked();
3018 }
3019 if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
3020 stopFreezingDisplayLocked();
3021 }
3022 }
3023 }
3024 }
Romain Guy06882f82009-06-10 13:36:04 -07003025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003026 public void startAppFreezingScreenLocked(AppWindowToken wtoken,
3027 int configChanges) {
3028 if (DEBUG_ORIENTATION) {
3029 RuntimeException e = new RuntimeException();
3030 e.fillInStackTrace();
3031 Log.i(TAG, "Set freezing of " + wtoken.appToken
3032 + ": hidden=" + wtoken.hidden + " freezing="
3033 + wtoken.freezingScreen, e);
3034 }
3035 if (!wtoken.hiddenRequested) {
3036 if (!wtoken.freezingScreen) {
3037 wtoken.freezingScreen = true;
3038 mAppsFreezingScreen++;
3039 if (mAppsFreezingScreen == 1) {
3040 startFreezingDisplayLocked();
3041 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
3042 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
3043 5000);
3044 }
3045 }
3046 final int N = wtoken.allAppWindows.size();
3047 for (int i=0; i<N; i++) {
3048 WindowState w = wtoken.allAppWindows.get(i);
3049 w.mAppFreezing = true;
3050 }
3051 }
3052 }
Romain Guy06882f82009-06-10 13:36:04 -07003053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 public void startAppFreezingScreen(IBinder token, int configChanges) {
3055 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3056 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003057 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003058 }
3059
3060 synchronized(mWindowMap) {
3061 if (configChanges == 0 && !mDisplayFrozen) {
3062 if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
3063 return;
3064 }
Romain Guy06882f82009-06-10 13:36:04 -07003065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003066 AppWindowToken wtoken = findAppWindowToken(token);
3067 if (wtoken == null || wtoken.appToken == null) {
3068 Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
3069 return;
3070 }
3071 final long origId = Binder.clearCallingIdentity();
3072 startAppFreezingScreenLocked(wtoken, configChanges);
3073 Binder.restoreCallingIdentity(origId);
3074 }
3075 }
Romain Guy06882f82009-06-10 13:36:04 -07003076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077 public void stopAppFreezingScreen(IBinder token, boolean force) {
3078 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3079 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003080 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 }
3082
3083 synchronized(mWindowMap) {
3084 AppWindowToken wtoken = findAppWindowToken(token);
3085 if (wtoken == null || wtoken.appToken == null) {
3086 return;
3087 }
3088 final long origId = Binder.clearCallingIdentity();
3089 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
3090 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
3091 unsetAppFreezingScreenLocked(wtoken, true, force);
3092 Binder.restoreCallingIdentity(origId);
3093 }
3094 }
Romain Guy06882f82009-06-10 13:36:04 -07003095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003096 public void removeAppToken(IBinder token) {
3097 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3098 "removeAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003099 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 }
3101
3102 AppWindowToken wtoken = null;
3103 AppWindowToken startingToken = null;
3104 boolean delayed = false;
3105
3106 final long origId = Binder.clearCallingIdentity();
3107 synchronized(mWindowMap) {
3108 WindowToken basewtoken = mTokenMap.remove(token);
3109 mTokenList.remove(basewtoken);
3110 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
3111 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
3112 delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
3113 wtoken.inPendingTransaction = false;
3114 mOpeningApps.remove(wtoken);
3115 if (mClosingApps.contains(wtoken)) {
3116 delayed = true;
3117 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
3118 mClosingApps.add(wtoken);
3119 delayed = true;
3120 }
3121 if (DEBUG_APP_TRANSITIONS) Log.v(
3122 TAG, "Removing app " + wtoken + " delayed=" + delayed
3123 + " animation=" + wtoken.animation
3124 + " animating=" + wtoken.animating);
3125 if (delayed) {
3126 // set the token aside because it has an active animation to be finished
3127 mExitingAppTokens.add(wtoken);
3128 }
3129 mAppTokens.remove(wtoken);
3130 wtoken.removed = true;
3131 if (wtoken.startingData != null) {
3132 startingToken = wtoken;
3133 }
3134 unsetAppFreezingScreenLocked(wtoken, true, true);
3135 if (mFocusedApp == wtoken) {
3136 if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
3137 mFocusedApp = null;
3138 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
3139 mKeyWaiter.tickle();
3140 }
3141 } else {
3142 Log.w(TAG, "Attempted to remove non-existing app token: " + token);
3143 }
Romain Guy06882f82009-06-10 13:36:04 -07003144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 if (!delayed && wtoken != null) {
3146 wtoken.updateReportedVisibilityLocked();
3147 }
3148 }
3149 Binder.restoreCallingIdentity(origId);
3150
3151 if (startingToken != null) {
3152 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
3153 + startingToken + ": app token removed");
3154 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
3155 mH.sendMessage(m);
3156 }
3157 }
3158
3159 private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
3160 final int NW = token.windows.size();
3161 for (int i=0; i<NW; i++) {
3162 WindowState win = token.windows.get(i);
3163 mWindows.remove(win);
3164 int j = win.mChildWindows.size();
3165 while (j > 0) {
3166 j--;
3167 mWindows.remove(win.mChildWindows.get(j));
3168 }
3169 }
3170 return NW > 0;
3171 }
3172
3173 void dumpAppTokensLocked() {
3174 for (int i=mAppTokens.size()-1; i>=0; i--) {
3175 Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
3176 }
3177 }
Romain Guy06882f82009-06-10 13:36:04 -07003178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 void dumpWindowsLocked() {
3180 for (int i=mWindows.size()-1; i>=0; i--) {
3181 Log.v(TAG, " #" + i + ": " + mWindows.get(i));
3182 }
3183 }
Romain Guy06882f82009-06-10 13:36:04 -07003184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 private int findWindowOffsetLocked(int tokenPos) {
3186 final int NW = mWindows.size();
3187
3188 if (tokenPos >= mAppTokens.size()) {
3189 int i = NW;
3190 while (i > 0) {
3191 i--;
3192 WindowState win = (WindowState)mWindows.get(i);
3193 if (win.getAppToken() != null) {
3194 return i+1;
3195 }
3196 }
3197 }
3198
3199 while (tokenPos > 0) {
3200 // Find the first app token below the new position that has
3201 // a window displayed.
3202 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
3203 if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
3204 + tokenPos + " -- " + wtoken.token);
3205 int i = wtoken.windows.size();
3206 while (i > 0) {
3207 i--;
3208 WindowState win = wtoken.windows.get(i);
3209 int j = win.mChildWindows.size();
3210 while (j > 0) {
3211 j--;
3212 WindowState cwin = (WindowState)win.mChildWindows.get(j);
3213 if (cwin.mSubLayer >= 0 ) {
3214 for (int pos=NW-1; pos>=0; pos--) {
3215 if (mWindows.get(pos) == cwin) {
3216 if (DEBUG_REORDER) Log.v(TAG,
3217 "Found child win @" + (pos+1));
3218 return pos+1;
3219 }
3220 }
3221 }
3222 }
3223 for (int pos=NW-1; pos>=0; pos--) {
3224 if (mWindows.get(pos) == win) {
3225 if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
3226 return pos+1;
3227 }
3228 }
3229 }
3230 tokenPos--;
3231 }
3232
3233 return 0;
3234 }
3235
3236 private final int reAddWindowLocked(int index, WindowState win) {
3237 final int NCW = win.mChildWindows.size();
3238 boolean added = false;
3239 for (int j=0; j<NCW; j++) {
3240 WindowState cwin = (WindowState)win.mChildWindows.get(j);
3241 if (!added && cwin.mSubLayer >= 0) {
3242 mWindows.add(index, win);
3243 index++;
3244 added = true;
3245 }
3246 mWindows.add(index, cwin);
3247 index++;
3248 }
3249 if (!added) {
3250 mWindows.add(index, win);
3251 index++;
3252 }
3253 return index;
3254 }
Romain Guy06882f82009-06-10 13:36:04 -07003255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 private final int reAddAppWindowsLocked(int index, WindowToken token) {
3257 final int NW = token.windows.size();
3258 for (int i=0; i<NW; i++) {
3259 index = reAddWindowLocked(index, token.windows.get(i));
3260 }
3261 return index;
3262 }
3263
3264 public void moveAppToken(int index, IBinder token) {
3265 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3266 "moveAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003267 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003268 }
3269
3270 synchronized(mWindowMap) {
3271 if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
3272 if (DEBUG_REORDER) dumpAppTokensLocked();
3273 final AppWindowToken wtoken = findAppWindowToken(token);
3274 if (wtoken == null || !mAppTokens.remove(wtoken)) {
3275 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
3276 + token + " (" + wtoken + ")");
3277 return;
3278 }
3279 mAppTokens.add(index, wtoken);
3280 if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
3281 if (DEBUG_REORDER) dumpAppTokensLocked();
Romain Guy06882f82009-06-10 13:36:04 -07003282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 final long origId = Binder.clearCallingIdentity();
3284 if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
3285 if (DEBUG_REORDER) dumpWindowsLocked();
3286 if (tmpRemoveAppWindowsLocked(wtoken)) {
3287 if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:");
3288 if (DEBUG_REORDER) dumpWindowsLocked();
3289 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
3290 if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
3291 if (DEBUG_REORDER) dumpWindowsLocked();
3292 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 mLayoutNeeded = true;
3294 performLayoutAndPlaceSurfacesLocked();
3295 }
3296 Binder.restoreCallingIdentity(origId);
3297 }
3298 }
3299
3300 private void removeAppTokensLocked(List<IBinder> tokens) {
3301 // XXX This should be done more efficiently!
3302 // (take advantage of the fact that both lists should be
3303 // ordered in the same way.)
3304 int N = tokens.size();
3305 for (int i=0; i<N; i++) {
3306 IBinder token = tokens.get(i);
3307 final AppWindowToken wtoken = findAppWindowToken(token);
3308 if (!mAppTokens.remove(wtoken)) {
3309 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
3310 + token + " (" + wtoken + ")");
3311 i--;
3312 N--;
3313 }
3314 }
3315 }
3316
3317 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
3318 // First remove all of the windows from the list.
3319 final int N = tokens.size();
3320 int i;
3321 for (i=0; i<N; i++) {
3322 WindowToken token = mTokenMap.get(tokens.get(i));
3323 if (token != null) {
3324 tmpRemoveAppWindowsLocked(token);
3325 }
3326 }
3327
3328 // Where to start adding?
3329 int pos = findWindowOffsetLocked(tokenPos);
3330
3331 // And now add them back at the correct place.
3332 for (i=0; i<N; i++) {
3333 WindowToken token = mTokenMap.get(tokens.get(i));
3334 if (token != null) {
3335 pos = reAddAppWindowsLocked(pos, token);
3336 }
3337 }
3338
3339 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 mLayoutNeeded = true;
3341 performLayoutAndPlaceSurfacesLocked();
3342
3343 //dump();
3344 }
3345
3346 public void moveAppTokensToTop(List<IBinder> tokens) {
3347 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3348 "moveAppTokensToTop()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003349 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
3351
3352 final long origId = Binder.clearCallingIdentity();
3353 synchronized(mWindowMap) {
3354 removeAppTokensLocked(tokens);
3355 final int N = tokens.size();
3356 for (int i=0; i<N; i++) {
3357 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3358 if (wt != null) {
3359 mAppTokens.add(wt);
3360 }
3361 }
3362 moveAppWindowsLocked(tokens, mAppTokens.size());
3363 }
3364 Binder.restoreCallingIdentity(origId);
3365 }
3366
3367 public void moveAppTokensToBottom(List<IBinder> tokens) {
3368 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3369 "moveAppTokensToBottom()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003370 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371 }
3372
3373 final long origId = Binder.clearCallingIdentity();
3374 synchronized(mWindowMap) {
3375 removeAppTokensLocked(tokens);
3376 final int N = tokens.size();
3377 int pos = 0;
3378 for (int i=0; i<N; i++) {
3379 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3380 if (wt != null) {
3381 mAppTokens.add(pos, wt);
3382 pos++;
3383 }
3384 }
3385 moveAppWindowsLocked(tokens, 0);
3386 }
3387 Binder.restoreCallingIdentity(origId);
3388 }
3389
3390 // -------------------------------------------------------------
3391 // Misc IWindowSession methods
3392 // -------------------------------------------------------------
Romain Guy06882f82009-06-10 13:36:04 -07003393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 public void disableKeyguard(IBinder token, String tag) {
3395 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3396 != PackageManager.PERMISSION_GRANTED) {
3397 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3398 }
3399 mKeyguardDisabled.acquire(token, tag);
3400 }
3401
3402 public void reenableKeyguard(IBinder token) {
3403 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3404 != PackageManager.PERMISSION_GRANTED) {
3405 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3406 }
3407 synchronized (mKeyguardDisabled) {
3408 mKeyguardDisabled.release(token);
3409
3410 if (!mKeyguardDisabled.isAcquired()) {
3411 // if we are the last one to reenable the keyguard wait until
3412 // we have actaully finished reenabling until returning
3413 mWaitingUntilKeyguardReenabled = true;
3414 while (mWaitingUntilKeyguardReenabled) {
3415 try {
3416 mKeyguardDisabled.wait();
3417 } catch (InterruptedException e) {
3418 Thread.currentThread().interrupt();
3419 }
3420 }
3421 }
3422 }
3423 }
3424
3425 /**
3426 * @see android.app.KeyguardManager#exitKeyguardSecurely
3427 */
3428 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
3429 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3430 != PackageManager.PERMISSION_GRANTED) {
3431 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3432 }
3433 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
3434 public void onKeyguardExitResult(boolean success) {
3435 try {
3436 callback.onKeyguardExitResult(success);
3437 } catch (RemoteException e) {
3438 // Client has died, we don't care.
3439 }
3440 }
3441 });
3442 }
3443
3444 public boolean inKeyguardRestrictedInputMode() {
3445 return mPolicy.inKeyguardRestrictedKeyInputMode();
3446 }
Romain Guy06882f82009-06-10 13:36:04 -07003447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 static float fixScale(float scale) {
3449 if (scale < 0) scale = 0;
3450 else if (scale > 20) scale = 20;
3451 return Math.abs(scale);
3452 }
Romain Guy06882f82009-06-10 13:36:04 -07003453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003454 public void setAnimationScale(int which, float scale) {
3455 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3456 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003457 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 }
3459
3460 if (scale < 0) scale = 0;
3461 else if (scale > 20) scale = 20;
3462 scale = Math.abs(scale);
3463 switch (which) {
3464 case 0: mWindowAnimationScale = fixScale(scale); break;
3465 case 1: mTransitionAnimationScale = fixScale(scale); break;
3466 }
Romain Guy06882f82009-06-10 13:36:04 -07003467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468 // Persist setting
3469 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3470 }
Romain Guy06882f82009-06-10 13:36:04 -07003471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 public void setAnimationScales(float[] scales) {
3473 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3474 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003475 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 }
3477
3478 if (scales != null) {
3479 if (scales.length >= 1) {
3480 mWindowAnimationScale = fixScale(scales[0]);
3481 }
3482 if (scales.length >= 2) {
3483 mTransitionAnimationScale = fixScale(scales[1]);
3484 }
3485 }
Romain Guy06882f82009-06-10 13:36:04 -07003486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 // Persist setting
3488 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3489 }
Romain Guy06882f82009-06-10 13:36:04 -07003490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003491 public float getAnimationScale(int which) {
3492 switch (which) {
3493 case 0: return mWindowAnimationScale;
3494 case 1: return mTransitionAnimationScale;
3495 }
3496 return 0;
3497 }
Romain Guy06882f82009-06-10 13:36:04 -07003498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 public float[] getAnimationScales() {
3500 return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
3501 }
Romain Guy06882f82009-06-10 13:36:04 -07003502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003503 public int getSwitchState(int sw) {
3504 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3505 "getSwitchState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003506 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 }
3508 return KeyInputQueue.getSwitchState(sw);
3509 }
Romain Guy06882f82009-06-10 13:36:04 -07003510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511 public int getSwitchStateForDevice(int devid, int sw) {
3512 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3513 "getSwitchStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003514 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 }
3516 return KeyInputQueue.getSwitchState(devid, sw);
3517 }
Romain Guy06882f82009-06-10 13:36:04 -07003518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 public int getScancodeState(int sw) {
3520 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3521 "getScancodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003522 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 }
3524 return KeyInputQueue.getScancodeState(sw);
3525 }
Romain Guy06882f82009-06-10 13:36:04 -07003526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 public int getScancodeStateForDevice(int devid, int sw) {
3528 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3529 "getScancodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003530 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 }
3532 return KeyInputQueue.getScancodeState(devid, sw);
3533 }
Romain Guy06882f82009-06-10 13:36:04 -07003534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 public int getKeycodeState(int sw) {
3536 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3537 "getKeycodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003538 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 }
3540 return KeyInputQueue.getKeycodeState(sw);
3541 }
Romain Guy06882f82009-06-10 13:36:04 -07003542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 public int getKeycodeStateForDevice(int devid, int sw) {
3544 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3545 "getKeycodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003546 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 }
3548 return KeyInputQueue.getKeycodeState(devid, sw);
3549 }
Romain Guy06882f82009-06-10 13:36:04 -07003550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
3552 return KeyInputQueue.hasKeys(keycodes, keyExists);
3553 }
Romain Guy06882f82009-06-10 13:36:04 -07003554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 public void enableScreenAfterBoot() {
3556 synchronized(mWindowMap) {
3557 if (mSystemBooted) {
3558 return;
3559 }
3560 mSystemBooted = true;
3561 }
Romain Guy06882f82009-06-10 13:36:04 -07003562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003563 performEnableScreen();
3564 }
Romain Guy06882f82009-06-10 13:36:04 -07003565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 public void enableScreenIfNeededLocked() {
3567 if (mDisplayEnabled) {
3568 return;
3569 }
3570 if (!mSystemBooted) {
3571 return;
3572 }
3573 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
3574 }
Romain Guy06882f82009-06-10 13:36:04 -07003575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 public void performEnableScreen() {
3577 synchronized(mWindowMap) {
3578 if (mDisplayEnabled) {
3579 return;
3580 }
3581 if (!mSystemBooted) {
3582 return;
3583 }
Romain Guy06882f82009-06-10 13:36:04 -07003584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 // Don't enable the screen until all existing windows
3586 // have been drawn.
3587 final int N = mWindows.size();
3588 for (int i=0; i<N; i++) {
3589 WindowState w = (WindowState)mWindows.get(i);
3590 if (w.isVisibleLw() && !w.isDisplayedLw()) {
3591 return;
3592 }
3593 }
Romain Guy06882f82009-06-10 13:36:04 -07003594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003595 mDisplayEnabled = true;
3596 if (false) {
3597 Log.i(TAG, "ENABLING SCREEN!");
3598 StringWriter sw = new StringWriter();
3599 PrintWriter pw = new PrintWriter(sw);
3600 this.dump(null, pw, null);
3601 Log.i(TAG, sw.toString());
3602 }
3603 try {
3604 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
3605 if (surfaceFlinger != null) {
3606 //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
3607 Parcel data = Parcel.obtain();
3608 data.writeInterfaceToken("android.ui.ISurfaceComposer");
3609 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
3610 data, null, 0);
3611 data.recycle();
3612 }
3613 } catch (RemoteException ex) {
3614 Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
3615 }
3616 }
Romain Guy06882f82009-06-10 13:36:04 -07003617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003618 mPolicy.enableScreenAfterBoot();
Romain Guy06882f82009-06-10 13:36:04 -07003619
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003620 // Make sure the last requested orientation has been applied.
Dianne Hackborn321ae682009-03-27 16:16:03 -07003621 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
3622 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 }
Romain Guy06882f82009-06-10 13:36:04 -07003624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 public void setInTouchMode(boolean mode) {
3626 synchronized(mWindowMap) {
3627 mInTouchMode = mode;
3628 }
3629 }
3630
Romain Guy06882f82009-06-10 13:36:04 -07003631 public void setRotation(int rotation,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003632 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003633 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003634 "setRotation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003635 throw new SecurityException("Requires SET_ORIENTATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003636 }
3637
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003638 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 }
Romain Guy06882f82009-06-10 13:36:04 -07003640
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003641 public void setRotationUnchecked(int rotation,
3642 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003643 if(DEBUG_ORIENTATION) Log.v(TAG,
3644 "alwaysSendConfiguration set to "+alwaysSendConfiguration);
Romain Guy06882f82009-06-10 13:36:04 -07003645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 long origId = Binder.clearCallingIdentity();
3647 boolean changed;
3648 synchronized(mWindowMap) {
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003649 changed = setRotationUncheckedLocked(rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 }
Romain Guy06882f82009-06-10 13:36:04 -07003651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003652 if (changed) {
3653 sendNewConfiguration();
3654 synchronized(mWindowMap) {
3655 mLayoutNeeded = true;
3656 performLayoutAndPlaceSurfacesLocked();
3657 }
3658 } else if (alwaysSendConfiguration) {
3659 //update configuration ignoring orientation change
3660 sendNewConfiguration();
3661 }
Romain Guy06882f82009-06-10 13:36:04 -07003662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 Binder.restoreCallingIdentity(origId);
3664 }
Romain Guy06882f82009-06-10 13:36:04 -07003665
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003666 public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 boolean changed;
3668 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
3669 rotation = mRequestedRotation;
3670 } else {
3671 mRequestedRotation = rotation;
Dianne Hackborn321ae682009-03-27 16:16:03 -07003672 mLastRotationFlags = animFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003673 }
3674 if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07003675 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 mRotation, mDisplayEnabled);
3677 if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
3678 changed = mDisplayEnabled && mRotation != rotation;
Romain Guy06882f82009-06-10 13:36:04 -07003679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 if (changed) {
Romain Guy06882f82009-06-10 13:36:04 -07003681 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682 "Rotation changed to " + rotation
3683 + " from " + mRotation
3684 + " (forceApp=" + mForcedAppOrientation
3685 + ", req=" + mRequestedRotation + ")");
3686 mRotation = rotation;
3687 mWindowsFreezingScreen = true;
3688 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
3689 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
3690 2000);
3691 startFreezingDisplayLocked();
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003692 Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003693 mQueue.setOrientation(rotation);
3694 if (mDisplayEnabled) {
Dianne Hackborn321ae682009-03-27 16:16:03 -07003695 Surface.setOrientation(0, rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003696 }
3697 for (int i=mWindows.size()-1; i>=0; i--) {
3698 WindowState w = (WindowState)mWindows.get(i);
3699 if (w.mSurface != null) {
3700 w.mOrientationChanging = true;
3701 }
3702 }
3703 for (int i=mRotationWatchers.size()-1; i>=0; i--) {
3704 try {
3705 mRotationWatchers.get(i).onRotationChanged(rotation);
3706 } catch (RemoteException e) {
3707 }
3708 }
3709 } //end if changed
Romain Guy06882f82009-06-10 13:36:04 -07003710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 return changed;
3712 }
Romain Guy06882f82009-06-10 13:36:04 -07003713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003714 public int getRotation() {
3715 return mRotation;
3716 }
3717
3718 public int watchRotation(IRotationWatcher watcher) {
3719 final IBinder watcherBinder = watcher.asBinder();
3720 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
3721 public void binderDied() {
3722 synchronized (mWindowMap) {
3723 for (int i=0; i<mRotationWatchers.size(); i++) {
3724 if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07003725 IRotationWatcher removed = mRotationWatchers.remove(i);
3726 if (removed != null) {
3727 removed.asBinder().unlinkToDeath(this, 0);
3728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003729 i--;
3730 }
3731 }
3732 }
3733 }
3734 };
Romain Guy06882f82009-06-10 13:36:04 -07003735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003736 synchronized (mWindowMap) {
3737 try {
3738 watcher.asBinder().linkToDeath(dr, 0);
3739 mRotationWatchers.add(watcher);
3740 } catch (RemoteException e) {
3741 // Client died, no cleanup needed.
3742 }
Romain Guy06882f82009-06-10 13:36:04 -07003743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003744 return mRotation;
3745 }
3746 }
3747
3748 /**
3749 * Starts the view server on the specified port.
3750 *
3751 * @param port The port to listener to.
3752 *
3753 * @return True if the server was successfully started, false otherwise.
3754 *
3755 * @see com.android.server.ViewServer
3756 * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
3757 */
3758 public boolean startViewServer(int port) {
Romain Guy06882f82009-06-10 13:36:04 -07003759 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003760 return false;
3761 }
3762
3763 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
3764 return false;
3765 }
3766
3767 if (port < 1024) {
3768 return false;
3769 }
3770
3771 if (mViewServer != null) {
3772 if (!mViewServer.isRunning()) {
3773 try {
3774 return mViewServer.start();
3775 } catch (IOException e) {
Romain Guy06882f82009-06-10 13:36:04 -07003776 Log.w(TAG, "View server did not start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 }
3778 }
3779 return false;
3780 }
3781
3782 try {
3783 mViewServer = new ViewServer(this, port);
3784 return mViewServer.start();
3785 } catch (IOException e) {
3786 Log.w(TAG, "View server did not start");
3787 }
3788 return false;
3789 }
3790
Romain Guy06882f82009-06-10 13:36:04 -07003791 private boolean isSystemSecure() {
3792 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
3793 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
3794 }
3795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 /**
3797 * Stops the view server if it exists.
3798 *
3799 * @return True if the server stopped, false if it wasn't started or
3800 * couldn't be stopped.
3801 *
3802 * @see com.android.server.ViewServer
3803 */
3804 public boolean stopViewServer() {
Romain Guy06882f82009-06-10 13:36:04 -07003805 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003806 return false;
3807 }
3808
3809 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
3810 return false;
3811 }
3812
3813 if (mViewServer != null) {
3814 return mViewServer.stop();
3815 }
3816 return false;
3817 }
3818
3819 /**
3820 * Indicates whether the view server is running.
3821 *
3822 * @return True if the server is running, false otherwise.
3823 *
3824 * @see com.android.server.ViewServer
3825 */
3826 public boolean isViewServerRunning() {
Romain Guy06882f82009-06-10 13:36:04 -07003827 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 return false;
3829 }
3830
3831 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
3832 return false;
3833 }
3834
3835 return mViewServer != null && mViewServer.isRunning();
3836 }
3837
3838 /**
3839 * Lists all availble windows in the system. The listing is written in the
3840 * specified Socket's output stream with the following syntax:
3841 * windowHashCodeInHexadecimal windowName
3842 * Each line of the ouput represents a different window.
3843 *
3844 * @param client The remote client to send the listing to.
3845 * @return False if an error occured, true otherwise.
3846 */
3847 boolean viewServerListWindows(Socket client) {
Romain Guy06882f82009-06-10 13:36:04 -07003848 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003849 return false;
3850 }
3851
3852 boolean result = true;
3853
3854 Object[] windows;
3855 synchronized (mWindowMap) {
3856 windows = new Object[mWindows.size()];
3857 //noinspection unchecked
3858 windows = mWindows.toArray(windows);
3859 }
3860
3861 BufferedWriter out = null;
3862
3863 // Any uncaught exception will crash the system process
3864 try {
3865 OutputStream clientStream = client.getOutputStream();
3866 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
3867
3868 final int count = windows.length;
3869 for (int i = 0; i < count; i++) {
3870 final WindowState w = (WindowState) windows[i];
3871 out.write(Integer.toHexString(System.identityHashCode(w)));
3872 out.write(' ');
3873 out.append(w.mAttrs.getTitle());
3874 out.write('\n');
3875 }
3876
3877 out.write("DONE.\n");
3878 out.flush();
3879 } catch (Exception e) {
3880 result = false;
3881 } finally {
3882 if (out != null) {
3883 try {
3884 out.close();
3885 } catch (IOException e) {
3886 result = false;
3887 }
3888 }
3889 }
3890
3891 return result;
3892 }
3893
3894 /**
3895 * Sends a command to a target window. The result of the command, if any, will be
3896 * written in the output stream of the specified socket.
3897 *
3898 * The parameters must follow this syntax:
3899 * windowHashcode extra
3900 *
3901 * Where XX is the length in characeters of the windowTitle.
3902 *
3903 * The first parameter is the target window. The window with the specified hashcode
3904 * will be the target. If no target can be found, nothing happens. The extra parameters
3905 * will be delivered to the target window and as parameters to the command itself.
3906 *
3907 * @param client The remote client to sent the result, if any, to.
3908 * @param command The command to execute.
3909 * @param parameters The command parameters.
3910 *
3911 * @return True if the command was successfully delivered, false otherwise. This does
3912 * not indicate whether the command itself was successful.
3913 */
3914 boolean viewServerWindowCommand(Socket client, String command, String parameters) {
Romain Guy06882f82009-06-10 13:36:04 -07003915 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003916 return false;
3917 }
3918
3919 boolean success = true;
3920 Parcel data = null;
3921 Parcel reply = null;
3922
3923 // Any uncaught exception will crash the system process
3924 try {
3925 // Find the hashcode of the window
3926 int index = parameters.indexOf(' ');
3927 if (index == -1) {
3928 index = parameters.length();
3929 }
3930 final String code = parameters.substring(0, index);
3931 int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
3932
3933 // Extract the command's parameter after the window description
3934 if (index < parameters.length()) {
3935 parameters = parameters.substring(index + 1);
3936 } else {
3937 parameters = "";
3938 }
3939
3940 final WindowManagerService.WindowState window = findWindow(hashCode);
3941 if (window == null) {
3942 return false;
3943 }
3944
3945 data = Parcel.obtain();
3946 data.writeInterfaceToken("android.view.IWindow");
3947 data.writeString(command);
3948 data.writeString(parameters);
3949 data.writeInt(1);
3950 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
3951
3952 reply = Parcel.obtain();
3953
3954 final IBinder binder = window.mClient.asBinder();
3955 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
3956 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
3957
3958 reply.readException();
3959
3960 } catch (Exception e) {
3961 Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
3962 success = false;
3963 } finally {
3964 if (data != null) {
3965 data.recycle();
3966 }
3967 if (reply != null) {
3968 reply.recycle();
3969 }
3970 }
3971
3972 return success;
3973 }
3974
3975 private WindowState findWindow(int hashCode) {
3976 if (hashCode == -1) {
3977 return getFocusedWindow();
3978 }
3979
3980 synchronized (mWindowMap) {
3981 final ArrayList windows = mWindows;
3982 final int count = windows.size();
3983
3984 for (int i = 0; i < count; i++) {
3985 WindowState w = (WindowState) windows.get(i);
3986 if (System.identityHashCode(w) == hashCode) {
3987 return w;
3988 }
3989 }
3990 }
3991
3992 return null;
3993 }
3994
3995 /*
3996 * Instruct the Activity Manager to fetch the current configuration and broadcast
3997 * that to config-changed listeners if appropriate.
3998 */
3999 void sendNewConfiguration() {
4000 try {
4001 mActivityManager.updateConfiguration(null);
4002 } catch (RemoteException e) {
4003 }
4004 }
Romain Guy06882f82009-06-10 13:36:04 -07004005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004006 public Configuration computeNewConfiguration() {
4007 synchronized (mWindowMap) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07004008 return computeNewConfigurationLocked();
4009 }
4010 }
Romain Guy06882f82009-06-10 13:36:04 -07004011
Dianne Hackbornc485a602009-03-24 22:39:49 -07004012 Configuration computeNewConfigurationLocked() {
4013 Configuration config = new Configuration();
4014 if (!computeNewConfigurationLocked(config)) {
4015 return null;
4016 }
4017 Log.i(TAG, "Config changed: " + config);
4018 long now = SystemClock.uptimeMillis();
4019 //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
4020 if (mFreezeGcPending != 0) {
4021 if (now > (mFreezeGcPending+1000)) {
4022 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
4023 mH.removeMessages(H.FORCE_GC);
4024 Runtime.getRuntime().gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004025 mFreezeGcPending = now;
4026 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07004027 } else {
4028 mFreezeGcPending = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07004030 return config;
4031 }
Romain Guy06882f82009-06-10 13:36:04 -07004032
Dianne Hackbornc485a602009-03-24 22:39:49 -07004033 boolean computeNewConfigurationLocked(Configuration config) {
4034 if (mDisplay == null) {
4035 return false;
4036 }
4037 mQueue.getInputConfiguration(config);
4038 final int dw = mDisplay.getWidth();
4039 final int dh = mDisplay.getHeight();
4040 int orientation = Configuration.ORIENTATION_SQUARE;
4041 if (dw < dh) {
4042 orientation = Configuration.ORIENTATION_PORTRAIT;
4043 } else if (dw > dh) {
4044 orientation = Configuration.ORIENTATION_LANDSCAPE;
4045 }
4046 config.orientation = orientation;
Dianne Hackborn723738c2009-06-25 19:48:04 -07004047
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07004048 DisplayMetrics dm = new DisplayMetrics();
4049 mDisplay.getMetrics(dm);
4050 CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
4051
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07004052 if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
Dianne Hackborn723738c2009-06-25 19:48:04 -07004053 // Note we only do this once because at this point we don't
4054 // expect the screen to change in this way at runtime, and want
4055 // to avoid all of this computation for every config change.
Dianne Hackborn723738c2009-06-25 19:48:04 -07004056 int longSize = dw;
4057 int shortSize = dh;
4058 if (longSize < shortSize) {
4059 int tmp = longSize;
4060 longSize = shortSize;
4061 shortSize = tmp;
4062 }
4063 longSize = (int)(longSize/dm.density);
4064 shortSize = (int)(shortSize/dm.density);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07004065
Dianne Hackborn723738c2009-06-25 19:48:04 -07004066 // These semi-magic numbers define our compatibility modes for
4067 // applications with different screens. Don't change unless you
4068 // make sure to test lots and lots of apps!
4069 if (longSize < 470) {
4070 // This is shorter than an HVGA normal density screen (which
4071 // is 480 pixels on its long side).
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07004072 mScreenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
4073 | Configuration.SCREENLAYOUT_LONG_NO;
Dianne Hackborn723738c2009-06-25 19:48:04 -07004074 } else {
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07004075 // Is this a large screen?
4076 if (longSize > 640 && shortSize >= 480) {
4077 // VGA or larger screens at medium density are the point
4078 // at which we consider it to be a large screen.
4079 mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
4080 } else {
4081 mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
4082
4083 // If this screen is wider than normal HVGA, or taller
4084 // than FWVGA, then for old apps we want to run in size
4085 // compatibility mode.
4086 if (shortSize > 321 || longSize > 570) {
4087 mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
4088 }
4089 }
4090
4091 // Is this a long screen?
4092 if (((longSize*3)/5) >= (shortSize-1)) {
4093 // Anything wider than WVGA (5:3) is considering to be long.
4094 mScreenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
4095 } else {
4096 mScreenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
4097 }
Dianne Hackborn723738c2009-06-25 19:48:04 -07004098 }
4099 }
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07004100 config.screenLayout = mScreenLayout;
Dianne Hackborn723738c2009-06-25 19:48:04 -07004101
Dianne Hackbornc485a602009-03-24 22:39:49 -07004102 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
4103 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
4104 mPolicy.adjustConfigurationLw(config);
4105 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004106 }
Romain Guy06882f82009-06-10 13:36:04 -07004107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 // -------------------------------------------------------------
4109 // Input Events and Focus Management
4110 // -------------------------------------------------------------
4111
4112 private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
Michael Chane96440f2009-05-06 10:27:36 -07004113 long curTime = SystemClock.uptimeMillis();
4114
Michael Chane10de972009-05-18 11:24:50 -07004115 if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
Michael Chane96440f2009-05-06 10:27:36 -07004116 if (mLastTouchEventType == eventType &&
4117 (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
4118 return;
4119 }
4120 mLastUserActivityCallTime = curTime;
4121 mLastTouchEventType = eventType;
4122 }
4123
4124 if (targetWin == null
4125 || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
4126 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 }
4128 }
4129
4130 // tells if it's a cheek event or not -- this function is stateful
4131 private static final int EVENT_NONE = 0;
4132 private static final int EVENT_UNKNOWN = 0;
4133 private static final int EVENT_CHEEK = 0;
4134 private static final int EVENT_IGNORE_DURATION = 300; // ms
4135 private static final float CHEEK_THRESHOLD = 0.6f;
4136 private int mEventState = EVENT_NONE;
4137 private float mEventSize;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07004138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 private int eventType(MotionEvent ev) {
4140 float size = ev.getSize();
4141 switch (ev.getAction()) {
4142 case MotionEvent.ACTION_DOWN:
4143 mEventSize = size;
4144 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
4145 case MotionEvent.ACTION_UP:
4146 if (size > mEventSize) mEventSize = size;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07004147 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004148 case MotionEvent.ACTION_MOVE:
4149 final int N = ev.getHistorySize();
4150 if (size > mEventSize) mEventSize = size;
4151 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
4152 for (int i=0; i<N; i++) {
4153 size = ev.getHistoricalSize(i);
4154 if (size > mEventSize) mEventSize = size;
4155 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
4156 }
4157 if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
4158 return TOUCH_EVENT;
4159 } else {
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07004160 return LONG_TOUCH_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004161 }
4162 default:
4163 // not good
4164 return OTHER_EVENT;
4165 }
4166 }
4167
4168 /**
4169 * @return Returns true if event was dispatched, false if it was dropped for any reason
4170 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004171 private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004172 if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
4173 "dispatchPointer " + ev);
4174
Michael Chan53071d62009-05-13 17:29:48 -07004175 if (MEASURE_LATENCY) {
4176 lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
4177 }
4178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004180 ev, true, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004181
Michael Chan53071d62009-05-13 17:29:48 -07004182 if (MEASURE_LATENCY) {
4183 lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
4184 }
4185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004186 int action = ev.getAction();
Romain Guy06882f82009-06-10 13:36:04 -07004187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 if (action == MotionEvent.ACTION_UP) {
4189 // let go of our target
4190 mKeyWaiter.mMotionTarget = null;
4191 mPowerManager.logPointerUpEvent();
4192 } else if (action == MotionEvent.ACTION_DOWN) {
4193 mPowerManager.logPointerDownEvent();
4194 }
4195
4196 if (targetObj == null) {
4197 // In this case we are either dropping the event, or have received
4198 // a move or up without a down. It is common to receive move
4199 // events in such a way, since this means the user is moving the
4200 // pointer without actually pressing down. All other cases should
4201 // be atypical, so let's log them.
Michael Chane96440f2009-05-06 10:27:36 -07004202 if (action != MotionEvent.ACTION_MOVE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004203 Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
4204 }
4205 if (qev != null) {
4206 mQueue.recycleEvent(qev);
4207 }
4208 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004209 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004210 }
4211 if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
4212 if (qev != null) {
4213 mQueue.recycleEvent(qev);
4214 }
4215 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004216 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004217 }
Romain Guy06882f82009-06-10 13:36:04 -07004218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004219 WindowState target = (WindowState)targetObj;
Romain Guy06882f82009-06-10 13:36:04 -07004220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004221 final long eventTime = ev.getEventTime();
Michael Chan53071d62009-05-13 17:29:48 -07004222 final long eventTimeNano = ev.getEventTimeNano();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004223
4224 //Log.i(TAG, "Sending " + ev + " to " + target);
4225
4226 if (uid != 0 && uid != target.mSession.mUid) {
4227 if (mContext.checkPermission(
4228 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4229 != PackageManager.PERMISSION_GRANTED) {
4230 Log.w(TAG, "Permission denied: injecting pointer event from pid "
4231 + pid + " uid " + uid + " to window " + target
4232 + " owned by uid " + target.mSession.mUid);
4233 if (qev != null) {
4234 mQueue.recycleEvent(qev);
4235 }
4236 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004237 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004238 }
4239 }
4240
Michael Chan53071d62009-05-13 17:29:48 -07004241 if (MEASURE_LATENCY) {
4242 lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
4243 }
4244
Romain Guy06882f82009-06-10 13:36:04 -07004245 if ((target.mAttrs.flags &
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004246 WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
4247 //target wants to ignore fat touch events
4248 boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
4249 //explicit flag to return without processing event further
4250 boolean returnFlag = false;
4251 if((action == MotionEvent.ACTION_DOWN)) {
4252 mFatTouch = false;
4253 if(cheekPress) {
4254 mFatTouch = true;
4255 returnFlag = true;
4256 }
4257 } else {
4258 if(action == MotionEvent.ACTION_UP) {
4259 if(mFatTouch) {
4260 //earlier even was invalid doesnt matter if current up is cheekpress or not
4261 mFatTouch = false;
4262 returnFlag = true;
4263 } else if(cheekPress) {
4264 //cancel the earlier event
4265 ev.setAction(MotionEvent.ACTION_CANCEL);
4266 action = MotionEvent.ACTION_CANCEL;
4267 }
4268 } else if(action == MotionEvent.ACTION_MOVE) {
4269 if(mFatTouch) {
4270 //two cases here
4271 //an invalid down followed by 0 or moves(valid or invalid)
Romain Guy06882f82009-06-10 13:36:04 -07004272 //a valid down, invalid move, more moves. want to ignore till up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004273 returnFlag = true;
4274 } else if(cheekPress) {
4275 //valid down followed by invalid moves
4276 //an invalid move have to cancel earlier action
4277 ev.setAction(MotionEvent.ACTION_CANCEL);
4278 action = MotionEvent.ACTION_CANCEL;
4279 if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE");
4280 //note that the subsequent invalid moves will not get here
4281 mFatTouch = true;
4282 }
4283 }
4284 } //else if action
4285 if(returnFlag) {
4286 //recycle que, ev
4287 if (qev != null) {
4288 mQueue.recycleEvent(qev);
4289 }
4290 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004291 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004292 }
4293 } //end if target
Michael Chane96440f2009-05-06 10:27:36 -07004294
Michael Chan9f028e62009-08-04 17:37:46 -07004295 // Enable this for testing the "right" value
4296 if (false && action == MotionEvent.ACTION_DOWN) {
Michael Chane96440f2009-05-06 10:27:36 -07004297 int max_events_per_sec = 35;
4298 try {
4299 max_events_per_sec = Integer.parseInt(SystemProperties
4300 .get("windowsmgr.max_events_per_sec"));
4301 if (max_events_per_sec < 1) {
4302 max_events_per_sec = 35;
4303 }
4304 } catch (NumberFormatException e) {
4305 }
4306 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
4307 }
4308
4309 /*
4310 * Throttle events to minimize CPU usage when there's a flood of events
4311 * e.g. constant contact with the screen
4312 */
4313 if (action == MotionEvent.ACTION_MOVE) {
4314 long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
4315 long now = SystemClock.uptimeMillis();
4316 if (now < nextEventTime) {
4317 try {
4318 Thread.sleep(nextEventTime - now);
4319 } catch (InterruptedException e) {
4320 }
4321 mLastTouchEventTime = nextEventTime;
4322 } else {
4323 mLastTouchEventTime = now;
4324 }
4325 }
4326
Michael Chan53071d62009-05-13 17:29:48 -07004327 if (MEASURE_LATENCY) {
4328 lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano);
4329 }
4330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004331 synchronized(mWindowMap) {
4332 if (qev != null && action == MotionEvent.ACTION_MOVE) {
4333 mKeyWaiter.bindTargetWindowLocked(target,
4334 KeyWaiter.RETURN_PENDING_POINTER, qev);
4335 ev = null;
4336 } else {
4337 if (action == MotionEvent.ACTION_DOWN) {
4338 WindowState out = mKeyWaiter.mOutsideTouchTargets;
4339 if (out != null) {
4340 MotionEvent oev = MotionEvent.obtain(ev);
4341 oev.setAction(MotionEvent.ACTION_OUTSIDE);
4342 do {
4343 final Rect frame = out.mFrame;
4344 oev.offsetLocation(-(float)frame.left, -(float)frame.top);
4345 try {
4346 out.mClient.dispatchPointer(oev, eventTime);
4347 } catch (android.os.RemoteException e) {
4348 Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
4349 }
4350 oev.offsetLocation((float)frame.left, (float)frame.top);
4351 out = out.mNextOutsideTouch;
4352 } while (out != null);
4353 mKeyWaiter.mOutsideTouchTargets = null;
4354 }
4355 }
4356 final Rect frame = target.mFrame;
4357 ev.offsetLocation(-(float)frame.left, -(float)frame.top);
4358 mKeyWaiter.bindTargetWindowLocked(target);
4359 }
4360 }
Romain Guy06882f82009-06-10 13:36:04 -07004361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 // finally offset the event to the target's coordinate system and
4363 // dispatch the event.
4364 try {
4365 if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
4366 Log.v(TAG, "Delivering pointer " + qev + " to " + target);
4367 }
Michael Chan53071d62009-05-13 17:29:48 -07004368
4369 if (MEASURE_LATENCY) {
4370 lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
4371 }
4372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004373 target.mClient.dispatchPointer(ev, eventTime);
Michael Chan53071d62009-05-13 17:29:48 -07004374
4375 if (MEASURE_LATENCY) {
4376 lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
4377 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004378 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004379 } catch (android.os.RemoteException e) {
4380 Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
4381 mKeyWaiter.mMotionTarget = null;
4382 try {
4383 removeWindow(target.mSession, target.mClient);
4384 } catch (java.util.NoSuchElementException ex) {
4385 // This will happen if the window has already been
4386 // removed.
4387 }
4388 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004389 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004390 }
Romain Guy06882f82009-06-10 13:36:04 -07004391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004392 /**
4393 * @return Returns true if event was dispatched, false if it was dropped for any reason
4394 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004395 private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004396 if (DEBUG_INPUT) Log.v(
4397 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
Romain Guy06882f82009-06-10 13:36:04 -07004398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004399 Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004400 ev, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004401 if (focusObj == null) {
4402 Log.w(TAG, "No focus window, dropping trackball: " + ev);
4403 if (qev != null) {
4404 mQueue.recycleEvent(qev);
4405 }
4406 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004407 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004408 }
4409 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
4410 if (qev != null) {
4411 mQueue.recycleEvent(qev);
4412 }
4413 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004414 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004415 }
Romain Guy06882f82009-06-10 13:36:04 -07004416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004417 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004419 if (uid != 0 && uid != focus.mSession.mUid) {
4420 if (mContext.checkPermission(
4421 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4422 != PackageManager.PERMISSION_GRANTED) {
4423 Log.w(TAG, "Permission denied: injecting key event from pid "
4424 + pid + " uid " + uid + " to window " + focus
4425 + " owned by uid " + focus.mSession.mUid);
4426 if (qev != null) {
4427 mQueue.recycleEvent(qev);
4428 }
4429 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004430 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004431 }
4432 }
Romain Guy06882f82009-06-10 13:36:04 -07004433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004434 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004436 synchronized(mWindowMap) {
4437 if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
4438 mKeyWaiter.bindTargetWindowLocked(focus,
4439 KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
4440 // We don't deliver movement events to the client, we hold
4441 // them and wait for them to call back.
4442 ev = null;
4443 } else {
4444 mKeyWaiter.bindTargetWindowLocked(focus);
4445 }
4446 }
Romain Guy06882f82009-06-10 13:36:04 -07004447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004448 try {
4449 focus.mClient.dispatchTrackball(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004450 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004451 } catch (android.os.RemoteException e) {
4452 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4453 try {
4454 removeWindow(focus.mSession, focus.mClient);
4455 } catch (java.util.NoSuchElementException ex) {
4456 // This will happen if the window has already been
4457 // removed.
4458 }
4459 }
Romain Guy06882f82009-06-10 13:36:04 -07004460
Dianne Hackborncfaef692009-06-15 14:24:44 -07004461 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004462 }
Romain Guy06882f82009-06-10 13:36:04 -07004463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 /**
4465 * @return Returns true if event was dispatched, false if it was dropped for any reason
4466 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004467 private int dispatchKey(KeyEvent event, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004468 if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
4469
4470 Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004471 null, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004472 if (focusObj == null) {
4473 Log.w(TAG, "No focus window, dropping: " + event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004474 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004475 }
4476 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004477 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004478 }
Romain Guy06882f82009-06-10 13:36:04 -07004479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482 if (DEBUG_INPUT) Log.v(
4483 TAG, "Dispatching to " + focus + ": " + event);
4484
4485 if (uid != 0 && uid != focus.mSession.mUid) {
4486 if (mContext.checkPermission(
4487 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4488 != PackageManager.PERMISSION_GRANTED) {
4489 Log.w(TAG, "Permission denied: injecting key event from pid "
4490 + pid + " uid " + uid + " to window " + focus
4491 + " owned by uid " + focus.mSession.mUid);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004492 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004493 }
4494 }
Romain Guy06882f82009-06-10 13:36:04 -07004495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 synchronized(mWindowMap) {
4497 mKeyWaiter.bindTargetWindowLocked(focus);
4498 }
4499
4500 // NOSHIP extra state logging
4501 mKeyWaiter.recordDispatchState(event, focus);
4502 // END NOSHIP
Romain Guy06882f82009-06-10 13:36:04 -07004503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004504 try {
4505 if (DEBUG_INPUT || DEBUG_FOCUS) {
4506 Log.v(TAG, "Delivering key " + event.getKeyCode()
4507 + " to " + focus);
4508 }
4509 focus.mClient.dispatchKey(event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004510 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004511 } catch (android.os.RemoteException e) {
4512 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4513 try {
4514 removeWindow(focus.mSession, focus.mClient);
4515 } catch (java.util.NoSuchElementException ex) {
4516 // This will happen if the window has already been
4517 // removed.
4518 }
4519 }
Romain Guy06882f82009-06-10 13:36:04 -07004520
Dianne Hackborncfaef692009-06-15 14:24:44 -07004521 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004522 }
Romain Guy06882f82009-06-10 13:36:04 -07004523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004524 public void pauseKeyDispatching(IBinder _token) {
4525 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4526 "pauseKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004527 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004528 }
4529
4530 synchronized (mWindowMap) {
4531 WindowToken token = mTokenMap.get(_token);
4532 if (token != null) {
4533 mKeyWaiter.pauseDispatchingLocked(token);
4534 }
4535 }
4536 }
4537
4538 public void resumeKeyDispatching(IBinder _token) {
4539 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4540 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004541 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004542 }
4543
4544 synchronized (mWindowMap) {
4545 WindowToken token = mTokenMap.get(_token);
4546 if (token != null) {
4547 mKeyWaiter.resumeDispatchingLocked(token);
4548 }
4549 }
4550 }
4551
4552 public void setEventDispatching(boolean enabled) {
4553 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4554 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004555 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004556 }
4557
4558 synchronized (mWindowMap) {
4559 mKeyWaiter.setEventDispatchingLocked(enabled);
4560 }
4561 }
Romain Guy06882f82009-06-10 13:36:04 -07004562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004563 /**
4564 * Injects a keystroke event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004565 *
4566 * @param ev A motion event describing the keystroke action. (Be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004567 * {@link SystemClock#uptimeMillis()} as the timebase.)
4568 * @param sync If true, wait for the event to be completed before returning to the caller.
4569 * @return Returns true if event was dispatched, false if it was dropped for any reason
4570 */
4571 public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
4572 long downTime = ev.getDownTime();
4573 long eventTime = ev.getEventTime();
4574
4575 int action = ev.getAction();
4576 int code = ev.getKeyCode();
4577 int repeatCount = ev.getRepeatCount();
4578 int metaState = ev.getMetaState();
4579 int deviceId = ev.getDeviceId();
4580 int scancode = ev.getScanCode();
4581
4582 if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
4583 if (downTime == 0) downTime = eventTime;
4584
4585 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
The Android Open Source Project10592532009-03-18 17:39:46 -07004586 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004587
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004588 final int pid = Binder.getCallingPid();
4589 final int uid = Binder.getCallingUid();
4590 final long ident = Binder.clearCallingIdentity();
4591 final int result = dispatchKey(newEvent, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004592 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004593 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004594 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004595 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004596 switch (result) {
4597 case INJECT_NO_PERMISSION:
4598 throw new SecurityException(
4599 "Injecting to another application requires INJECT_EVENT permission");
4600 case INJECT_SUCCEEDED:
4601 return true;
4602 }
4603 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604 }
4605
4606 /**
4607 * Inject a pointer (touch) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004608 *
4609 * @param ev A motion event describing the pointer (touch) action. (As noted in
4610 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004611 * {@link SystemClock#uptimeMillis()} as the timebase.)
4612 * @param sync If true, wait for the event to be completed before returning to the caller.
4613 * @return Returns true if event was dispatched, false if it was dropped for any reason
4614 */
4615 public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004616 final int pid = Binder.getCallingPid();
4617 final int uid = Binder.getCallingUid();
4618 final long ident = Binder.clearCallingIdentity();
4619 final int result = dispatchPointer(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004620 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004621 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004622 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004623 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004624 switch (result) {
4625 case INJECT_NO_PERMISSION:
4626 throw new SecurityException(
4627 "Injecting to another application requires INJECT_EVENT permission");
4628 case INJECT_SUCCEEDED:
4629 return true;
4630 }
4631 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004632 }
Romain Guy06882f82009-06-10 13:36:04 -07004633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 /**
4635 * Inject a trackball (navigation device) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004636 *
4637 * @param ev A motion event describing the trackball action. (As noted in
4638 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 * {@link SystemClock#uptimeMillis()} as the timebase.)
4640 * @param sync If true, wait for the event to be completed before returning to the caller.
4641 * @return Returns true if event was dispatched, false if it was dropped for any reason
4642 */
4643 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004644 final int pid = Binder.getCallingPid();
4645 final int uid = Binder.getCallingUid();
4646 final long ident = Binder.clearCallingIdentity();
4647 final int result = dispatchTrackball(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004648 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004649 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004651 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004652 switch (result) {
4653 case INJECT_NO_PERMISSION:
4654 throw new SecurityException(
4655 "Injecting to another application requires INJECT_EVENT permission");
4656 case INJECT_SUCCEEDED:
4657 return true;
4658 }
4659 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004660 }
Romain Guy06882f82009-06-10 13:36:04 -07004661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004662 private WindowState getFocusedWindow() {
4663 synchronized (mWindowMap) {
4664 return getFocusedWindowLocked();
4665 }
4666 }
4667
4668 private WindowState getFocusedWindowLocked() {
4669 return mCurrentFocus;
4670 }
Romain Guy06882f82009-06-10 13:36:04 -07004671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 /**
4673 * This class holds the state for dispatching key events. This state
4674 * is protected by the KeyWaiter instance, NOT by the window lock. You
4675 * can be holding the main window lock while acquire the KeyWaiter lock,
4676 * but not the other way around.
4677 */
4678 final class KeyWaiter {
4679 // NOSHIP debugging
4680 public class DispatchState {
4681 private KeyEvent event;
4682 private WindowState focus;
4683 private long time;
4684 private WindowState lastWin;
4685 private IBinder lastBinder;
4686 private boolean finished;
4687 private boolean gotFirstWindow;
4688 private boolean eventDispatching;
4689 private long timeToSwitch;
4690 private boolean wasFrozen;
4691 private boolean focusPaused;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004692 private WindowState curFocus;
Romain Guy06882f82009-06-10 13:36:04 -07004693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 DispatchState(KeyEvent theEvent, WindowState theFocus) {
4695 focus = theFocus;
4696 event = theEvent;
4697 time = System.currentTimeMillis();
4698 // snapshot KeyWaiter state
4699 lastWin = mLastWin;
4700 lastBinder = mLastBinder;
4701 finished = mFinished;
4702 gotFirstWindow = mGotFirstWindow;
4703 eventDispatching = mEventDispatching;
4704 timeToSwitch = mTimeToSwitch;
4705 wasFrozen = mWasFrozen;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004706 curFocus = mCurrentFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004707 // cache the paused state at ctor time as well
4708 if (theFocus == null || theFocus.mToken == null) {
4709 Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
4710 focusPaused = false;
4711 } else {
4712 focusPaused = theFocus.mToken.paused;
4713 }
4714 }
Romain Guy06882f82009-06-10 13:36:04 -07004715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004716 public String toString() {
4717 return "{{" + event + " to " + focus + " @ " + time
4718 + " lw=" + lastWin + " lb=" + lastBinder
4719 + " fin=" + finished + " gfw=" + gotFirstWindow
4720 + " ed=" + eventDispatching + " tts=" + timeToSwitch
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004721 + " wf=" + wasFrozen + " fp=" + focusPaused
4722 + " mcf=" + mCurrentFocus + "}}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004723 }
4724 };
4725 private DispatchState mDispatchState = null;
4726 public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
4727 mDispatchState = new DispatchState(theEvent, theFocus);
4728 }
4729 // END NOSHIP
4730
4731 public static final int RETURN_NOTHING = 0;
4732 public static final int RETURN_PENDING_POINTER = 1;
4733 public static final int RETURN_PENDING_TRACKBALL = 2;
Romain Guy06882f82009-06-10 13:36:04 -07004734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004735 final Object SKIP_TARGET_TOKEN = new Object();
4736 final Object CONSUMED_EVENT_TOKEN = new Object();
Romain Guy06882f82009-06-10 13:36:04 -07004737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004738 private WindowState mLastWin = null;
4739 private IBinder mLastBinder = null;
4740 private boolean mFinished = true;
4741 private boolean mGotFirstWindow = false;
4742 private boolean mEventDispatching = true;
4743 private long mTimeToSwitch = 0;
4744 /* package */ boolean mWasFrozen = false;
Romain Guy06882f82009-06-10 13:36:04 -07004745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 // Target of Motion events
4747 WindowState mMotionTarget;
Romain Guy06882f82009-06-10 13:36:04 -07004748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004749 // Windows above the target who would like to receive an "outside"
4750 // touch event for any down events outside of them.
4751 WindowState mOutsideTouchTargets;
4752
4753 /**
4754 * Wait for the last event dispatch to complete, then find the next
4755 * target that should receive the given event and wait for that one
4756 * to be ready to receive it.
4757 */
4758 Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
4759 MotionEvent nextMotion, boolean isPointerEvent,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004760 boolean failIfTimeout, int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004761 long startTime = SystemClock.uptimeMillis();
4762 long keyDispatchingTimeout = 5 * 1000;
4763 long waitedFor = 0;
4764
4765 while (true) {
4766 // Figure out which window we care about. It is either the
4767 // last window we are waiting to have process the event or,
4768 // if none, then the next window we think the event should go
4769 // to. Note: we retrieve mLastWin outside of the lock, so
4770 // it may change before we lock. Thus we must check it again.
4771 WindowState targetWin = mLastWin;
4772 boolean targetIsNew = targetWin == null;
4773 if (DEBUG_INPUT) Log.v(
4774 TAG, "waitForLastKey: mFinished=" + mFinished +
4775 ", mLastWin=" + mLastWin);
4776 if (targetIsNew) {
4777 Object target = findTargetWindow(nextKey, qev, nextMotion,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004778 isPointerEvent, callingPid, callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004779 if (target == SKIP_TARGET_TOKEN) {
4780 // The user has pressed a special key, and we are
4781 // dropping all pending events before it.
4782 if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey
4783 + " " + nextMotion);
4784 return null;
4785 }
4786 if (target == CONSUMED_EVENT_TOKEN) {
4787 if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
4788 + " " + nextMotion);
4789 return target;
4790 }
4791 targetWin = (WindowState)target;
4792 }
Romain Guy06882f82009-06-10 13:36:04 -07004793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004794 AppWindowToken targetApp = null;
Romain Guy06882f82009-06-10 13:36:04 -07004795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004796 // Now: is it okay to send the next event to this window?
4797 synchronized (this) {
4798 // First: did we come here based on the last window not
4799 // being null, but it changed by the time we got here?
4800 // If so, try again.
4801 if (!targetIsNew && mLastWin == null) {
4802 continue;
4803 }
Romain Guy06882f82009-06-10 13:36:04 -07004804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 // We never dispatch events if not finished with the
4806 // last one, or the display is frozen.
4807 if (mFinished && !mDisplayFrozen) {
4808 // If event dispatching is disabled, then we
4809 // just consume the events.
4810 if (!mEventDispatching) {
4811 if (DEBUG_INPUT) Log.v(TAG,
4812 "Skipping event; dispatching disabled: "
4813 + nextKey + " " + nextMotion);
4814 return null;
4815 }
4816 if (targetWin != null) {
4817 // If this is a new target, and that target is not
4818 // paused or unresponsive, then all looks good to
4819 // handle the event.
4820 if (targetIsNew && !targetWin.mToken.paused) {
4821 return targetWin;
4822 }
Romain Guy06882f82009-06-10 13:36:04 -07004823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004824 // If we didn't find a target window, and there is no
4825 // focused app window, then just eat the events.
4826 } else if (mFocusedApp == null) {
4827 if (DEBUG_INPUT) Log.v(TAG,
4828 "Skipping event; no focused app: "
4829 + nextKey + " " + nextMotion);
4830 return null;
4831 }
4832 }
Romain Guy06882f82009-06-10 13:36:04 -07004833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004834 if (DEBUG_INPUT) Log.v(
4835 TAG, "Waiting for last key in " + mLastBinder
4836 + " target=" + targetWin
4837 + " mFinished=" + mFinished
4838 + " mDisplayFrozen=" + mDisplayFrozen
4839 + " targetIsNew=" + targetIsNew
4840 + " paused="
4841 + (targetWin != null ? targetWin.mToken.paused : false)
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004842 + " mFocusedApp=" + mFocusedApp
4843 + " mCurrentFocus=" + mCurrentFocus);
Romain Guy06882f82009-06-10 13:36:04 -07004844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004845 targetApp = targetWin != null
4846 ? targetWin.mAppToken : mFocusedApp;
Romain Guy06882f82009-06-10 13:36:04 -07004847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004848 long curTimeout = keyDispatchingTimeout;
4849 if (mTimeToSwitch != 0) {
4850 long now = SystemClock.uptimeMillis();
4851 if (mTimeToSwitch <= now) {
4852 // If an app switch key has been pressed, and we have
4853 // waited too long for the current app to finish
4854 // processing keys, then wait no more!
4855 doFinishedKeyLocked(true);
4856 continue;
4857 }
4858 long switchTimeout = mTimeToSwitch - now;
4859 if (curTimeout > switchTimeout) {
4860 curTimeout = switchTimeout;
4861 }
4862 }
Romain Guy06882f82009-06-10 13:36:04 -07004863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 try {
4865 // after that continue
4866 // processing keys, so we don't get stuck.
4867 if (DEBUG_INPUT) Log.v(
4868 TAG, "Waiting for key dispatch: " + curTimeout);
4869 wait(curTimeout);
4870 if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
4871 + SystemClock.uptimeMillis() + " startTime="
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004872 + startTime + " switchTime=" + mTimeToSwitch
4873 + " target=" + targetWin + " mLW=" + mLastWin
4874 + " mLB=" + mLastBinder + " fin=" + mFinished
4875 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004876 } catch (InterruptedException e) {
4877 }
4878 }
4879
4880 // If we were frozen during configuration change, restart the
4881 // timeout checks from now; otherwise look at whether we timed
4882 // out before awakening.
4883 if (mWasFrozen) {
4884 waitedFor = 0;
4885 mWasFrozen = false;
4886 } else {
4887 waitedFor = SystemClock.uptimeMillis() - startTime;
4888 }
4889
4890 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
4891 IApplicationToken at = null;
4892 synchronized (this) {
4893 Log.w(TAG, "Key dispatching timed out sending to " +
4894 (targetWin != null ? targetWin.mAttrs.getTitle()
4895 : "<null>"));
4896 // NOSHIP debugging
4897 Log.w(TAG, "Dispatch state: " + mDispatchState);
4898 Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
4899 // END NOSHIP
4900 //dump();
4901 if (targetWin != null) {
4902 at = targetWin.getAppToken();
4903 } else if (targetApp != null) {
4904 at = targetApp.appToken;
4905 }
4906 }
4907
4908 boolean abort = true;
4909 if (at != null) {
4910 try {
4911 long timeout = at.getKeyDispatchingTimeout();
4912 if (timeout > waitedFor) {
4913 // we did not wait the proper amount of time for this application.
4914 // set the timeout to be the real timeout and wait again.
4915 keyDispatchingTimeout = timeout - waitedFor;
4916 continue;
4917 } else {
4918 abort = at.keyDispatchingTimedOut();
4919 }
4920 } catch (RemoteException ex) {
4921 }
4922 }
4923
4924 synchronized (this) {
4925 if (abort && (mLastWin == targetWin || targetWin == null)) {
4926 mFinished = true;
Romain Guy06882f82009-06-10 13:36:04 -07004927 if (mLastWin != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004928 if (DEBUG_INPUT) Log.v(TAG,
4929 "Window " + mLastWin +
4930 " timed out on key input");
4931 if (mLastWin.mToken.paused) {
4932 Log.w(TAG, "Un-pausing dispatching to this window");
4933 mLastWin.mToken.paused = false;
4934 }
4935 }
4936 if (mMotionTarget == targetWin) {
4937 mMotionTarget = null;
4938 }
4939 mLastWin = null;
4940 mLastBinder = null;
4941 if (failIfTimeout || targetWin == null) {
4942 return null;
4943 }
4944 } else {
4945 Log.w(TAG, "Continuing to wait for key to be dispatched");
4946 startTime = SystemClock.uptimeMillis();
4947 }
4948 }
4949 }
4950 }
4951 }
Romain Guy06882f82009-06-10 13:36:04 -07004952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004953 Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004954 MotionEvent nextMotion, boolean isPointerEvent,
4955 int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004956 mOutsideTouchTargets = null;
Romain Guy06882f82009-06-10 13:36:04 -07004957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004958 if (nextKey != null) {
4959 // Find the target window for a normal key event.
4960 final int keycode = nextKey.getKeyCode();
4961 final int repeatCount = nextKey.getRepeatCount();
4962 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
4963 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004965 if (!dispatch) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004966 if (callingUid == 0 ||
4967 mContext.checkPermission(
4968 android.Manifest.permission.INJECT_EVENTS,
4969 callingPid, callingUid)
4970 == PackageManager.PERMISSION_GRANTED) {
4971 mPolicy.interceptKeyTi(null, keycode,
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07004972 nextKey.getMetaState(), down, repeatCount,
4973 nextKey.getFlags());
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004975 Log.w(TAG, "Event timeout during app switch: dropping "
4976 + nextKey);
4977 return SKIP_TARGET_TOKEN;
4978 }
Romain Guy06882f82009-06-10 13:36:04 -07004979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004980 // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
Romain Guy06882f82009-06-10 13:36:04 -07004981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004982 WindowState focus = null;
4983 synchronized(mWindowMap) {
4984 focus = getFocusedWindowLocked();
4985 }
Romain Guy06882f82009-06-10 13:36:04 -07004986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004987 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
Romain Guy06882f82009-06-10 13:36:04 -07004988
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004989 if (callingUid == 0 ||
4990 (focus != null && callingUid == focus.mSession.mUid) ||
4991 mContext.checkPermission(
4992 android.Manifest.permission.INJECT_EVENTS,
4993 callingPid, callingUid)
4994 == PackageManager.PERMISSION_GRANTED) {
4995 if (mPolicy.interceptKeyTi(focus,
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07004996 keycode, nextKey.getMetaState(), down, repeatCount,
4997 nextKey.getFlags())) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004998 return CONSUMED_EVENT_TOKEN;
4999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005000 }
Romain Guy06882f82009-06-10 13:36:04 -07005001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002 return focus;
Romain Guy06882f82009-06-10 13:36:04 -07005003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005004 } else if (!isPointerEvent) {
5005 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
5006 if (!dispatch) {
5007 Log.w(TAG, "Event timeout during app switch: dropping trackball "
5008 + nextMotion);
5009 return SKIP_TARGET_TOKEN;
5010 }
Romain Guy06882f82009-06-10 13:36:04 -07005011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005012 WindowState focus = null;
5013 synchronized(mWindowMap) {
5014 focus = getFocusedWindowLocked();
5015 }
Romain Guy06882f82009-06-10 13:36:04 -07005016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005017 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
5018 return focus;
5019 }
Romain Guy06882f82009-06-10 13:36:04 -07005020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005021 if (nextMotion == null) {
5022 return SKIP_TARGET_TOKEN;
5023 }
Romain Guy06882f82009-06-10 13:36:04 -07005024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005025 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
5026 KeyEvent.KEYCODE_UNKNOWN);
5027 if (!dispatch) {
5028 Log.w(TAG, "Event timeout during app switch: dropping pointer "
5029 + nextMotion);
5030 return SKIP_TARGET_TOKEN;
5031 }
Romain Guy06882f82009-06-10 13:36:04 -07005032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005033 // Find the target window for a pointer event.
5034 int action = nextMotion.getAction();
5035 final float xf = nextMotion.getX();
5036 final float yf = nextMotion.getY();
5037 final long eventTime = nextMotion.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07005038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005039 final boolean screenWasOff = qev != null
5040 && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07005041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005042 WindowState target = null;
Romain Guy06882f82009-06-10 13:36:04 -07005043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005044 synchronized(mWindowMap) {
5045 synchronized (this) {
5046 if (action == MotionEvent.ACTION_DOWN) {
5047 if (mMotionTarget != null) {
5048 // this is weird, we got a pen down, but we thought it was
5049 // already down!
5050 // XXX: We should probably send an ACTION_UP to the current
5051 // target.
5052 Log.w(TAG, "Pointer down received while already down in: "
5053 + mMotionTarget);
5054 mMotionTarget = null;
5055 }
Romain Guy06882f82009-06-10 13:36:04 -07005056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005057 // ACTION_DOWN is special, because we need to lock next events to
5058 // the window we'll land onto.
5059 final int x = (int)xf;
5060 final int y = (int)yf;
Romain Guy06882f82009-06-10 13:36:04 -07005061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005062 final ArrayList windows = mWindows;
5063 final int N = windows.size();
5064 WindowState topErrWindow = null;
5065 final Rect tmpRect = mTempRect;
5066 for (int i=N-1; i>=0; i--) {
5067 WindowState child = (WindowState)windows.get(i);
5068 //Log.i(TAG, "Checking dispatch to: " + child);
5069 final int flags = child.mAttrs.flags;
5070 if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
5071 if (topErrWindow == null) {
5072 topErrWindow = child;
5073 }
5074 }
5075 if (!child.isVisibleLw()) {
5076 //Log.i(TAG, "Not visible!");
5077 continue;
5078 }
5079 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
5080 //Log.i(TAG, "Not touchable!");
5081 if ((flags & WindowManager.LayoutParams
5082 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
5083 child.mNextOutsideTouch = mOutsideTouchTargets;
5084 mOutsideTouchTargets = child;
5085 }
5086 continue;
5087 }
5088 tmpRect.set(child.mFrame);
5089 if (child.mTouchableInsets == ViewTreeObserver
5090 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
5091 // The touch is inside of the window if it is
5092 // inside the frame, AND the content part of that
5093 // frame that was given by the application.
5094 tmpRect.left += child.mGivenContentInsets.left;
5095 tmpRect.top += child.mGivenContentInsets.top;
5096 tmpRect.right -= child.mGivenContentInsets.right;
5097 tmpRect.bottom -= child.mGivenContentInsets.bottom;
5098 } else if (child.mTouchableInsets == ViewTreeObserver
5099 .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
5100 // The touch is inside of the window if it is
5101 // inside the frame, AND the visible part of that
5102 // frame that was given by the application.
5103 tmpRect.left += child.mGivenVisibleInsets.left;
5104 tmpRect.top += child.mGivenVisibleInsets.top;
5105 tmpRect.right -= child.mGivenVisibleInsets.right;
5106 tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
5107 }
5108 final int touchFlags = flags &
5109 (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
5110 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
5111 if (tmpRect.contains(x, y) || touchFlags == 0) {
5112 //Log.i(TAG, "Using this target!");
5113 if (!screenWasOff || (flags &
5114 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
5115 mMotionTarget = child;
5116 } else {
5117 //Log.i(TAG, "Waking, skip!");
5118 mMotionTarget = null;
5119 }
5120 break;
5121 }
Romain Guy06882f82009-06-10 13:36:04 -07005122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005123 if ((flags & WindowManager.LayoutParams
5124 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
5125 child.mNextOutsideTouch = mOutsideTouchTargets;
5126 mOutsideTouchTargets = child;
5127 //Log.i(TAG, "Adding to outside target list: " + child);
5128 }
5129 }
5130
5131 // if there's an error window but it's not accepting
5132 // focus (typically because it is not yet visible) just
5133 // wait for it -- any other focused window may in fact
5134 // be in ANR state.
5135 if (topErrWindow != null && mMotionTarget != topErrWindow) {
5136 mMotionTarget = null;
5137 }
5138 }
Romain Guy06882f82009-06-10 13:36:04 -07005139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140 target = mMotionTarget;
5141 }
5142 }
Romain Guy06882f82009-06-10 13:36:04 -07005143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005144 wakeupIfNeeded(target, eventType(nextMotion));
Romain Guy06882f82009-06-10 13:36:04 -07005145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005146 // Pointer events are a little different -- if there isn't a
5147 // target found for any event, then just drop it.
5148 return target != null ? target : SKIP_TARGET_TOKEN;
5149 }
Romain Guy06882f82009-06-10 13:36:04 -07005150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005151 boolean checkShouldDispatchKey(int keycode) {
5152 synchronized (this) {
5153 if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
5154 mTimeToSwitch = 0;
5155 return true;
5156 }
5157 if (mTimeToSwitch != 0
5158 && mTimeToSwitch < SystemClock.uptimeMillis()) {
5159 return false;
5160 }
5161 return true;
5162 }
5163 }
Romain Guy06882f82009-06-10 13:36:04 -07005164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005165 void bindTargetWindowLocked(WindowState win,
5166 int pendingWhat, QueuedEvent pendingMotion) {
5167 synchronized (this) {
5168 bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
5169 }
5170 }
Romain Guy06882f82009-06-10 13:36:04 -07005171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005172 void bindTargetWindowLocked(WindowState win) {
5173 synchronized (this) {
5174 bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
5175 }
5176 }
5177
5178 void bindTargetWindowLockedLocked(WindowState win,
5179 int pendingWhat, QueuedEvent pendingMotion) {
5180 mLastWin = win;
5181 mLastBinder = win.mClient.asBinder();
5182 mFinished = false;
5183 if (pendingMotion != null) {
5184 final Session s = win.mSession;
5185 if (pendingWhat == RETURN_PENDING_POINTER) {
5186 releasePendingPointerLocked(s);
5187 s.mPendingPointerMove = pendingMotion;
5188 s.mPendingPointerWindow = win;
Romain Guy06882f82009-06-10 13:36:04 -07005189 if (DEBUG_INPUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005190 "bindTargetToWindow " + s.mPendingPointerMove);
5191 } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
5192 releasePendingTrackballLocked(s);
5193 s.mPendingTrackballMove = pendingMotion;
5194 s.mPendingTrackballWindow = win;
5195 }
5196 }
5197 }
Romain Guy06882f82009-06-10 13:36:04 -07005198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 void releasePendingPointerLocked(Session s) {
5200 if (DEBUG_INPUT) Log.v(TAG,
5201 "releasePendingPointer " + s.mPendingPointerMove);
5202 if (s.mPendingPointerMove != null) {
5203 mQueue.recycleEvent(s.mPendingPointerMove);
5204 s.mPendingPointerMove = null;
5205 }
5206 }
Romain Guy06882f82009-06-10 13:36:04 -07005207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 void releasePendingTrackballLocked(Session s) {
5209 if (s.mPendingTrackballMove != null) {
5210 mQueue.recycleEvent(s.mPendingTrackballMove);
5211 s.mPendingTrackballMove = null;
5212 }
5213 }
Romain Guy06882f82009-06-10 13:36:04 -07005214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005215 MotionEvent finishedKey(Session session, IWindow client, boolean force,
5216 int returnWhat) {
5217 if (DEBUG_INPUT) Log.v(
5218 TAG, "finishedKey: client=" + client + ", force=" + force);
5219
5220 if (client == null) {
5221 return null;
5222 }
5223
5224 synchronized (this) {
5225 if (DEBUG_INPUT) Log.v(
5226 TAG, "finishedKey: client=" + client.asBinder()
5227 + ", force=" + force + ", last=" + mLastBinder
5228 + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
5229
5230 QueuedEvent qev = null;
5231 WindowState win = null;
5232 if (returnWhat == RETURN_PENDING_POINTER) {
5233 qev = session.mPendingPointerMove;
5234 win = session.mPendingPointerWindow;
5235 session.mPendingPointerMove = null;
5236 session.mPendingPointerWindow = null;
5237 } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
5238 qev = session.mPendingTrackballMove;
5239 win = session.mPendingTrackballWindow;
5240 session.mPendingTrackballMove = null;
5241 session.mPendingTrackballWindow = null;
5242 }
Romain Guy06882f82009-06-10 13:36:04 -07005243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005244 if (mLastBinder == client.asBinder()) {
5245 if (DEBUG_INPUT) Log.v(
5246 TAG, "finishedKey: last paused="
5247 + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
5248 if (mLastWin != null && (!mLastWin.mToken.paused || force
5249 || !mEventDispatching)) {
5250 doFinishedKeyLocked(false);
5251 } else {
5252 // Make sure to wake up anyone currently waiting to
5253 // dispatch a key, so they can re-evaluate their
5254 // current situation.
5255 mFinished = true;
5256 notifyAll();
5257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005258 }
Romain Guy06882f82009-06-10 13:36:04 -07005259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005260 if (qev != null) {
5261 MotionEvent res = (MotionEvent)qev.event;
5262 if (DEBUG_INPUT) Log.v(TAG,
5263 "Returning pending motion: " + res);
5264 mQueue.recycleEvent(qev);
5265 if (win != null && returnWhat == RETURN_PENDING_POINTER) {
5266 res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
5267 }
5268 return res;
5269 }
5270 return null;
5271 }
5272 }
5273
5274 void tickle() {
5275 synchronized (this) {
5276 notifyAll();
5277 }
5278 }
Romain Guy06882f82009-06-10 13:36:04 -07005279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005280 void handleNewWindowLocked(WindowState newWindow) {
5281 if (!newWindow.canReceiveKeys()) {
5282 return;
5283 }
5284 synchronized (this) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005285 if (DEBUG_INPUT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 TAG, "New key dispatch window: win="
5287 + newWindow.mClient.asBinder()
5288 + ", last=" + mLastBinder
5289 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
5290 + "), finished=" + mFinished + ", paused="
5291 + newWindow.mToken.paused);
5292
5293 // Displaying a window implicitly causes dispatching to
5294 // be unpaused. (This is to protect against bugs if someone
5295 // pauses dispatching but forgets to resume.)
5296 newWindow.mToken.paused = false;
5297
5298 mGotFirstWindow = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005299
5300 if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
5301 if (DEBUG_INPUT) Log.v(TAG,
5302 "New SYSTEM_ERROR window; resetting state");
5303 mLastWin = null;
5304 mLastBinder = null;
5305 mMotionTarget = null;
5306 mFinished = true;
5307 } else if (mLastWin != null) {
5308 // If the new window is above the window we are
5309 // waiting on, then stop waiting and let key dispatching
5310 // start on the new guy.
5311 if (DEBUG_INPUT) Log.v(
5312 TAG, "Last win layer=" + mLastWin.mLayer
5313 + ", new win layer=" + newWindow.mLayer);
5314 if (newWindow.mLayer >= mLastWin.mLayer) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005315 // The new window is above the old; finish pending input to the last
5316 // window and start directing it to the new one.
5317 mLastWin.mToken.paused = false;
5318 doFinishedKeyLocked(true); // does a notifyAll()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005319 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005320 // Either the new window is lower, so there is no need to wake key waiters,
5321 // or we just finished key input to the previous window, which implicitly
5322 // notified the key waiters. In both cases, we don't need to issue the
5323 // notification here.
5324 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005325 }
5326
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005327 // Now that we've put a new window state in place, make the event waiter
5328 // take notice and retarget its attentions.
5329 notifyAll();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005330 }
5331 }
5332
5333 void pauseDispatchingLocked(WindowToken token) {
5334 synchronized (this)
5335 {
5336 if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
5337 token.paused = true;
5338
5339 /*
5340 if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
5341 mPaused = true;
5342 } else {
5343 if (mLastWin == null) {
Dave Bortcfe65242009-04-09 14:51:04 -07005344 Log.i(TAG, "Key dispatching not paused: no last window.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005345 } else if (mFinished) {
Dave Bortcfe65242009-04-09 14:51:04 -07005346 Log.i(TAG, "Key dispatching not paused: finished last key.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005347 } else {
Dave Bortcfe65242009-04-09 14:51:04 -07005348 Log.i(TAG, "Key dispatching not paused: window in higher layer.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005349 }
5350 }
5351 */
5352 }
5353 }
5354
5355 void resumeDispatchingLocked(WindowToken token) {
5356 synchronized (this) {
5357 if (token.paused) {
5358 if (DEBUG_INPUT) Log.v(
5359 TAG, "Resuming WindowToken " + token
5360 + ", last=" + mLastBinder
5361 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
5362 + "), finished=" + mFinished + ", paused="
5363 + token.paused);
5364 token.paused = false;
5365 if (mLastWin != null && mLastWin.mToken == token && mFinished) {
5366 doFinishedKeyLocked(true);
5367 } else {
5368 notifyAll();
5369 }
5370 }
5371 }
5372 }
5373
5374 void setEventDispatchingLocked(boolean enabled) {
5375 synchronized (this) {
5376 mEventDispatching = enabled;
5377 notifyAll();
5378 }
5379 }
Romain Guy06882f82009-06-10 13:36:04 -07005380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005381 void appSwitchComing() {
5382 synchronized (this) {
5383 // Don't wait for more than .5 seconds for app to finish
5384 // processing the pending events.
5385 long now = SystemClock.uptimeMillis() + 500;
5386 if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now);
5387 if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
5388 mTimeToSwitch = now;
5389 }
5390 notifyAll();
5391 }
5392 }
Romain Guy06882f82009-06-10 13:36:04 -07005393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 private final void doFinishedKeyLocked(boolean doRecycle) {
5395 if (mLastWin != null) {
5396 releasePendingPointerLocked(mLastWin.mSession);
5397 releasePendingTrackballLocked(mLastWin.mSession);
5398 }
Romain Guy06882f82009-06-10 13:36:04 -07005399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005400 if (mLastWin == null || !mLastWin.mToken.paused
5401 || !mLastWin.isVisibleLw()) {
5402 // If the current window has been paused, we aren't -really-
5403 // finished... so let the waiters still wait.
5404 mLastWin = null;
5405 mLastBinder = null;
5406 }
5407 mFinished = true;
5408 notifyAll();
5409 }
5410 }
5411
5412 private class KeyQ extends KeyInputQueue
5413 implements KeyInputQueue.FilterCallback {
5414 PowerManager.WakeLock mHoldingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07005415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005416 KeyQ() {
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07005417 super(mContext, WindowManagerService.this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005418 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
5419 mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
5420 "KEEP_SCREEN_ON_FLAG");
5421 mHoldingScreen.setReferenceCounted(false);
5422 }
5423
5424 @Override
5425 boolean preprocessEvent(InputDevice device, RawInputEvent event) {
5426 if (mPolicy.preprocessInputEventTq(event)) {
5427 return true;
5428 }
Romain Guy06882f82009-06-10 13:36:04 -07005429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005430 switch (event.type) {
5431 case RawInputEvent.EV_KEY: {
5432 // XXX begin hack
5433 if (DEBUG) {
5434 if (event.keycode == KeyEvent.KEYCODE_G) {
5435 if (event.value != 0) {
5436 // G down
5437 mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
5438 }
5439 return false;
5440 }
5441 if (event.keycode == KeyEvent.KEYCODE_D) {
5442 if (event.value != 0) {
5443 //dump();
5444 }
5445 return false;
5446 }
5447 }
5448 // XXX end hack
Romain Guy06882f82009-06-10 13:36:04 -07005449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005450 boolean screenIsOff = !mPowerManager.screenIsOn();
5451 boolean screenIsDim = !mPowerManager.screenIsBright();
5452 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
Romain Guy06882f82009-06-10 13:36:04 -07005453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005454 if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
5455 mPowerManager.goToSleep(event.when);
5456 }
5457
5458 if (screenIsOff) {
5459 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5460 }
5461 if (screenIsDim) {
5462 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5463 }
5464 if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
5465 mPowerManager.userActivity(event.when, false,
Michael Chane96440f2009-05-06 10:27:36 -07005466 LocalPowerManager.BUTTON_EVENT, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005467 }
Romain Guy06882f82009-06-10 13:36:04 -07005468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005469 if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
5470 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
5471 filterQueue(this);
5472 mKeyWaiter.appSwitchComing();
5473 }
5474 return true;
5475 } else {
5476 return false;
5477 }
5478 }
Romain Guy06882f82009-06-10 13:36:04 -07005479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 case RawInputEvent.EV_REL: {
5481 boolean screenIsOff = !mPowerManager.screenIsOn();
5482 boolean screenIsDim = !mPowerManager.screenIsBright();
5483 if (screenIsOff) {
5484 if (!mPolicy.isWakeRelMovementTq(event.deviceId,
5485 device.classes, event)) {
5486 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5487 return false;
5488 }
5489 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5490 }
5491 if (screenIsDim) {
5492 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5493 }
5494 return true;
5495 }
Romain Guy06882f82009-06-10 13:36:04 -07005496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005497 case RawInputEvent.EV_ABS: {
5498 boolean screenIsOff = !mPowerManager.screenIsOn();
5499 boolean screenIsDim = !mPowerManager.screenIsBright();
5500 if (screenIsOff) {
5501 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
5502 device.classes, event)) {
5503 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5504 return false;
5505 }
5506 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5507 }
5508 if (screenIsDim) {
5509 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5510 }
5511 return true;
5512 }
Romain Guy06882f82009-06-10 13:36:04 -07005513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005514 default:
5515 return true;
5516 }
5517 }
5518
5519 public int filterEvent(QueuedEvent ev) {
5520 switch (ev.classType) {
5521 case RawInputEvent.CLASS_KEYBOARD:
5522 KeyEvent ke = (KeyEvent)ev.event;
5523 if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
5524 Log.w(TAG, "Dropping movement key during app switch: "
5525 + ke.getKeyCode() + ", action=" + ke.getAction());
5526 return FILTER_REMOVE;
5527 }
5528 return FILTER_ABORT;
5529 default:
5530 return FILTER_KEEP;
5531 }
5532 }
Romain Guy06882f82009-06-10 13:36:04 -07005533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005534 /**
5535 * Must be called with the main window manager lock held.
5536 */
5537 void setHoldScreenLocked(boolean holding) {
5538 boolean state = mHoldingScreen.isHeld();
5539 if (holding != state) {
5540 if (holding) {
5541 mHoldingScreen.acquire();
5542 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005543 mPolicy.screenOnStoppedLw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005544 mHoldingScreen.release();
5545 }
5546 }
5547 }
Michael Chan53071d62009-05-13 17:29:48 -07005548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005549
5550 public boolean detectSafeMode() {
5551 mSafeMode = mPolicy.detectSafeMode();
5552 return mSafeMode;
5553 }
Romain Guy06882f82009-06-10 13:36:04 -07005554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005555 public void systemReady() {
5556 mPolicy.systemReady();
5557 }
Romain Guy06882f82009-06-10 13:36:04 -07005558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005559 private final class InputDispatcherThread extends Thread {
5560 // Time to wait when there is nothing to do: 9999 seconds.
5561 static final int LONG_WAIT=9999*1000;
5562
5563 public InputDispatcherThread() {
5564 super("InputDispatcher");
5565 }
Romain Guy06882f82009-06-10 13:36:04 -07005566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005567 @Override
5568 public void run() {
5569 while (true) {
5570 try {
5571 process();
5572 } catch (Exception e) {
5573 Log.e(TAG, "Exception in input dispatcher", e);
5574 }
5575 }
5576 }
Romain Guy06882f82009-06-10 13:36:04 -07005577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005578 private void process() {
5579 android.os.Process.setThreadPriority(
5580 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -07005581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005582 // The last key event we saw
5583 KeyEvent lastKey = null;
5584
5585 // Last keydown time for auto-repeating keys
5586 long lastKeyTime = SystemClock.uptimeMillis();
5587 long nextKeyTime = lastKeyTime+LONG_WAIT;
5588
Romain Guy06882f82009-06-10 13:36:04 -07005589 // How many successive repeats we generated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005590 int keyRepeatCount = 0;
5591
5592 // Need to report that configuration has changed?
5593 boolean configChanged = false;
Romain Guy06882f82009-06-10 13:36:04 -07005594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005595 while (true) {
5596 long curTime = SystemClock.uptimeMillis();
5597
5598 if (DEBUG_INPUT) Log.v(
5599 TAG, "Waiting for next key: now=" + curTime
5600 + ", repeat @ " + nextKeyTime);
5601
5602 // Retrieve next event, waiting only as long as the next
5603 // repeat timeout. If the configuration has changed, then
5604 // don't wait at all -- we'll report the change as soon as
5605 // we have processed all events.
5606 QueuedEvent ev = mQueue.getEvent(
5607 (int)((!configChanged && curTime < nextKeyTime)
5608 ? (nextKeyTime-curTime) : 0));
5609
5610 if (DEBUG_INPUT && ev != null) Log.v(
5611 TAG, "Event: type=" + ev.classType + " data=" + ev.event);
5612
Michael Chan53071d62009-05-13 17:29:48 -07005613 if (MEASURE_LATENCY) {
5614 lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
5615 }
5616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005617 try {
5618 if (ev != null) {
Michael Chan53071d62009-05-13 17:29:48 -07005619 curTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005620 int eventType;
5621 if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
5622 eventType = eventType((MotionEvent)ev.event);
5623 } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
5624 ev.classType == RawInputEvent.CLASS_TRACKBALL) {
5625 eventType = LocalPowerManager.BUTTON_EVENT;
5626 } else {
5627 eventType = LocalPowerManager.OTHER_EVENT;
5628 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005629 try {
Michael Chan53071d62009-05-13 17:29:48 -07005630 if ((curTime - mLastBatteryStatsCallTime)
Michael Chane96440f2009-05-06 10:27:36 -07005631 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
Michael Chan53071d62009-05-13 17:29:48 -07005632 mLastBatteryStatsCallTime = curTime;
Michael Chane96440f2009-05-06 10:27:36 -07005633 mBatteryStats.noteInputEvent();
5634 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005635 } catch (RemoteException e) {
5636 // Ignore
5637 }
Michael Chane10de972009-05-18 11:24:50 -07005638
5639 if (eventType != TOUCH_EVENT
5640 && eventType != LONG_TOUCH_EVENT
5641 && eventType != CHEEK_EVENT) {
5642 mPowerManager.userActivity(curTime, false,
5643 eventType, false);
5644 } else if (mLastTouchEventType != eventType
5645 || (curTime - mLastUserActivityCallTime)
5646 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
5647 mLastUserActivityCallTime = curTime;
5648 mLastTouchEventType = eventType;
5649 mPowerManager.userActivity(curTime, false,
5650 eventType, false);
5651 }
5652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005653 switch (ev.classType) {
5654 case RawInputEvent.CLASS_KEYBOARD:
5655 KeyEvent ke = (KeyEvent)ev.event;
5656 if (ke.isDown()) {
5657 lastKey = ke;
5658 keyRepeatCount = 0;
5659 lastKeyTime = curTime;
5660 nextKeyTime = lastKeyTime
5661 + KEY_REPEAT_FIRST_DELAY;
5662 if (DEBUG_INPUT) Log.v(
5663 TAG, "Received key down: first repeat @ "
5664 + nextKeyTime);
5665 } else {
5666 lastKey = null;
5667 // Arbitrary long timeout.
5668 lastKeyTime = curTime;
5669 nextKeyTime = curTime + LONG_WAIT;
5670 if (DEBUG_INPUT) Log.v(
5671 TAG, "Received key up: ignore repeat @ "
5672 + nextKeyTime);
5673 }
5674 dispatchKey((KeyEvent)ev.event, 0, 0);
5675 mQueue.recycleEvent(ev);
5676 break;
5677 case RawInputEvent.CLASS_TOUCHSCREEN:
5678 //Log.i(TAG, "Read next event " + ev);
5679 dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
5680 break;
5681 case RawInputEvent.CLASS_TRACKBALL:
5682 dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
5683 break;
5684 case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
5685 configChanged = true;
5686 break;
5687 default:
5688 mQueue.recycleEvent(ev);
5689 break;
5690 }
Romain Guy06882f82009-06-10 13:36:04 -07005691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005692 } else if (configChanged) {
5693 configChanged = false;
5694 sendNewConfiguration();
Romain Guy06882f82009-06-10 13:36:04 -07005695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005696 } else if (lastKey != null) {
5697 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005699 // Timeout occurred while key was down. If it is at or
5700 // past the key repeat time, dispatch the repeat.
5701 if (DEBUG_INPUT) Log.v(
5702 TAG, "Key timeout: repeat=" + nextKeyTime
5703 + ", now=" + curTime);
5704 if (curTime < nextKeyTime) {
5705 continue;
5706 }
Romain Guy06882f82009-06-10 13:36:04 -07005707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005708 lastKeyTime = nextKeyTime;
5709 nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
5710 keyRepeatCount++;
5711 if (DEBUG_INPUT) Log.v(
5712 TAG, "Key repeat: count=" + keyRepeatCount
5713 + ", next @ " + nextKeyTime);
The Android Open Source Project10592532009-03-18 17:39:46 -07005714 dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
Romain Guy06882f82009-06-10 13:36:04 -07005715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005716 } else {
5717 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005719 lastKeyTime = curTime;
5720 nextKeyTime = curTime + LONG_WAIT;
5721 }
Romain Guy06882f82009-06-10 13:36:04 -07005722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005723 } catch (Exception e) {
5724 Log.e(TAG,
5725 "Input thread received uncaught exception: " + e, e);
5726 }
5727 }
5728 }
5729 }
5730
5731 // -------------------------------------------------------------
5732 // Client Session State
5733 // -------------------------------------------------------------
5734
5735 private final class Session extends IWindowSession.Stub
5736 implements IBinder.DeathRecipient {
5737 final IInputMethodClient mClient;
5738 final IInputContext mInputContext;
5739 final int mUid;
5740 final int mPid;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005741 final String mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 SurfaceSession mSurfaceSession;
5743 int mNumWindow = 0;
5744 boolean mClientDead = false;
Romain Guy06882f82009-06-10 13:36:04 -07005745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005746 /**
5747 * Current pointer move event being dispatched to client window... must
5748 * hold key lock to access.
5749 */
5750 QueuedEvent mPendingPointerMove;
5751 WindowState mPendingPointerWindow;
Romain Guy06882f82009-06-10 13:36:04 -07005752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005753 /**
5754 * Current trackball move event being dispatched to client window... must
5755 * hold key lock to access.
5756 */
5757 QueuedEvent mPendingTrackballMove;
5758 WindowState mPendingTrackballWindow;
5759
5760 public Session(IInputMethodClient client, IInputContext inputContext) {
5761 mClient = client;
5762 mInputContext = inputContext;
5763 mUid = Binder.getCallingUid();
5764 mPid = Binder.getCallingPid();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005765 StringBuilder sb = new StringBuilder();
5766 sb.append("Session{");
5767 sb.append(Integer.toHexString(System.identityHashCode(this)));
5768 sb.append(" uid ");
5769 sb.append(mUid);
5770 sb.append("}");
5771 mStringName = sb.toString();
Romain Guy06882f82009-06-10 13:36:04 -07005772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005773 synchronized (mWindowMap) {
5774 if (mInputMethodManager == null && mHaveInputMethods) {
5775 IBinder b = ServiceManager.getService(
5776 Context.INPUT_METHOD_SERVICE);
5777 mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
5778 }
5779 }
5780 long ident = Binder.clearCallingIdentity();
5781 try {
5782 // Note: it is safe to call in to the input method manager
5783 // here because we are not holding our lock.
5784 if (mInputMethodManager != null) {
5785 mInputMethodManager.addClient(client, inputContext,
5786 mUid, mPid);
5787 } else {
5788 client.setUsingInputMethod(false);
5789 }
5790 client.asBinder().linkToDeath(this, 0);
5791 } catch (RemoteException e) {
5792 // The caller has died, so we can just forget about this.
5793 try {
5794 if (mInputMethodManager != null) {
5795 mInputMethodManager.removeClient(client);
5796 }
5797 } catch (RemoteException ee) {
5798 }
5799 } finally {
5800 Binder.restoreCallingIdentity(ident);
5801 }
5802 }
Romain Guy06882f82009-06-10 13:36:04 -07005803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005804 @Override
5805 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5806 throws RemoteException {
5807 try {
5808 return super.onTransact(code, data, reply, flags);
5809 } catch (RuntimeException e) {
5810 // Log all 'real' exceptions thrown to the caller
5811 if (!(e instanceof SecurityException)) {
5812 Log.e(TAG, "Window Session Crash", e);
5813 }
5814 throw e;
5815 }
5816 }
5817
5818 public void binderDied() {
5819 // Note: it is safe to call in to the input method manager
5820 // here because we are not holding our lock.
5821 try {
5822 if (mInputMethodManager != null) {
5823 mInputMethodManager.removeClient(mClient);
5824 }
5825 } catch (RemoteException e) {
5826 }
5827 synchronized(mWindowMap) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07005828 mClient.asBinder().unlinkToDeath(this, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005829 mClientDead = true;
5830 killSessionLocked();
5831 }
5832 }
5833
5834 public int add(IWindow window, WindowManager.LayoutParams attrs,
5835 int viewVisibility, Rect outContentInsets) {
5836 return addWindow(this, window, attrs, viewVisibility, outContentInsets);
5837 }
Romain Guy06882f82009-06-10 13:36:04 -07005838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005839 public void remove(IWindow window) {
5840 removeWindow(this, window);
5841 }
Romain Guy06882f82009-06-10 13:36:04 -07005842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005843 public int relayout(IWindow window, WindowManager.LayoutParams attrs,
5844 int requestedWidth, int requestedHeight, int viewFlags,
5845 boolean insetsPending, Rect outFrame, Rect outContentInsets,
5846 Rect outVisibleInsets, Surface outSurface) {
5847 return relayoutWindow(this, window, attrs,
5848 requestedWidth, requestedHeight, viewFlags, insetsPending,
5849 outFrame, outContentInsets, outVisibleInsets, outSurface);
5850 }
Romain Guy06882f82009-06-10 13:36:04 -07005851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005852 public void setTransparentRegion(IWindow window, Region region) {
5853 setTransparentRegionWindow(this, window, region);
5854 }
Romain Guy06882f82009-06-10 13:36:04 -07005855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005856 public void setInsets(IWindow window, int touchableInsets,
5857 Rect contentInsets, Rect visibleInsets) {
5858 setInsetsWindow(this, window, touchableInsets, contentInsets,
5859 visibleInsets);
5860 }
Romain Guy06882f82009-06-10 13:36:04 -07005861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005862 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
5863 getWindowDisplayFrame(this, window, outDisplayFrame);
5864 }
Romain Guy06882f82009-06-10 13:36:04 -07005865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005866 public void finishDrawing(IWindow window) {
5867 if (localLOGV) Log.v(
5868 TAG, "IWindow finishDrawing called for " + window);
5869 finishDrawingWindow(this, window);
5870 }
5871
5872 public void finishKey(IWindow window) {
5873 if (localLOGV) Log.v(
5874 TAG, "IWindow finishKey called for " + window);
5875 mKeyWaiter.finishedKey(this, window, false,
5876 KeyWaiter.RETURN_NOTHING);
5877 }
5878
5879 public MotionEvent getPendingPointerMove(IWindow window) {
5880 if (localLOGV) Log.v(
5881 TAG, "IWindow getPendingMotionEvent called for " + window);
5882 return mKeyWaiter.finishedKey(this, window, false,
5883 KeyWaiter.RETURN_PENDING_POINTER);
5884 }
Romain Guy06882f82009-06-10 13:36:04 -07005885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005886 public MotionEvent getPendingTrackballMove(IWindow window) {
5887 if (localLOGV) Log.v(
5888 TAG, "IWindow getPendingMotionEvent called for " + window);
5889 return mKeyWaiter.finishedKey(this, window, false,
5890 KeyWaiter.RETURN_PENDING_TRACKBALL);
5891 }
5892
5893 public void setInTouchMode(boolean mode) {
5894 synchronized(mWindowMap) {
5895 mInTouchMode = mode;
5896 }
5897 }
5898
5899 public boolean getInTouchMode() {
5900 synchronized(mWindowMap) {
5901 return mInTouchMode;
5902 }
5903 }
5904
5905 public boolean performHapticFeedback(IWindow window, int effectId,
5906 boolean always) {
5907 synchronized(mWindowMap) {
5908 long ident = Binder.clearCallingIdentity();
5909 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005910 return mPolicy.performHapticFeedbackLw(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005911 windowForClientLocked(this, window), effectId, always);
5912 } finally {
5913 Binder.restoreCallingIdentity(ident);
5914 }
5915 }
5916 }
Romain Guy06882f82009-06-10 13:36:04 -07005917
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07005918 public void setWallpaperPosition(IBinder window, float x, float y) {
5919 synchronized(mWindowMap) {
5920 long ident = Binder.clearCallingIdentity();
5921 try {
5922 setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
5923 x, y);
5924 } finally {
5925 Binder.restoreCallingIdentity(ident);
5926 }
5927 }
5928 }
5929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005930 void windowAddedLocked() {
5931 if (mSurfaceSession == null) {
5932 if (localLOGV) Log.v(
5933 TAG, "First window added to " + this + ", creating SurfaceSession");
5934 mSurfaceSession = new SurfaceSession();
5935 mSessions.add(this);
5936 }
5937 mNumWindow++;
5938 }
5939
5940 void windowRemovedLocked() {
5941 mNumWindow--;
5942 killSessionLocked();
5943 }
Romain Guy06882f82009-06-10 13:36:04 -07005944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005945 void killSessionLocked() {
5946 if (mNumWindow <= 0 && mClientDead) {
5947 mSessions.remove(this);
5948 if (mSurfaceSession != null) {
5949 if (localLOGV) Log.v(
5950 TAG, "Last window removed from " + this
5951 + ", destroying " + mSurfaceSession);
5952 try {
5953 mSurfaceSession.kill();
5954 } catch (Exception e) {
5955 Log.w(TAG, "Exception thrown when killing surface session "
5956 + mSurfaceSession + " in session " + this
5957 + ": " + e.toString());
5958 }
5959 mSurfaceSession = null;
5960 }
5961 }
5962 }
Romain Guy06882f82009-06-10 13:36:04 -07005963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005964 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005965 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
5966 pw.print(" mClientDead="); pw.print(mClientDead);
5967 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
5968 if (mPendingPointerWindow != null || mPendingPointerMove != null) {
5969 pw.print(prefix);
5970 pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
5971 pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
5972 }
5973 if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
5974 pw.print(prefix);
5975 pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
5976 pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
5977 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005978 }
5979
5980 @Override
5981 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005982 return mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005983 }
5984 }
5985
5986 // -------------------------------------------------------------
5987 // Client Window State
5988 // -------------------------------------------------------------
5989
5990 private final class WindowState implements WindowManagerPolicy.WindowState {
5991 final Session mSession;
5992 final IWindow mClient;
5993 WindowToken mToken;
The Android Open Source Project10592532009-03-18 17:39:46 -07005994 WindowToken mRootToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005995 AppWindowToken mAppToken;
5996 AppWindowToken mTargetAppToken;
5997 final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
5998 final DeathRecipient mDeathRecipient;
5999 final WindowState mAttachedWindow;
6000 final ArrayList mChildWindows = new ArrayList();
6001 final int mBaseLayer;
6002 final int mSubLayer;
6003 final boolean mLayoutAttached;
6004 final boolean mIsImWindow;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07006005 final boolean mIsWallpaper;
6006 final boolean mIsFloatingLayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006007 int mViewVisibility;
6008 boolean mPolicyVisibility = true;
6009 boolean mPolicyVisibilityAfterAnim = true;
6010 boolean mAppFreezing;
6011 Surface mSurface;
6012 boolean mAttachedHidden; // is our parent window hidden?
6013 boolean mLastHidden; // was this window last hidden?
Dianne Hackborn759a39e2009-08-09 17:20:27 -07006014 boolean mWallpaperVisible; // for wallpaper, what was last vis report?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006015 int mRequestedWidth;
6016 int mRequestedHeight;
6017 int mLastRequestedWidth;
6018 int mLastRequestedHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006019 int mLayer;
6020 int mAnimLayer;
6021 int mLastLayer;
6022 boolean mHaveFrame;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07006023 boolean mObscured;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006024
6025 WindowState mNextOutsideTouch;
Romain Guy06882f82009-06-10 13:36:04 -07006026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006027 // Actual frame shown on-screen (may be modified by animation)
6028 final Rect mShownFrame = new Rect();
6029 final Rect mLastShownFrame = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07006030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006031 /**
6032 * Insets that determine the actually visible area
6033 */
6034 final Rect mVisibleInsets = new Rect();
6035 final Rect mLastVisibleInsets = new Rect();
6036 boolean mVisibleInsetsChanged;
6037
6038 /**
6039 * Insets that are covered by system windows
6040 */
6041 final Rect mContentInsets = new Rect();
6042 final Rect mLastContentInsets = new Rect();
6043 boolean mContentInsetsChanged;
6044
6045 /**
6046 * Set to true if we are waiting for this window to receive its
6047 * given internal insets before laying out other windows based on it.
6048 */
6049 boolean mGivenInsetsPending;
Romain Guy06882f82009-06-10 13:36:04 -07006050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006051 /**
6052 * These are the content insets that were given during layout for
6053 * this window, to be applied to windows behind it.
6054 */
6055 final Rect mGivenContentInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07006056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006057 /**
6058 * These are the visible insets that were given during layout for
6059 * this window, to be applied to windows behind it.
6060 */
6061 final Rect mGivenVisibleInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07006062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006063 /**
6064 * Flag indicating whether the touchable region should be adjusted by
6065 * the visible insets; if false the area outside the visible insets is
6066 * NOT touchable, so we must use those to adjust the frame during hit
6067 * tests.
6068 */
6069 int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
Romain Guy06882f82009-06-10 13:36:04 -07006070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006071 // Current transformation being applied.
6072 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
6073 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
6074 float mHScale=1, mVScale=1;
6075 float mLastHScale=1, mLastVScale=1;
6076 final Matrix mTmpMatrix = new Matrix();
6077
6078 // "Real" frame that the application sees.
6079 final Rect mFrame = new Rect();
6080 final Rect mLastFrame = new Rect();
6081
6082 final Rect mContainingFrame = new Rect();
6083 final Rect mDisplayFrame = new Rect();
6084 final Rect mContentFrame = new Rect();
6085 final Rect mVisibleFrame = new Rect();
6086
6087 float mShownAlpha = 1;
6088 float mAlpha = 1;
6089 float mLastAlpha = 1;
6090
6091 // Set to true if, when the window gets displayed, it should perform
6092 // an enter animation.
6093 boolean mEnterAnimationPending;
6094
6095 // Currently running animation.
6096 boolean mAnimating;
6097 boolean mLocalAnimating;
6098 Animation mAnimation;
6099 boolean mAnimationIsEntrance;
6100 boolean mHasTransformation;
6101 boolean mHasLocalTransformation;
6102 final Transformation mTransformation = new Transformation();
6103
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006104 // If a window showing a wallpaper: the requested offset for the
6105 // wallpaper; if a wallpaper window: the currently applied offset.
6106 float mWallpaperX = -1;
6107 float mWallpaperY = -1;
6108
6109 // Wallpaper windows: pixels offset based on above variables.
6110 int mXOffset;
6111 int mYOffset;
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07006112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006113 // This is set after IWindowSession.relayout() has been called at
6114 // least once for the window. It allows us to detect the situation
6115 // where we don't yet have a surface, but should have one soon, so
6116 // we can give the window focus before waiting for the relayout.
6117 boolean mRelayoutCalled;
Romain Guy06882f82009-06-10 13:36:04 -07006118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006119 // This is set after the Surface has been created but before the
6120 // window has been drawn. During this time the surface is hidden.
6121 boolean mDrawPending;
6122
6123 // This is set after the window has finished drawing for the first
6124 // time but before its surface is shown. The surface will be
6125 // displayed when the next layout is run.
6126 boolean mCommitDrawPending;
6127
6128 // This is set during the time after the window's drawing has been
6129 // committed, and before its surface is actually shown. It is used
6130 // to delay showing the surface until all windows in a token are ready
6131 // to be shown.
6132 boolean mReadyToShow;
Romain Guy06882f82009-06-10 13:36:04 -07006133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006134 // Set when the window has been shown in the screen the first time.
6135 boolean mHasDrawn;
6136
6137 // Currently running an exit animation?
6138 boolean mExiting;
6139
6140 // Currently on the mDestroySurface list?
6141 boolean mDestroying;
Romain Guy06882f82009-06-10 13:36:04 -07006142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006143 // Completely remove from window manager after exit animation?
6144 boolean mRemoveOnExit;
6145
6146 // Set when the orientation is changing and this window has not yet
6147 // been updated for the new orientation.
6148 boolean mOrientationChanging;
Romain Guy06882f82009-06-10 13:36:04 -07006149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006150 // Is this window now (or just being) removed?
6151 boolean mRemoved;
Romain Guy06882f82009-06-10 13:36:04 -07006152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006153 WindowState(Session s, IWindow c, WindowToken token,
6154 WindowState attachedWindow, WindowManager.LayoutParams a,
6155 int viewVisibility) {
6156 mSession = s;
6157 mClient = c;
6158 mToken = token;
6159 mAttrs.copyFrom(a);
6160 mViewVisibility = viewVisibility;
6161 DeathRecipient deathRecipient = new DeathRecipient();
6162 mAlpha = a.alpha;
6163 if (localLOGV) Log.v(
6164 TAG, "Window " + this + " client=" + c.asBinder()
6165 + " token=" + token + " (" + mAttrs.token + ")");
6166 try {
6167 c.asBinder().linkToDeath(deathRecipient, 0);
6168 } catch (RemoteException e) {
6169 mDeathRecipient = null;
6170 mAttachedWindow = null;
6171 mLayoutAttached = false;
6172 mIsImWindow = false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07006173 mIsWallpaper = false;
6174 mIsFloatingLayer = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006175 mBaseLayer = 0;
6176 mSubLayer = 0;
6177 return;
6178 }
6179 mDeathRecipient = deathRecipient;
Romain Guy06882f82009-06-10 13:36:04 -07006180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006181 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
6182 mAttrs.type <= LAST_SUB_WINDOW)) {
6183 // The multiplier here is to reserve space for multiple
6184 // windows in the same type layer.
6185 mBaseLayer = mPolicy.windowTypeToLayerLw(
6186 attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
6187 + TYPE_LAYER_OFFSET;
6188 mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
6189 mAttachedWindow = attachedWindow;
6190 mAttachedWindow.mChildWindows.add(this);
6191 mLayoutAttached = mAttrs.type !=
6192 WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
6193 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
6194 || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07006195 mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
6196 mIsFloatingLayer = mIsImWindow || mIsWallpaper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006197 } else {
6198 // The multiplier here is to reserve space for multiple
6199 // windows in the same type layer.
6200 mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
6201 * TYPE_LAYER_MULTIPLIER
6202 + TYPE_LAYER_OFFSET;
6203 mSubLayer = 0;
6204 mAttachedWindow = null;
6205 mLayoutAttached = false;
6206 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
6207 || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07006208 mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
6209 mIsFloatingLayer = mIsImWindow || mIsWallpaper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006210 }
6211
6212 WindowState appWin = this;
6213 while (appWin.mAttachedWindow != null) {
6214 appWin = mAttachedWindow;
6215 }
6216 WindowToken appToken = appWin.mToken;
6217 while (appToken.appWindowToken == null) {
6218 WindowToken parent = mTokenMap.get(appToken.token);
6219 if (parent == null || appToken == parent) {
6220 break;
6221 }
6222 appToken = parent;
6223 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006224 mRootToken = appToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006225 mAppToken = appToken.appWindowToken;
6226
6227 mSurface = null;
6228 mRequestedWidth = 0;
6229 mRequestedHeight = 0;
6230 mLastRequestedWidth = 0;
6231 mLastRequestedHeight = 0;
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07006232 mXOffset = 0;
6233 mYOffset = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006234 mLayer = 0;
6235 mAnimLayer = 0;
6236 mLastLayer = 0;
6237 }
6238
6239 void attach() {
6240 if (localLOGV) Log.v(
6241 TAG, "Attaching " + this + " token=" + mToken
6242 + ", list=" + mToken.windows);
6243 mSession.windowAddedLocked();
6244 }
6245
6246 public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
6247 mHaveFrame = true;
6248
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006249 final Rect container = mContainingFrame;
6250 container.set(pf);
6251
6252 final Rect display = mDisplayFrame;
6253 display.set(df);
6254
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07006255 if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006256 container.intersect(mCompatibleScreenFrame);
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07006257 if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
6258 display.intersect(mCompatibleScreenFrame);
6259 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006260 }
6261
6262 final int pw = container.right - container.left;
6263 final int ph = container.bottom - container.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006264
6265 int w,h;
6266 if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
6267 w = mAttrs.width < 0 ? pw : mAttrs.width;
6268 h = mAttrs.height< 0 ? ph : mAttrs.height;
6269 } else {
6270 w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
6271 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
6272 }
Romain Guy06882f82009-06-10 13:36:04 -07006273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006274 final Rect content = mContentFrame;
6275 content.set(cf);
Romain Guy06882f82009-06-10 13:36:04 -07006276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006277 final Rect visible = mVisibleFrame;
6278 visible.set(vf);
Romain Guy06882f82009-06-10 13:36:04 -07006279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006280 final Rect frame = mFrame;
Romain Guy06882f82009-06-10 13:36:04 -07006281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006282 //System.out.println("In: w=" + w + " h=" + h + " container=" +
6283 // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
6284
6285 Gravity.apply(mAttrs.gravity, w, h, container,
6286 (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
6287 (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
6288
6289 //System.out.println("Out: " + mFrame);
6290
6291 // Now make sure the window fits in the overall display.
6292 Gravity.applyDisplay(mAttrs.gravity, df, frame);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006294 // Make sure the content and visible frames are inside of the
6295 // final window frame.
6296 if (content.left < frame.left) content.left = frame.left;
6297 if (content.top < frame.top) content.top = frame.top;
6298 if (content.right > frame.right) content.right = frame.right;
6299 if (content.bottom > frame.bottom) content.bottom = frame.bottom;
6300 if (visible.left < frame.left) visible.left = frame.left;
6301 if (visible.top < frame.top) visible.top = frame.top;
6302 if (visible.right > frame.right) visible.right = frame.right;
6303 if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07006304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006305 final Rect contentInsets = mContentInsets;
6306 contentInsets.left = content.left-frame.left;
6307 contentInsets.top = content.top-frame.top;
6308 contentInsets.right = frame.right-content.right;
6309 contentInsets.bottom = frame.bottom-content.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07006310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006311 final Rect visibleInsets = mVisibleInsets;
6312 visibleInsets.left = visible.left-frame.left;
6313 visibleInsets.top = visible.top-frame.top;
6314 visibleInsets.right = frame.right-visible.right;
6315 visibleInsets.bottom = frame.bottom-visible.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07006316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006317 if (localLOGV) {
6318 //if ("com.google.android.youtube".equals(mAttrs.packageName)
6319 // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
6320 Log.v(TAG, "Resolving (mRequestedWidth="
6321 + mRequestedWidth + ", mRequestedheight="
6322 + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
6323 + "): frame=" + mFrame.toShortString()
6324 + " ci=" + contentInsets.toShortString()
6325 + " vi=" + visibleInsets.toShortString());
6326 //}
6327 }
6328 }
Romain Guy06882f82009-06-10 13:36:04 -07006329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006330 public Rect getFrameLw() {
6331 return mFrame;
6332 }
6333
6334 public Rect getShownFrameLw() {
6335 return mShownFrame;
6336 }
6337
6338 public Rect getDisplayFrameLw() {
6339 return mDisplayFrame;
6340 }
6341
6342 public Rect getContentFrameLw() {
6343 return mContentFrame;
6344 }
6345
6346 public Rect getVisibleFrameLw() {
6347 return mVisibleFrame;
6348 }
6349
6350 public boolean getGivenInsetsPendingLw() {
6351 return mGivenInsetsPending;
6352 }
6353
6354 public Rect getGivenContentInsetsLw() {
6355 return mGivenContentInsets;
6356 }
Romain Guy06882f82009-06-10 13:36:04 -07006357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006358 public Rect getGivenVisibleInsetsLw() {
6359 return mGivenVisibleInsets;
6360 }
Romain Guy06882f82009-06-10 13:36:04 -07006361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006362 public WindowManager.LayoutParams getAttrs() {
6363 return mAttrs;
6364 }
6365
6366 public int getSurfaceLayer() {
6367 return mLayer;
6368 }
Romain Guy06882f82009-06-10 13:36:04 -07006369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006370 public IApplicationToken getAppToken() {
6371 return mAppToken != null ? mAppToken.appToken : null;
6372 }
6373
6374 public boolean hasAppShownWindows() {
6375 return mAppToken != null ? mAppToken.firstWindowDrawn : false;
6376 }
6377
6378 public boolean hasAppStartingIcon() {
6379 return mAppToken != null ? (mAppToken.startingData != null) : false;
6380 }
6381
6382 public WindowManagerPolicy.WindowState getAppStartingWindow() {
6383 return mAppToken != null ? mAppToken.startingWindow : null;
6384 }
6385
6386 public void setAnimation(Animation anim) {
6387 if (localLOGV) Log.v(
6388 TAG, "Setting animation in " + this + ": " + anim);
6389 mAnimating = false;
6390 mLocalAnimating = false;
6391 mAnimation = anim;
6392 mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
6393 mAnimation.scaleCurrentDuration(mWindowAnimationScale);
6394 }
6395
6396 public void clearAnimation() {
6397 if (mAnimation != null) {
6398 mAnimating = true;
6399 mLocalAnimating = false;
6400 mAnimation = null;
6401 }
6402 }
Romain Guy06882f82009-06-10 13:36:04 -07006403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006404 Surface createSurfaceLocked() {
6405 if (mSurface == null) {
6406 mDrawPending = true;
6407 mCommitDrawPending = false;
6408 mReadyToShow = false;
6409 if (mAppToken != null) {
6410 mAppToken.allDrawn = false;
6411 }
6412
6413 int flags = 0;
Mathias Agopian317a6282009-08-13 17:29:02 -07006414 if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006415 flags |= Surface.PUSH_BUFFERS;
6416 }
6417
6418 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
6419 flags |= Surface.SECURE;
6420 }
6421 if (DEBUG_VISIBILITY) Log.v(
6422 TAG, "Creating surface in session "
6423 + mSession.mSurfaceSession + " window " + this
6424 + " w=" + mFrame.width()
6425 + " h=" + mFrame.height() + " format="
6426 + mAttrs.format + " flags=" + flags);
6427
6428 int w = mFrame.width();
6429 int h = mFrame.height();
6430 if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
6431 // for a scaled surface, we always want the requested
6432 // size.
6433 w = mRequestedWidth;
6434 h = mRequestedHeight;
6435 }
6436
6437 try {
6438 mSurface = new Surface(
Romain Guy06882f82009-06-10 13:36:04 -07006439 mSession.mSurfaceSession, mSession.mPid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006440 0, w, h, mAttrs.format, flags);
6441 } catch (Surface.OutOfResourcesException e) {
6442 Log.w(TAG, "OutOfResourcesException creating surface");
6443 reclaimSomeSurfaceMemoryLocked(this, "create");
6444 return null;
6445 } catch (Exception e) {
6446 Log.e(TAG, "Exception creating surface", e);
6447 return null;
6448 }
Romain Guy06882f82009-06-10 13:36:04 -07006449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006450 if (localLOGV) Log.v(
6451 TAG, "Got surface: " + mSurface
6452 + ", set left=" + mFrame.left + " top=" + mFrame.top
6453 + ", animLayer=" + mAnimLayer);
6454 if (SHOW_TRANSACTIONS) {
6455 Log.i(TAG, ">>> OPEN TRANSACTION");
6456 Log.i(TAG, " SURFACE " + mSurface + ": CREATE ("
6457 + mAttrs.getTitle() + ") pos=(" +
6458 mFrame.left + "," + mFrame.top + ") (" +
6459 mFrame.width() + "x" + mFrame.height() + "), layer=" +
6460 mAnimLayer + " HIDE");
6461 }
6462 Surface.openTransaction();
6463 try {
6464 try {
6465 mSurface.setPosition(mFrame.left, mFrame.top);
6466 mSurface.setLayer(mAnimLayer);
6467 mSurface.hide();
6468 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
6469 mSurface.setFlags(Surface.SURFACE_DITHER,
6470 Surface.SURFACE_DITHER);
6471 }
6472 } catch (RuntimeException e) {
6473 Log.w(TAG, "Error creating surface in " + w, e);
6474 reclaimSomeSurfaceMemoryLocked(this, "create-init");
6475 }
6476 mLastHidden = true;
6477 } finally {
6478 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
6479 Surface.closeTransaction();
6480 }
6481 if (localLOGV) Log.v(
6482 TAG, "Created surface " + this);
6483 }
6484 return mSurface;
6485 }
Romain Guy06882f82009-06-10 13:36:04 -07006486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006487 void destroySurfaceLocked() {
6488 // Window is no longer on-screen, so can no longer receive
6489 // key events... if we were waiting for it to finish
6490 // handling a key event, the wait is over!
6491 mKeyWaiter.finishedKey(mSession, mClient, true,
6492 KeyWaiter.RETURN_NOTHING);
6493 mKeyWaiter.releasePendingPointerLocked(mSession);
6494 mKeyWaiter.releasePendingTrackballLocked(mSession);
6495
6496 if (mAppToken != null && this == mAppToken.startingWindow) {
6497 mAppToken.startingDisplayed = false;
6498 }
Romain Guy06882f82009-06-10 13:36:04 -07006499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006500 if (localLOGV) Log.v(
6501 TAG, "Window " + this
6502 + " destroying surface " + mSurface + ", session " + mSession);
6503 if (mSurface != null) {
6504 try {
6505 if (SHOW_TRANSACTIONS) {
6506 RuntimeException ex = new RuntimeException();
6507 ex.fillInStackTrace();
6508 Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
6509 + mAttrs.getTitle() + ")", ex);
6510 }
6511 mSurface.clear();
6512 } catch (RuntimeException e) {
6513 Log.w(TAG, "Exception thrown when destroying Window " + this
6514 + " surface " + mSurface + " session " + mSession
6515 + ": " + e.toString());
6516 }
6517 mSurface = null;
6518 mDrawPending = false;
6519 mCommitDrawPending = false;
6520 mReadyToShow = false;
6521
6522 int i = mChildWindows.size();
6523 while (i > 0) {
6524 i--;
6525 WindowState c = (WindowState)mChildWindows.get(i);
6526 c.mAttachedHidden = true;
6527 }
6528 }
6529 }
6530
6531 boolean finishDrawingLocked() {
6532 if (mDrawPending) {
6533 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
6534 TAG, "finishDrawingLocked: " + mSurface);
6535 mCommitDrawPending = true;
6536 mDrawPending = false;
6537 return true;
6538 }
6539 return false;
6540 }
6541
6542 // This must be called while inside a transaction.
6543 void commitFinishDrawingLocked(long currentTime) {
6544 //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
6545 if (!mCommitDrawPending) {
6546 return;
6547 }
6548 mCommitDrawPending = false;
6549 mReadyToShow = true;
6550 final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING;
6551 final AppWindowToken atoken = mAppToken;
6552 if (atoken == null || atoken.allDrawn || starting) {
6553 performShowLocked();
6554 }
6555 }
6556
6557 // This must be called while inside a transaction.
6558 boolean performShowLocked() {
6559 if (DEBUG_VISIBILITY) {
6560 RuntimeException e = new RuntimeException();
6561 e.fillInStackTrace();
6562 Log.v(TAG, "performShow on " + this
6563 + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
6564 + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
6565 }
6566 if (mReadyToShow && isReadyForDisplay()) {
6567 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i(
6568 TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)");
6569 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this
6570 + " during animation: policyVis=" + mPolicyVisibility
6571 + " attHidden=" + mAttachedHidden
6572 + " tok.hiddenRequested="
6573 + (mAppToken != null ? mAppToken.hiddenRequested : false)
6574 + " tok.idden="
6575 + (mAppToken != null ? mAppToken.hidden : false)
6576 + " animating=" + mAnimating
6577 + " tok animating="
6578 + (mAppToken != null ? mAppToken.animating : false));
6579 if (!showSurfaceRobustlyLocked(this)) {
6580 return false;
6581 }
6582 mLastAlpha = -1;
6583 mHasDrawn = true;
6584 mLastHidden = false;
6585 mReadyToShow = false;
6586 enableScreenIfNeededLocked();
6587
6588 applyEnterAnimationLocked(this);
Romain Guy06882f82009-06-10 13:36:04 -07006589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006590 int i = mChildWindows.size();
6591 while (i > 0) {
6592 i--;
6593 WindowState c = (WindowState)mChildWindows.get(i);
6594 if (c.mSurface != null && c.mAttachedHidden) {
6595 c.mAttachedHidden = false;
6596 c.performShowLocked();
6597 }
6598 }
Romain Guy06882f82009-06-10 13:36:04 -07006599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006600 if (mAttrs.type != TYPE_APPLICATION_STARTING
6601 && mAppToken != null) {
6602 mAppToken.firstWindowDrawn = true;
6603 if (mAnimation == null && mAppToken.startingData != null) {
6604 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6605 + mToken
6606 + ": first real window is shown, no animation");
6607 mFinishedStarting.add(mAppToken);
6608 mH.sendEmptyMessage(H.FINISHED_STARTING);
6609 }
6610 mAppToken.updateReportedVisibilityLocked();
6611 }
6612 }
6613 return true;
6614 }
Romain Guy06882f82009-06-10 13:36:04 -07006615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006616 // This must be called while inside a transaction. Returns true if
6617 // there is more animation to run.
6618 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6619 if (!mDisplayFrozen) {
6620 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07006621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006622 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
6623 mHasTransformation = true;
6624 mHasLocalTransformation = true;
6625 if (!mLocalAnimating) {
6626 if (DEBUG_ANIM) Log.v(
6627 TAG, "Starting animation in " + this +
6628 " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
6629 " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
6630 mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
6631 mAnimation.setStartTime(currentTime);
6632 mLocalAnimating = true;
6633 mAnimating = true;
6634 }
6635 mTransformation.clear();
6636 final boolean more = mAnimation.getTransformation(
6637 currentTime, mTransformation);
6638 if (DEBUG_ANIM) Log.v(
6639 TAG, "Stepped animation in " + this +
6640 ": more=" + more + ", xform=" + mTransformation);
6641 if (more) {
6642 // we're not done!
6643 return true;
6644 }
6645 if (DEBUG_ANIM) Log.v(
6646 TAG, "Finished animation in " + this +
6647 " @ " + currentTime);
6648 mAnimation = null;
6649 //WindowManagerService.this.dump();
6650 }
6651 mHasLocalTransformation = false;
6652 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
6653 && mAppToken.hasTransformation) {
6654 // When our app token is animating, we kind-of pretend like
6655 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
6656 // part of this check means that we will only do this if
6657 // our window is not currently exiting, or it is not
6658 // locally animating itself. The idea being that one that
6659 // is exiting and doing a local animation should be removed
6660 // once that animation is done.
6661 mAnimating = true;
6662 mHasTransformation = true;
6663 mTransformation.clear();
6664 return false;
6665 } else if (mHasTransformation) {
6666 // Little trick to get through the path below to act like
6667 // we have finished an animation.
6668 mAnimating = true;
6669 } else if (isAnimating()) {
6670 mAnimating = true;
6671 }
6672 } else if (mAnimation != null) {
6673 // If the display is frozen, and there is a pending animation,
6674 // clear it and make sure we run the cleanup code.
6675 mAnimating = true;
6676 mLocalAnimating = true;
6677 mAnimation = null;
6678 }
Romain Guy06882f82009-06-10 13:36:04 -07006679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006680 if (!mAnimating && !mLocalAnimating) {
6681 return false;
6682 }
6683
6684 if (DEBUG_ANIM) Log.v(
6685 TAG, "Animation done in " + this + ": exiting=" + mExiting
6686 + ", reportedVisible="
6687 + (mAppToken != null ? mAppToken.reportedVisible : false));
Romain Guy06882f82009-06-10 13:36:04 -07006688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006689 mAnimating = false;
6690 mLocalAnimating = false;
6691 mAnimation = null;
6692 mAnimLayer = mLayer;
6693 if (mIsImWindow) {
6694 mAnimLayer += mInputMethodAnimLayerAdjustment;
Dianne Hackborn759a39e2009-08-09 17:20:27 -07006695 } else if (mIsWallpaper) {
6696 mAnimLayer += mWallpaperAnimLayerAdjustment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006697 }
6698 if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
6699 + " anim layer: " + mAnimLayer);
6700 mHasTransformation = false;
6701 mHasLocalTransformation = false;
6702 mPolicyVisibility = mPolicyVisibilityAfterAnim;
6703 mTransformation.clear();
6704 if (mHasDrawn
6705 && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
6706 && mAppToken != null
6707 && mAppToken.firstWindowDrawn
6708 && mAppToken.startingData != null) {
6709 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6710 + mToken + ": first real window done animating");
6711 mFinishedStarting.add(mAppToken);
6712 mH.sendEmptyMessage(H.FINISHED_STARTING);
6713 }
Romain Guy06882f82009-06-10 13:36:04 -07006714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006715 finishExit();
6716
6717 if (mAppToken != null) {
6718 mAppToken.updateReportedVisibilityLocked();
6719 }
6720
6721 return false;
6722 }
6723
6724 void finishExit() {
6725 if (DEBUG_ANIM) Log.v(
6726 TAG, "finishExit in " + this
6727 + ": exiting=" + mExiting
6728 + " remove=" + mRemoveOnExit
6729 + " windowAnimating=" + isWindowAnimating());
Romain Guy06882f82009-06-10 13:36:04 -07006730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006731 final int N = mChildWindows.size();
6732 for (int i=0; i<N; i++) {
6733 ((WindowState)mChildWindows.get(i)).finishExit();
6734 }
Romain Guy06882f82009-06-10 13:36:04 -07006735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006736 if (!mExiting) {
6737 return;
6738 }
Romain Guy06882f82009-06-10 13:36:04 -07006739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006740 if (isWindowAnimating()) {
6741 return;
6742 }
6743
6744 if (localLOGV) Log.v(
6745 TAG, "Exit animation finished in " + this
6746 + ": remove=" + mRemoveOnExit);
6747 if (mSurface != null) {
6748 mDestroySurface.add(this);
6749 mDestroying = true;
6750 if (SHOW_TRANSACTIONS) Log.i(
6751 TAG, " SURFACE " + mSurface + ": HIDE (finishExit)");
6752 try {
6753 mSurface.hide();
6754 } catch (RuntimeException e) {
6755 Log.w(TAG, "Error hiding surface in " + this, e);
6756 }
6757 mLastHidden = true;
6758 mKeyWaiter.releasePendingPointerLocked(mSession);
6759 }
6760 mExiting = false;
6761 if (mRemoveOnExit) {
6762 mPendingRemove.add(this);
6763 mRemoveOnExit = false;
6764 }
6765 }
Romain Guy06882f82009-06-10 13:36:04 -07006766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006767 boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
6768 if (dsdx < .99999f || dsdx > 1.00001f) return false;
6769 if (dtdy < .99999f || dtdy > 1.00001f) return false;
6770 if (dtdx < -.000001f || dtdx > .000001f) return false;
6771 if (dsdy < -.000001f || dsdy > .000001f) return false;
6772 return true;
6773 }
Romain Guy06882f82009-06-10 13:36:04 -07006774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006775 void computeShownFrameLocked() {
6776 final boolean selfTransformation = mHasLocalTransformation;
6777 Transformation attachedTransformation =
6778 (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
6779 ? mAttachedWindow.mTransformation : null;
6780 Transformation appTransformation =
6781 (mAppToken != null && mAppToken.hasTransformation)
6782 ? mAppToken.transformation : null;
Dianne Hackborn759a39e2009-08-09 17:20:27 -07006783
6784 // Wallpapers are animated based on the "real" window they
6785 // are currently targeting.
6786 if (mAttrs.type == TYPE_WALLPAPER && mWallpaperTarget != null) {
6787 if (mWallpaperTarget.mHasLocalTransformation) {
6788 attachedTransformation = mWallpaperTarget.mTransformation;
6789 }
6790 if (mWallpaperTarget.mAppToken != null &&
6791 mWallpaperTarget.mAppToken.hasTransformation) {
6792 appTransformation = mWallpaperTarget.mAppToken.transformation;
6793 }
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07006794 if (DEBUG_WALLPAPER && attachedTransformation != null) {
6795 Log.v(TAG, "WP target attached xform: " + attachedTransformation);
6796 }
6797 if (DEBUG_WALLPAPER && appTransformation != null) {
6798 Log.v(TAG, "WP target app xform: " + appTransformation);
6799 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -07006800 }
6801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006802 if (selfTransformation || attachedTransformation != null
6803 || appTransformation != null) {
Romain Guy06882f82009-06-10 13:36:04 -07006804 // cache often used attributes locally
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006805 final Rect frame = mFrame;
6806 final float tmpFloats[] = mTmpFloats;
6807 final Matrix tmpMatrix = mTmpMatrix;
6808
6809 // Compute the desired transformation.
6810 tmpMatrix.setTranslate(frame.left, frame.top);
6811 if (selfTransformation) {
6812 tmpMatrix.preConcat(mTransformation.getMatrix());
6813 }
6814 if (attachedTransformation != null) {
6815 tmpMatrix.preConcat(attachedTransformation.getMatrix());
6816 }
6817 if (appTransformation != null) {
6818 tmpMatrix.preConcat(appTransformation.getMatrix());
6819 }
6820
6821 // "convert" it into SurfaceFlinger's format
6822 // (a 2x2 matrix + an offset)
6823 // Here we must not transform the position of the surface
6824 // since it is already included in the transformation.
6825 //Log.i(TAG, "Transform: " + matrix);
Romain Guy06882f82009-06-10 13:36:04 -07006826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006827 tmpMatrix.getValues(tmpFloats);
6828 mDsDx = tmpFloats[Matrix.MSCALE_X];
6829 mDtDx = tmpFloats[Matrix.MSKEW_X];
6830 mDsDy = tmpFloats[Matrix.MSKEW_Y];
6831 mDtDy = tmpFloats[Matrix.MSCALE_Y];
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07006832 int x = (int)tmpFloats[Matrix.MTRANS_X] + mXOffset;
6833 int y = (int)tmpFloats[Matrix.MTRANS_Y] + mYOffset;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006834 int w = frame.width();
6835 int h = frame.height();
6836 mShownFrame.set(x, y, x+w, y+h);
6837
6838 // Now set the alpha... but because our current hardware
6839 // can't do alpha transformation on a non-opaque surface,
6840 // turn it off if we are running an animation that is also
6841 // transforming since it is more important to have that
6842 // animation be smooth.
6843 mShownAlpha = mAlpha;
6844 if (!mLimitedAlphaCompositing
6845 || (!PixelFormat.formatHasAlpha(mAttrs.format)
6846 || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
6847 && x == frame.left && y == frame.top))) {
6848 //Log.i(TAG, "Applying alpha transform");
6849 if (selfTransformation) {
6850 mShownAlpha *= mTransformation.getAlpha();
6851 }
6852 if (attachedTransformation != null) {
6853 mShownAlpha *= attachedTransformation.getAlpha();
6854 }
6855 if (appTransformation != null) {
6856 mShownAlpha *= appTransformation.getAlpha();
6857 }
6858 } else {
6859 //Log.i(TAG, "Not applying alpha transform");
6860 }
Romain Guy06882f82009-06-10 13:36:04 -07006861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006862 if (localLOGV) Log.v(
6863 TAG, "Continuing animation in " + this +
6864 ": " + mShownFrame +
6865 ", alpha=" + mTransformation.getAlpha());
6866 return;
6867 }
Romain Guy06882f82009-06-10 13:36:04 -07006868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006869 mShownFrame.set(mFrame);
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07006870 if (mXOffset != 0 || mYOffset != 0) {
6871 mShownFrame.offset(mXOffset, mYOffset);
6872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006873 mShownAlpha = mAlpha;
6874 mDsDx = 1;
6875 mDtDx = 0;
6876 mDsDy = 0;
6877 mDtDy = 1;
6878 }
Romain Guy06882f82009-06-10 13:36:04 -07006879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006880 /**
6881 * Is this window visible? It is not visible if there is no
6882 * surface, or we are in the process of running an exit animation
6883 * that will remove the surface, or its app token has been hidden.
6884 */
6885 public boolean isVisibleLw() {
6886 final AppWindowToken atoken = mAppToken;
6887 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6888 && (atoken == null || !atoken.hiddenRequested)
6889 && !mExiting && !mDestroying;
6890 }
6891
6892 /**
6893 * Is this window visible, ignoring its app token? It is not visible
6894 * if there is no surface, or we are in the process of running an exit animation
6895 * that will remove the surface.
6896 */
6897 public boolean isWinVisibleLw() {
6898 final AppWindowToken atoken = mAppToken;
6899 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6900 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
6901 && !mExiting && !mDestroying;
6902 }
6903
6904 /**
6905 * The same as isVisible(), but follows the current hidden state of
6906 * the associated app token, not the pending requested hidden state.
6907 */
6908 boolean isVisibleNow() {
6909 return mSurface != null && mPolicyVisibility && !mAttachedHidden
The Android Open Source Project10592532009-03-18 17:39:46 -07006910 && !mRootToken.hidden && !mExiting && !mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006911 }
6912
6913 /**
6914 * Same as isVisible(), but we also count it as visible between the
6915 * call to IWindowSession.add() and the first relayout().
6916 */
6917 boolean isVisibleOrAdding() {
6918 final AppWindowToken atoken = mAppToken;
6919 return (mSurface != null
6920 || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
6921 && mPolicyVisibility && !mAttachedHidden
6922 && (atoken == null || !atoken.hiddenRequested)
6923 && !mExiting && !mDestroying;
6924 }
6925
6926 /**
6927 * Is this window currently on-screen? It is on-screen either if it
6928 * is visible or it is currently running an animation before no longer
6929 * being visible.
6930 */
6931 boolean isOnScreen() {
6932 final AppWindowToken atoken = mAppToken;
6933 if (atoken != null) {
6934 return mSurface != null && mPolicyVisibility && !mDestroying
6935 && ((!mAttachedHidden && !atoken.hiddenRequested)
Dianne Hackborn0cd48872009-08-13 18:51:59 -07006936 || mAnimation != null || atoken.animation != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006937 } else {
6938 return mSurface != null && mPolicyVisibility && !mDestroying
Dianne Hackborn0cd48872009-08-13 18:51:59 -07006939 && (!mAttachedHidden || mAnimation != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006940 }
6941 }
Romain Guy06882f82009-06-10 13:36:04 -07006942
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006943 /**
6944 * Like isOnScreen(), but we don't return true if the window is part
6945 * of a transition that has not yet been started.
6946 */
6947 boolean isReadyForDisplay() {
6948 final AppWindowToken atoken = mAppToken;
Dianne Hackborn0cd48872009-08-13 18:51:59 -07006949 final boolean animating = atoken != null
6950 ? (atoken.animation != null) : false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006951 return mSurface != null && mPolicyVisibility && !mDestroying
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07006952 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
6953 && !mRootToken.hidden)
Dianne Hackborn0cd48872009-08-13 18:51:59 -07006954 || mAnimation != null || animating);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006955 }
6956
6957 /** Is the window or its container currently animating? */
6958 boolean isAnimating() {
6959 final WindowState attached = mAttachedWindow;
6960 final AppWindowToken atoken = mAppToken;
6961 return mAnimation != null
6962 || (attached != null && attached.mAnimation != null)
Romain Guy06882f82009-06-10 13:36:04 -07006963 || (atoken != null &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006964 (atoken.animation != null
6965 || atoken.inPendingTransaction));
6966 }
6967
6968 /** Is this window currently animating? */
6969 boolean isWindowAnimating() {
6970 return mAnimation != null;
6971 }
6972
6973 /**
6974 * Like isOnScreen, but returns false if the surface hasn't yet
6975 * been drawn.
6976 */
6977 public boolean isDisplayedLw() {
6978 final AppWindowToken atoken = mAppToken;
6979 return mSurface != null && mPolicyVisibility && !mDestroying
6980 && !mDrawPending && !mCommitDrawPending
6981 && ((!mAttachedHidden &&
6982 (atoken == null || !atoken.hiddenRequested))
6983 || mAnimating);
6984 }
6985
6986 public boolean fillsScreenLw(int screenWidth, int screenHeight,
6987 boolean shownFrame, boolean onlyOpaque) {
6988 if (mSurface == null) {
6989 return false;
6990 }
6991 if (mAppToken != null && !mAppToken.appFullscreen) {
6992 return false;
6993 }
6994 if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
6995 return false;
6996 }
6997 final Rect frame = shownFrame ? mShownFrame : mFrame;
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07006998
6999 if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
7000 return frame.left <= mCompatibleScreenFrame.left &&
7001 frame.top <= mCompatibleScreenFrame.top &&
7002 frame.right >= mCompatibleScreenFrame.right &&
7003 frame.bottom >= mCompatibleScreenFrame.bottom;
7004 } else {
7005 return frame.left <= 0 && frame.top <= 0
7006 && frame.right >= screenWidth
7007 && frame.bottom >= screenHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007009 }
Romain Guy06882f82009-06-10 13:36:04 -07007010
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07007011 /**
7012 * Return true if the window is opaque and fully drawn.
7013 */
7014 boolean isOpaqueDrawn() {
7015 return mAttrs.format == PixelFormat.OPAQUE && mSurface != null
7016 && mAnimation == null && !mDrawPending && !mCommitDrawPending;
7017 }
7018
7019 boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
7020 return
7021 // only if the application is requesting compatible window
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07007022 (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
7023 // only if it's visible
7024 mHasDrawn && mViewVisibility == View.VISIBLE &&
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07007025 // and only if the application fills the compatible screen
7026 mFrame.left <= mCompatibleScreenFrame.left &&
7027 mFrame.top <= mCompatibleScreenFrame.top &&
7028 mFrame.right >= mCompatibleScreenFrame.right &&
7029 mFrame.bottom >= mCompatibleScreenFrame.bottom &&
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07007030 // and starting window do not need background filler
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07007031 mAttrs.type != mAttrs.TYPE_APPLICATION_STARTING;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07007032 }
7033
7034 boolean isFullscreen(int screenWidth, int screenHeight) {
7035 return mFrame.left <= 0 && mFrame.top <= 0 &&
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07007036 mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007037 }
7038
7039 void removeLocked() {
7040 if (mAttachedWindow != null) {
7041 mAttachedWindow.mChildWindows.remove(this);
7042 }
7043 destroySurfaceLocked();
7044 mSession.windowRemovedLocked();
7045 try {
7046 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
7047 } catch (RuntimeException e) {
7048 // Ignore if it has already been removed (usually because
7049 // we are doing this as part of processing a death note.)
7050 }
7051 }
7052
7053 private class DeathRecipient implements IBinder.DeathRecipient {
7054 public void binderDied() {
7055 try {
7056 synchronized(mWindowMap) {
7057 WindowState win = windowForClientLocked(mSession, mClient);
7058 Log.i(TAG, "WIN DEATH: " + win);
7059 if (win != null) {
7060 removeWindowLocked(mSession, win);
7061 }
7062 }
7063 } catch (IllegalArgumentException ex) {
7064 // This will happen if the window has already been
7065 // removed.
7066 }
7067 }
7068 }
7069
7070 /** Returns true if this window desires key events. */
7071 public final boolean canReceiveKeys() {
7072 return isVisibleOrAdding()
7073 && (mViewVisibility == View.VISIBLE)
7074 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
7075 }
7076
7077 public boolean hasDrawnLw() {
7078 return mHasDrawn;
7079 }
7080
7081 public boolean showLw(boolean doAnimation) {
7082 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
7083 mPolicyVisibility = true;
7084 mPolicyVisibilityAfterAnim = true;
7085 if (doAnimation) {
7086 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
7087 }
7088 requestAnimationLocked(0);
7089 return true;
7090 }
7091 return false;
7092 }
7093
7094 public boolean hideLw(boolean doAnimation) {
7095 boolean current = doAnimation ? mPolicyVisibilityAfterAnim
7096 : mPolicyVisibility;
7097 if (current) {
7098 if (doAnimation) {
7099 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
7100 if (mAnimation == null) {
7101 doAnimation = false;
7102 }
7103 }
7104 if (doAnimation) {
7105 mPolicyVisibilityAfterAnim = false;
7106 } else {
7107 mPolicyVisibilityAfterAnim = false;
7108 mPolicyVisibility = false;
7109 }
7110 requestAnimationLocked(0);
7111 return true;
7112 }
7113 return false;
7114 }
7115
7116 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007117 StringBuilder sb = new StringBuilder(64);
Romain Guy06882f82009-06-10 13:36:04 -07007118
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007119 pw.print(prefix); pw.print("mSession="); pw.print(mSession);
7120 pw.print(" mClient="); pw.println(mClient.asBinder());
7121 pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
7122 if (mAttachedWindow != null || mLayoutAttached) {
7123 pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
7124 pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
7125 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07007126 if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
7127 pw.print(prefix); pw.print("mIsImWindow="); pw.print(mIsImWindow);
7128 pw.print(" mIsWallpaper="); pw.print(mIsWallpaper);
Dianne Hackborn759a39e2009-08-09 17:20:27 -07007129 pw.print(" mIsFloatingLayer="); pw.print(mIsFloatingLayer);
7130 pw.print(" mWallpaperVisible="); pw.println(mWallpaperVisible);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007131 }
7132 pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
7133 pw.print(" mSubLayer="); pw.print(mSubLayer);
7134 pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
7135 pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
7136 : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)));
7137 pw.print("="); pw.print(mAnimLayer);
7138 pw.print(" mLastLayer="); pw.println(mLastLayer);
7139 if (mSurface != null) {
7140 pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
7141 }
7142 pw.print(prefix); pw.print("mToken="); pw.println(mToken);
7143 pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
7144 if (mAppToken != null) {
7145 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
7146 }
7147 if (mTargetAppToken != null) {
7148 pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken);
7149 }
7150 pw.print(prefix); pw.print("mViewVisibility=0x");
7151 pw.print(Integer.toHexString(mViewVisibility));
7152 pw.print(" mLastHidden="); pw.print(mLastHidden);
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07007153 pw.print(" mHaveFrame="); pw.print(mHaveFrame);
7154 pw.print(" mObscured="); pw.println(mObscured);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007155 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
7156 pw.print(prefix); pw.print("mPolicyVisibility=");
7157 pw.print(mPolicyVisibility);
7158 pw.print(" mPolicyVisibilityAfterAnim=");
7159 pw.print(mPolicyVisibilityAfterAnim);
7160 pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
7161 }
7162 pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07007163 pw.print(" h="); pw.println(mRequestedHeight);
7164 if (mXOffset != 0 || mYOffset != 0) {
7165 pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
7166 pw.print(" y="); pw.println(mYOffset);
7167 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007168 pw.print(prefix); pw.print("mGivenContentInsets=");
7169 mGivenContentInsets.printShortString(pw);
7170 pw.print(" mGivenVisibleInsets=");
7171 mGivenVisibleInsets.printShortString(pw);
7172 pw.println();
7173 if (mTouchableInsets != 0 || mGivenInsetsPending) {
7174 pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
7175 pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
7176 }
7177 pw.print(prefix); pw.print("mShownFrame=");
7178 mShownFrame.printShortString(pw);
7179 pw.print(" last="); mLastShownFrame.printShortString(pw);
7180 pw.println();
7181 pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
7182 pw.print(" last="); mLastFrame.printShortString(pw);
7183 pw.println();
7184 pw.print(prefix); pw.print("mContainingFrame=");
7185 mContainingFrame.printShortString(pw);
7186 pw.print(" mDisplayFrame=");
7187 mDisplayFrame.printShortString(pw);
7188 pw.println();
7189 pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw);
7190 pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw);
7191 pw.println();
7192 pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw);
7193 pw.print(" last="); mLastContentInsets.printShortString(pw);
7194 pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw);
7195 pw.print(" last="); mLastVisibleInsets.printShortString(pw);
7196 pw.println();
7197 if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
7198 pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
7199 pw.print(" mAlpha="); pw.print(mAlpha);
7200 pw.print(" mLastAlpha="); pw.println(mLastAlpha);
7201 }
7202 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
7203 || mAnimation != null) {
7204 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
7205 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
7206 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
7207 pw.print(" mAnimation="); pw.println(mAnimation);
7208 }
7209 if (mHasTransformation || mHasLocalTransformation) {
7210 pw.print(prefix); pw.print("XForm: has=");
7211 pw.print(mHasTransformation);
7212 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
7213 pw.print(" "); mTransformation.printShortString(pw);
7214 pw.println();
7215 }
7216 pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending);
7217 pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending);
7218 pw.print(" mReadyToShow="); pw.print(mReadyToShow);
7219 pw.print(" mHasDrawn="); pw.println(mHasDrawn);
7220 if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
7221 pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
7222 pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
7223 pw.print(" mDestroying="); pw.print(mDestroying);
7224 pw.print(" mRemoved="); pw.println(mRemoved);
7225 }
7226 if (mOrientationChanging || mAppFreezing) {
7227 pw.print(prefix); pw.print("mOrientationChanging=");
7228 pw.print(mOrientationChanging);
7229 pw.print(" mAppFreezing="); pw.println(mAppFreezing);
7230 }
Mitsuru Oshima589cebe2009-07-22 20:38:58 -07007231 if (mHScale != 1 || mVScale != 1) {
7232 pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
7233 pw.print(" mVScale="); pw.println(mVScale);
7234 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07007235 if (mWallpaperX != -1 || mWallpaperY != -1) {
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07007236 pw.print(prefix); pw.print("mWallpaperX="); pw.print(mWallpaperX);
7237 pw.print(" mWallpaperY="); pw.println(mWallpaperY);
7238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007239 }
7240
7241 @Override
7242 public String toString() {
7243 return "Window{"
7244 + Integer.toHexString(System.identityHashCode(this))
7245 + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
7246 }
7247 }
Romain Guy06882f82009-06-10 13:36:04 -07007248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007249 // -------------------------------------------------------------
7250 // Window Token State
7251 // -------------------------------------------------------------
7252
7253 class WindowToken {
7254 // The actual token.
7255 final IBinder token;
7256
7257 // The type of window this token is for, as per WindowManager.LayoutParams.
7258 final int windowType;
Romain Guy06882f82009-06-10 13:36:04 -07007259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007260 // Set if this token was explicitly added by a client, so should
7261 // not be removed when all windows are removed.
7262 final boolean explicit;
Romain Guy06882f82009-06-10 13:36:04 -07007263
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007264 // For printing.
7265 String stringName;
Romain Guy06882f82009-06-10 13:36:04 -07007266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007267 // If this is an AppWindowToken, this is non-null.
7268 AppWindowToken appWindowToken;
Romain Guy06882f82009-06-10 13:36:04 -07007269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007270 // All of the windows associated with this token.
7271 final ArrayList<WindowState> windows = new ArrayList<WindowState>();
7272
7273 // Is key dispatching paused for this token?
7274 boolean paused = false;
7275
7276 // Should this token's windows be hidden?
7277 boolean hidden;
7278
7279 // Temporary for finding which tokens no longer have visible windows.
7280 boolean hasVisible;
7281
7282 WindowToken(IBinder _token, int type, boolean _explicit) {
7283 token = _token;
7284 windowType = type;
7285 explicit = _explicit;
7286 }
7287
7288 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007289 pw.print(prefix); pw.print("token="); pw.println(token);
7290 pw.print(prefix); pw.print("windows="); pw.println(windows);
7291 pw.print(prefix); pw.print("windowType="); pw.print(windowType);
7292 pw.print(" hidden="); pw.print(hidden);
7293 pw.print(" hasVisible="); pw.println(hasVisible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007294 }
7295
7296 @Override
7297 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007298 if (stringName == null) {
7299 StringBuilder sb = new StringBuilder();
7300 sb.append("WindowToken{");
7301 sb.append(Integer.toHexString(System.identityHashCode(this)));
7302 sb.append(" token="); sb.append(token); sb.append('}');
7303 stringName = sb.toString();
7304 }
7305 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007306 }
7307 };
7308
7309 class AppWindowToken extends WindowToken {
7310 // Non-null only for application tokens.
7311 final IApplicationToken appToken;
7312
7313 // All of the windows and child windows that are included in this
7314 // application token. Note this list is NOT sorted!
7315 final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
7316
7317 int groupId = -1;
7318 boolean appFullscreen;
7319 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Romain Guy06882f82009-06-10 13:36:04 -07007320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007321 // These are used for determining when all windows associated with
7322 // an activity have been drawn, so they can be made visible together
7323 // at the same time.
7324 int lastTransactionSequence = mTransactionSequence-1;
7325 int numInterestingWindows;
7326 int numDrawnWindows;
7327 boolean inPendingTransaction;
7328 boolean allDrawn;
Romain Guy06882f82009-06-10 13:36:04 -07007329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007330 // Is this token going to be hidden in a little while? If so, it
7331 // won't be taken into account for setting the screen orientation.
7332 boolean willBeHidden;
Romain Guy06882f82009-06-10 13:36:04 -07007333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007334 // Is this window's surface needed? This is almost like hidden, except
7335 // it will sometimes be true a little earlier: when the token has
7336 // been shown, but is still waiting for its app transition to execute
7337 // before making its windows shown.
7338 boolean hiddenRequested;
Romain Guy06882f82009-06-10 13:36:04 -07007339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007340 // Have we told the window clients to hide themselves?
7341 boolean clientHidden;
Romain Guy06882f82009-06-10 13:36:04 -07007342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007343 // Last visibility state we reported to the app token.
7344 boolean reportedVisible;
7345
7346 // Set to true when the token has been removed from the window mgr.
7347 boolean removed;
7348
7349 // Have we been asked to have this token keep the screen frozen?
7350 boolean freezingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07007351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007352 boolean animating;
7353 Animation animation;
7354 boolean hasTransformation;
7355 final Transformation transformation = new Transformation();
Romain Guy06882f82009-06-10 13:36:04 -07007356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007357 // Offset to the window of all layers in the token, for use by
7358 // AppWindowToken animations.
7359 int animLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -07007360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007361 // Information about an application starting window if displayed.
7362 StartingData startingData;
7363 WindowState startingWindow;
7364 View startingView;
7365 boolean startingDisplayed;
7366 boolean startingMoved;
7367 boolean firstWindowDrawn;
7368
7369 AppWindowToken(IApplicationToken _token) {
7370 super(_token.asBinder(),
7371 WindowManager.LayoutParams.TYPE_APPLICATION, true);
7372 appWindowToken = this;
7373 appToken = _token;
7374 }
Romain Guy06882f82009-06-10 13:36:04 -07007375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007376 public void setAnimation(Animation anim) {
7377 if (localLOGV) Log.v(
7378 TAG, "Setting animation in " + this + ": " + anim);
7379 animation = anim;
7380 animating = false;
7381 anim.restrictDuration(MAX_ANIMATION_DURATION);
7382 anim.scaleCurrentDuration(mTransitionAnimationScale);
7383 int zorder = anim.getZAdjustment();
7384 int adj = 0;
7385 if (zorder == Animation.ZORDER_TOP) {
7386 adj = TYPE_LAYER_OFFSET;
7387 } else if (zorder == Animation.ZORDER_BOTTOM) {
7388 adj = -TYPE_LAYER_OFFSET;
7389 }
Romain Guy06882f82009-06-10 13:36:04 -07007390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007391 if (animLayerAdjustment != adj) {
7392 animLayerAdjustment = adj;
7393 updateLayers();
7394 }
7395 }
Romain Guy06882f82009-06-10 13:36:04 -07007396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007397 public void setDummyAnimation() {
7398 if (animation == null) {
7399 if (localLOGV) Log.v(
7400 TAG, "Setting dummy animation in " + this);
7401 animation = sDummyAnimation;
7402 }
7403 }
7404
7405 public void clearAnimation() {
7406 if (animation != null) {
7407 animation = null;
7408 animating = true;
7409 }
7410 }
Romain Guy06882f82009-06-10 13:36:04 -07007411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007412 void updateLayers() {
7413 final int N = allAppWindows.size();
7414 final int adj = animLayerAdjustment;
7415 for (int i=0; i<N; i++) {
7416 WindowState w = allAppWindows.get(i);
7417 w.mAnimLayer = w.mLayer + adj;
7418 if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
7419 + w.mAnimLayer);
7420 if (w == mInputMethodTarget) {
7421 setInputMethodAnimLayerAdjustment(adj);
7422 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -07007423 if (w == mWallpaperTarget) {
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07007424 setWallpaperAnimLayerAdjustmentLocked(adj);
Dianne Hackborn759a39e2009-08-09 17:20:27 -07007425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007426 }
7427 }
Romain Guy06882f82009-06-10 13:36:04 -07007428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007429 void sendAppVisibilityToClients() {
7430 final int N = allAppWindows.size();
7431 for (int i=0; i<N; i++) {
7432 WindowState win = allAppWindows.get(i);
7433 if (win == startingWindow && clientHidden) {
7434 // Don't hide the starting window.
7435 continue;
7436 }
7437 try {
7438 if (DEBUG_VISIBILITY) Log.v(TAG,
7439 "Setting visibility of " + win + ": " + (!clientHidden));
7440 win.mClient.dispatchAppVisibility(!clientHidden);
7441 } catch (RemoteException e) {
7442 }
7443 }
7444 }
Romain Guy06882f82009-06-10 13:36:04 -07007445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007446 void showAllWindowsLocked() {
7447 final int NW = allAppWindows.size();
7448 for (int i=0; i<NW; i++) {
7449 WindowState w = allAppWindows.get(i);
7450 if (DEBUG_VISIBILITY) Log.v(TAG,
7451 "performing show on: " + w);
7452 w.performShowLocked();
7453 }
7454 }
Romain Guy06882f82009-06-10 13:36:04 -07007455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007456 // This must be called while inside a transaction.
7457 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
7458 if (!mDisplayFrozen) {
7459 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07007460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007461 if (animation == sDummyAnimation) {
7462 // This guy is going to animate, but not yet. For now count
7463 // it is not animating for purposes of scheduling transactions;
7464 // when it is really time to animate, this will be set to
7465 // a real animation and the next call will execute normally.
7466 return false;
7467 }
Romain Guy06882f82009-06-10 13:36:04 -07007468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007469 if ((allDrawn || animating || startingDisplayed) && animation != null) {
7470 if (!animating) {
7471 if (DEBUG_ANIM) Log.v(
7472 TAG, "Starting animation in " + this +
7473 " @ " + currentTime + ": dw=" + dw + " dh=" + dh
7474 + " scale=" + mTransitionAnimationScale
7475 + " allDrawn=" + allDrawn + " animating=" + animating);
7476 animation.initialize(dw, dh, dw, dh);
7477 animation.setStartTime(currentTime);
7478 animating = true;
7479 }
7480 transformation.clear();
7481 final boolean more = animation.getTransformation(
7482 currentTime, transformation);
7483 if (DEBUG_ANIM) Log.v(
7484 TAG, "Stepped animation in " + this +
7485 ": more=" + more + ", xform=" + transformation);
7486 if (more) {
7487 // we're done!
7488 hasTransformation = true;
7489 return true;
7490 }
7491 if (DEBUG_ANIM) Log.v(
7492 TAG, "Finished animation in " + this +
7493 " @ " + currentTime);
7494 animation = null;
7495 }
7496 } else if (animation != null) {
7497 // If the display is frozen, and there is a pending animation,
7498 // clear it and make sure we run the cleanup code.
7499 animating = true;
7500 animation = null;
7501 }
7502
7503 hasTransformation = false;
Romain Guy06882f82009-06-10 13:36:04 -07007504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007505 if (!animating) {
7506 return false;
7507 }
7508
7509 clearAnimation();
7510 animating = false;
7511 if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
7512 moveInputMethodWindowsIfNeededLocked(true);
7513 }
Romain Guy06882f82009-06-10 13:36:04 -07007514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007515 if (DEBUG_ANIM) Log.v(
7516 TAG, "Animation done in " + this
7517 + ": reportedVisible=" + reportedVisible);
7518
7519 transformation.clear();
7520 if (animLayerAdjustment != 0) {
7521 animLayerAdjustment = 0;
7522 updateLayers();
7523 }
Romain Guy06882f82009-06-10 13:36:04 -07007524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007525 final int N = windows.size();
7526 for (int i=0; i<N; i++) {
7527 ((WindowState)windows.get(i)).finishExit();
7528 }
7529 updateReportedVisibilityLocked();
Romain Guy06882f82009-06-10 13:36:04 -07007530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007531 return false;
7532 }
7533
7534 void updateReportedVisibilityLocked() {
7535 if (appToken == null) {
7536 return;
7537 }
Romain Guy06882f82009-06-10 13:36:04 -07007538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007539 int numInteresting = 0;
7540 int numVisible = 0;
7541 boolean nowGone = true;
Romain Guy06882f82009-06-10 13:36:04 -07007542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007543 if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
7544 final int N = allAppWindows.size();
7545 for (int i=0; i<N; i++) {
7546 WindowState win = allAppWindows.get(i);
7547 if (win == startingWindow || win.mAppFreezing) {
7548 continue;
7549 }
7550 if (DEBUG_VISIBILITY) {
7551 Log.v(TAG, "Win " + win + ": isDisplayed="
7552 + win.isDisplayedLw()
7553 + ", isAnimating=" + win.isAnimating());
7554 if (!win.isDisplayedLw()) {
7555 Log.v(TAG, "Not displayed: s=" + win.mSurface
7556 + " pv=" + win.mPolicyVisibility
7557 + " dp=" + win.mDrawPending
7558 + " cdp=" + win.mCommitDrawPending
7559 + " ah=" + win.mAttachedHidden
7560 + " th="
7561 + (win.mAppToken != null
7562 ? win.mAppToken.hiddenRequested : false)
7563 + " a=" + win.mAnimating);
7564 }
7565 }
7566 numInteresting++;
7567 if (win.isDisplayedLw()) {
7568 if (!win.isAnimating()) {
7569 numVisible++;
7570 }
7571 nowGone = false;
7572 } else if (win.isAnimating()) {
7573 nowGone = false;
7574 }
7575 }
Romain Guy06882f82009-06-10 13:36:04 -07007576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007577 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
7578 if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
7579 + numInteresting + " visible=" + numVisible);
7580 if (nowVisible != reportedVisible) {
7581 if (DEBUG_VISIBILITY) Log.v(
7582 TAG, "Visibility changed in " + this
7583 + ": vis=" + nowVisible);
7584 reportedVisible = nowVisible;
7585 Message m = mH.obtainMessage(
7586 H.REPORT_APPLICATION_TOKEN_WINDOWS,
7587 nowVisible ? 1 : 0,
7588 nowGone ? 1 : 0,
7589 this);
7590 mH.sendMessage(m);
7591 }
7592 }
Romain Guy06882f82009-06-10 13:36:04 -07007593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 void dump(PrintWriter pw, String prefix) {
7595 super.dump(pw, prefix);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007596 if (appToken != null) {
7597 pw.print(prefix); pw.println("app=true");
7598 }
7599 if (allAppWindows.size() > 0) {
7600 pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
7601 }
7602 pw.print(prefix); pw.print("groupId="); pw.print(groupId);
7603 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
7604 pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
7605 pw.print(" clientHidden="); pw.print(clientHidden);
7606 pw.print(" willBeHidden="); pw.print(willBeHidden);
7607 pw.print(" reportedVisible="); pw.println(reportedVisible);
7608 if (paused || freezingScreen) {
7609 pw.print(prefix); pw.print("paused="); pw.print(paused);
7610 pw.print(" freezingScreen="); pw.println(freezingScreen);
7611 }
7612 if (numInterestingWindows != 0 || numDrawnWindows != 0
7613 || inPendingTransaction || allDrawn) {
7614 pw.print(prefix); pw.print("numInterestingWindows=");
7615 pw.print(numInterestingWindows);
7616 pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
7617 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
7618 pw.print(" allDrawn="); pw.println(allDrawn);
7619 }
7620 if (animating || animation != null) {
7621 pw.print(prefix); pw.print("animating="); pw.print(animating);
7622 pw.print(" animation="); pw.println(animation);
7623 }
7624 if (animLayerAdjustment != 0) {
7625 pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
7626 }
7627 if (hasTransformation) {
7628 pw.print(prefix); pw.print("hasTransformation="); pw.print(hasTransformation);
7629 pw.print(" transformation="); transformation.printShortString(pw);
7630 pw.println();
7631 }
7632 if (startingData != null || removed || firstWindowDrawn) {
7633 pw.print(prefix); pw.print("startingData="); pw.print(startingData);
7634 pw.print(" removed="); pw.print(removed);
7635 pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
7636 }
7637 if (startingWindow != null || startingView != null
7638 || startingDisplayed || startingMoved) {
7639 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
7640 pw.print(" startingView="); pw.print(startingView);
7641 pw.print(" startingDisplayed="); pw.print(startingDisplayed);
7642 pw.print(" startingMoved"); pw.println(startingMoved);
7643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007644 }
7645
7646 @Override
7647 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007648 if (stringName == null) {
7649 StringBuilder sb = new StringBuilder();
7650 sb.append("AppWindowToken{");
7651 sb.append(Integer.toHexString(System.identityHashCode(this)));
7652 sb.append(" token="); sb.append(token); sb.append('}');
7653 stringName = sb.toString();
7654 }
7655 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007656 }
7657 }
Romain Guy06882f82009-06-10 13:36:04 -07007658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007659 public static WindowManager.LayoutParams findAnimations(
7660 ArrayList<AppWindowToken> order,
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007661 ArrayList<AppWindowToken> openingTokenList1,
7662 ArrayList<AppWindowToken> closingTokenList2) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007663 // We need to figure out which animation to use...
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007664
7665 // First, check if there is a compatible window in opening/closing
7666 // apps, and use it if exists.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007667 WindowManager.LayoutParams animParams = null;
7668 int animSrc = 0;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007669 animParams = findCompatibleWindowParams(openingTokenList1);
7670 if (animParams == null) {
7671 animParams = findCompatibleWindowParams(closingTokenList2);
7672 }
7673 if (animParams != null) {
7674 return animParams;
7675 }
7676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007677 //Log.i(TAG, "Looking for animations...");
7678 for (int i=order.size()-1; i>=0; i--) {
7679 AppWindowToken wtoken = order.get(i);
7680 //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007681 if (openingTokenList1.contains(wtoken) || closingTokenList2.contains(wtoken)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007682 int j = wtoken.windows.size();
7683 while (j > 0) {
7684 j--;
7685 WindowState win = wtoken.windows.get(j);
7686 //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
7687 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
7688 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
7689 //Log.i(TAG, "Found base or application window, done!");
7690 if (wtoken.appFullscreen) {
7691 return win.mAttrs;
7692 }
7693 if (animSrc < 2) {
7694 animParams = win.mAttrs;
7695 animSrc = 2;
7696 }
7697 } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
7698 //Log.i(TAG, "Found normal window, we may use this...");
7699 animParams = win.mAttrs;
7700 animSrc = 1;
7701 }
7702 }
7703 }
7704 }
Romain Guy06882f82009-06-10 13:36:04 -07007705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007706 return animParams;
7707 }
Romain Guy06882f82009-06-10 13:36:04 -07007708
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007709 private static LayoutParams findCompatibleWindowParams(ArrayList<AppWindowToken> tokenList) {
7710 for (int appCount = tokenList.size() - 1; appCount >= 0; appCount--) {
7711 AppWindowToken wtoken = tokenList.get(appCount);
7712 // Just checking one window is sufficient as all windows have the compatible flag
7713 // if the application is in compatibility mode.
7714 if (wtoken.windows.size() > 0) {
7715 WindowManager.LayoutParams params = wtoken.windows.get(0).mAttrs;
7716 if ((params.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
7717 return params;
7718 }
7719 }
7720 }
7721 return null;
7722 }
7723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 // -------------------------------------------------------------
7725 // DummyAnimation
7726 // -------------------------------------------------------------
7727
7728 // This is an animation that does nothing: it just immediately finishes
7729 // itself every time it is called. It is used as a stub animation in cases
7730 // where we want to synchronize multiple things that may be animating.
7731 static final class DummyAnimation extends Animation {
7732 public boolean getTransformation(long currentTime, Transformation outTransformation) {
7733 return false;
7734 }
7735 }
7736 static final Animation sDummyAnimation = new DummyAnimation();
Romain Guy06882f82009-06-10 13:36:04 -07007737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007738 // -------------------------------------------------------------
7739 // Async Handler
7740 // -------------------------------------------------------------
7741
7742 static final class StartingData {
7743 final String pkg;
7744 final int theme;
7745 final CharSequence nonLocalizedLabel;
7746 final int labelRes;
7747 final int icon;
Romain Guy06882f82009-06-10 13:36:04 -07007748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007749 StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
7750 int _labelRes, int _icon) {
7751 pkg = _pkg;
7752 theme = _theme;
7753 nonLocalizedLabel = _nonLocalizedLabel;
7754 labelRes = _labelRes;
7755 icon = _icon;
7756 }
7757 }
7758
7759 private final class H extends Handler {
7760 public static final int REPORT_FOCUS_CHANGE = 2;
7761 public static final int REPORT_LOSING_FOCUS = 3;
7762 public static final int ANIMATE = 4;
7763 public static final int ADD_STARTING = 5;
7764 public static final int REMOVE_STARTING = 6;
7765 public static final int FINISHED_STARTING = 7;
7766 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007767 public static final int WINDOW_FREEZE_TIMEOUT = 11;
7768 public static final int HOLD_SCREEN_CHANGED = 12;
7769 public static final int APP_TRANSITION_TIMEOUT = 13;
7770 public static final int PERSIST_ANIMATION_SCALE = 14;
7771 public static final int FORCE_GC = 15;
7772 public static final int ENABLE_SCREEN = 16;
7773 public static final int APP_FREEZE_TIMEOUT = 17;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007774 public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
Romain Guy06882f82009-06-10 13:36:04 -07007775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007776 private Session mLastReportedHold;
Romain Guy06882f82009-06-10 13:36:04 -07007777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007778 public H() {
7779 }
Romain Guy06882f82009-06-10 13:36:04 -07007780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007781 @Override
7782 public void handleMessage(Message msg) {
7783 switch (msg.what) {
7784 case REPORT_FOCUS_CHANGE: {
7785 WindowState lastFocus;
7786 WindowState newFocus;
Romain Guy06882f82009-06-10 13:36:04 -07007787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007788 synchronized(mWindowMap) {
7789 lastFocus = mLastFocus;
7790 newFocus = mCurrentFocus;
7791 if (lastFocus == newFocus) {
7792 // Focus is not changing, so nothing to do.
7793 return;
7794 }
7795 mLastFocus = newFocus;
7796 //Log.i(TAG, "Focus moving from " + lastFocus
7797 // + " to " + newFocus);
7798 if (newFocus != null && lastFocus != null
7799 && !newFocus.isDisplayedLw()) {
7800 //Log.i(TAG, "Delaying loss of focus...");
7801 mLosingFocus.add(lastFocus);
7802 lastFocus = null;
7803 }
7804 }
7805
7806 if (lastFocus != newFocus) {
7807 //System.out.println("Changing focus from " + lastFocus
7808 // + " to " + newFocus);
7809 if (newFocus != null) {
7810 try {
7811 //Log.i(TAG, "Gaining focus: " + newFocus);
7812 newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7813 } catch (RemoteException e) {
7814 // Ignore if process has died.
7815 }
7816 }
7817
7818 if (lastFocus != null) {
7819 try {
7820 //Log.i(TAG, "Losing focus: " + lastFocus);
7821 lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7822 } catch (RemoteException e) {
7823 // Ignore if process has died.
7824 }
7825 }
7826 }
7827 } break;
7828
7829 case REPORT_LOSING_FOCUS: {
7830 ArrayList<WindowState> losers;
Romain Guy06882f82009-06-10 13:36:04 -07007831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007832 synchronized(mWindowMap) {
7833 losers = mLosingFocus;
7834 mLosingFocus = new ArrayList<WindowState>();
7835 }
7836
7837 final int N = losers.size();
7838 for (int i=0; i<N; i++) {
7839 try {
7840 //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
7841 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7842 } catch (RemoteException e) {
7843 // Ignore if process has died.
7844 }
7845 }
7846 } break;
7847
7848 case ANIMATE: {
7849 synchronized(mWindowMap) {
7850 mAnimationPending = false;
7851 performLayoutAndPlaceSurfacesLocked();
7852 }
7853 } break;
7854
7855 case ADD_STARTING: {
7856 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7857 final StartingData sd = wtoken.startingData;
7858
7859 if (sd == null) {
7860 // Animation has been canceled... do nothing.
7861 return;
7862 }
Romain Guy06882f82009-06-10 13:36:04 -07007863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007864 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
7865 + wtoken + ": pkg=" + sd.pkg);
Romain Guy06882f82009-06-10 13:36:04 -07007866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007867 View view = null;
7868 try {
7869 view = mPolicy.addStartingWindow(
7870 wtoken.token, sd.pkg,
7871 sd.theme, sd.nonLocalizedLabel, sd.labelRes,
7872 sd.icon);
7873 } catch (Exception e) {
7874 Log.w(TAG, "Exception when adding starting window", e);
7875 }
7876
7877 if (view != null) {
7878 boolean abort = false;
7879
7880 synchronized(mWindowMap) {
7881 if (wtoken.removed || wtoken.startingData == null) {
7882 // If the window was successfully added, then
7883 // we need to remove it.
7884 if (wtoken.startingWindow != null) {
7885 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7886 "Aborted starting " + wtoken
7887 + ": removed=" + wtoken.removed
7888 + " startingData=" + wtoken.startingData);
7889 wtoken.startingWindow = null;
7890 wtoken.startingData = null;
7891 abort = true;
7892 }
7893 } else {
7894 wtoken.startingView = view;
7895 }
7896 if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
7897 "Added starting " + wtoken
7898 + ": startingWindow="
7899 + wtoken.startingWindow + " startingView="
7900 + wtoken.startingView);
7901 }
7902
7903 if (abort) {
7904 try {
7905 mPolicy.removeStartingWindow(wtoken.token, view);
7906 } catch (Exception e) {
7907 Log.w(TAG, "Exception when removing starting window", e);
7908 }
7909 }
7910 }
7911 } break;
7912
7913 case REMOVE_STARTING: {
7914 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7915 IBinder token = null;
7916 View view = null;
7917 synchronized (mWindowMap) {
7918 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
7919 + wtoken + ": startingWindow="
7920 + wtoken.startingWindow + " startingView="
7921 + wtoken.startingView);
7922 if (wtoken.startingWindow != null) {
7923 view = wtoken.startingView;
7924 token = wtoken.token;
7925 wtoken.startingData = null;
7926 wtoken.startingView = null;
7927 wtoken.startingWindow = null;
7928 }
7929 }
7930 if (view != null) {
7931 try {
7932 mPolicy.removeStartingWindow(token, view);
7933 } catch (Exception e) {
7934 Log.w(TAG, "Exception when removing starting window", e);
7935 }
7936 }
7937 } break;
7938
7939 case FINISHED_STARTING: {
7940 IBinder token = null;
7941 View view = null;
7942 while (true) {
7943 synchronized (mWindowMap) {
7944 final int N = mFinishedStarting.size();
7945 if (N <= 0) {
7946 break;
7947 }
7948 AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7949
7950 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7951 "Finished starting " + wtoken
7952 + ": startingWindow=" + wtoken.startingWindow
7953 + " startingView=" + wtoken.startingView);
7954
7955 if (wtoken.startingWindow == null) {
7956 continue;
7957 }
7958
7959 view = wtoken.startingView;
7960 token = wtoken.token;
7961 wtoken.startingData = null;
7962 wtoken.startingView = null;
7963 wtoken.startingWindow = null;
7964 }
7965
7966 try {
7967 mPolicy.removeStartingWindow(token, view);
7968 } catch (Exception e) {
7969 Log.w(TAG, "Exception when removing starting window", e);
7970 }
7971 }
7972 } break;
7973
7974 case REPORT_APPLICATION_TOKEN_WINDOWS: {
7975 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7976
7977 boolean nowVisible = msg.arg1 != 0;
7978 boolean nowGone = msg.arg2 != 0;
7979
7980 try {
7981 if (DEBUG_VISIBILITY) Log.v(
7982 TAG, "Reporting visible in " + wtoken
7983 + " visible=" + nowVisible
7984 + " gone=" + nowGone);
7985 if (nowVisible) {
7986 wtoken.appToken.windowsVisible();
7987 } else {
7988 wtoken.appToken.windowsGone();
7989 }
7990 } catch (RemoteException ex) {
7991 }
7992 } break;
Romain Guy06882f82009-06-10 13:36:04 -07007993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007994 case WINDOW_FREEZE_TIMEOUT: {
7995 synchronized (mWindowMap) {
7996 Log.w(TAG, "Window freeze timeout expired.");
7997 int i = mWindows.size();
7998 while (i > 0) {
7999 i--;
8000 WindowState w = (WindowState)mWindows.get(i);
8001 if (w.mOrientationChanging) {
8002 w.mOrientationChanging = false;
8003 Log.w(TAG, "Force clearing orientation change: " + w);
8004 }
8005 }
8006 performLayoutAndPlaceSurfacesLocked();
8007 }
8008 break;
8009 }
Romain Guy06882f82009-06-10 13:36:04 -07008010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008011 case HOLD_SCREEN_CHANGED: {
8012 Session oldHold;
8013 Session newHold;
8014 synchronized (mWindowMap) {
8015 oldHold = mLastReportedHold;
8016 newHold = (Session)msg.obj;
8017 mLastReportedHold = newHold;
8018 }
Romain Guy06882f82009-06-10 13:36:04 -07008019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008020 if (oldHold != newHold) {
8021 try {
8022 if (oldHold != null) {
8023 mBatteryStats.noteStopWakelock(oldHold.mUid,
8024 "window",
8025 BatteryStats.WAKE_TYPE_WINDOW);
8026 }
8027 if (newHold != null) {
8028 mBatteryStats.noteStartWakelock(newHold.mUid,
8029 "window",
8030 BatteryStats.WAKE_TYPE_WINDOW);
8031 }
8032 } catch (RemoteException e) {
8033 }
8034 }
8035 break;
8036 }
Romain Guy06882f82009-06-10 13:36:04 -07008037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008038 case APP_TRANSITION_TIMEOUT: {
8039 synchronized (mWindowMap) {
8040 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
8041 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8042 "*** APP TRANSITION TIMEOUT");
8043 mAppTransitionReady = true;
8044 mAppTransitionTimeout = true;
8045 performLayoutAndPlaceSurfacesLocked();
8046 }
8047 }
8048 break;
8049 }
Romain Guy06882f82009-06-10 13:36:04 -07008050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008051 case PERSIST_ANIMATION_SCALE: {
8052 Settings.System.putFloat(mContext.getContentResolver(),
8053 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
8054 Settings.System.putFloat(mContext.getContentResolver(),
8055 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
8056 break;
8057 }
Romain Guy06882f82009-06-10 13:36:04 -07008058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008059 case FORCE_GC: {
8060 synchronized(mWindowMap) {
8061 if (mAnimationPending) {
8062 // If we are animating, don't do the gc now but
8063 // delay a bit so we don't interrupt the animation.
8064 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8065 2000);
8066 return;
8067 }
8068 // If we are currently rotating the display, it will
8069 // schedule a new message when done.
8070 if (mDisplayFrozen) {
8071 return;
8072 }
8073 mFreezeGcPending = 0;
8074 }
8075 Runtime.getRuntime().gc();
8076 break;
8077 }
Romain Guy06882f82009-06-10 13:36:04 -07008078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008079 case ENABLE_SCREEN: {
8080 performEnableScreen();
8081 break;
8082 }
Romain Guy06882f82009-06-10 13:36:04 -07008083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008084 case APP_FREEZE_TIMEOUT: {
8085 synchronized (mWindowMap) {
8086 Log.w(TAG, "App freeze timeout expired.");
8087 int i = mAppTokens.size();
8088 while (i > 0) {
8089 i--;
8090 AppWindowToken tok = mAppTokens.get(i);
8091 if (tok.freezingScreen) {
8092 Log.w(TAG, "Force clearing freeze: " + tok);
8093 unsetAppFreezingScreenLocked(tok, true, true);
8094 }
8095 }
8096 }
8097 break;
8098 }
Romain Guy06882f82009-06-10 13:36:04 -07008099
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07008100 case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
Dianne Hackborncfaef692009-06-15 14:24:44 -07008101 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07008102 sendNewConfiguration();
8103 }
8104 break;
8105 }
Romain Guy06882f82009-06-10 13:36:04 -07008106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008107 }
8108 }
8109 }
8110
8111 // -------------------------------------------------------------
8112 // IWindowManager API
8113 // -------------------------------------------------------------
8114
8115 public IWindowSession openSession(IInputMethodClient client,
8116 IInputContext inputContext) {
8117 if (client == null) throw new IllegalArgumentException("null client");
8118 if (inputContext == null) throw new IllegalArgumentException("null inputContext");
8119 return new Session(client, inputContext);
8120 }
8121
8122 public boolean inputMethodClientHasFocus(IInputMethodClient client) {
8123 synchronized (mWindowMap) {
8124 // The focus for the client is the window immediately below
8125 // where we would place the input method window.
8126 int idx = findDesiredInputMethodWindowIndexLocked(false);
8127 WindowState imFocus;
8128 if (idx > 0) {
8129 imFocus = (WindowState)mWindows.get(idx-1);
8130 if (imFocus != null) {
8131 if (imFocus.mSession.mClient != null &&
8132 imFocus.mSession.mClient.asBinder() == client.asBinder()) {
8133 return true;
8134 }
8135 }
8136 }
8137 }
8138 return false;
8139 }
Romain Guy06882f82009-06-10 13:36:04 -07008140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008141 // -------------------------------------------------------------
8142 // Internals
8143 // -------------------------------------------------------------
8144
8145 final WindowState windowForClientLocked(Session session, IWindow client) {
8146 return windowForClientLocked(session, client.asBinder());
8147 }
Romain Guy06882f82009-06-10 13:36:04 -07008148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008149 final WindowState windowForClientLocked(Session session, IBinder client) {
8150 WindowState win = mWindowMap.get(client);
8151 if (localLOGV) Log.v(
8152 TAG, "Looking up client " + client + ": " + win);
8153 if (win == null) {
8154 RuntimeException ex = new RuntimeException();
8155 Log.w(TAG, "Requested window " + client + " does not exist", ex);
8156 return null;
8157 }
8158 if (session != null && win.mSession != session) {
8159 RuntimeException ex = new RuntimeException();
8160 Log.w(TAG, "Requested window " + client + " is in session " +
8161 win.mSession + ", not " + session, ex);
8162 return null;
8163 }
8164
8165 return win;
8166 }
8167
8168 private final void assignLayersLocked() {
8169 int N = mWindows.size();
8170 int curBaseLayer = 0;
8171 int curLayer = 0;
8172 int i;
Romain Guy06882f82009-06-10 13:36:04 -07008173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008174 for (i=0; i<N; i++) {
8175 WindowState w = (WindowState)mWindows.get(i);
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07008176 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
8177 || (i > 0 && w.mIsWallpaper)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008178 curLayer += WINDOW_LAYER_MULTIPLIER;
8179 w.mLayer = curLayer;
8180 } else {
8181 curBaseLayer = curLayer = w.mBaseLayer;
8182 w.mLayer = curLayer;
8183 }
8184 if (w.mTargetAppToken != null) {
8185 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
8186 } else if (w.mAppToken != null) {
8187 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
8188 } else {
8189 w.mAnimLayer = w.mLayer;
8190 }
8191 if (w.mIsImWindow) {
8192 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
Dianne Hackborn759a39e2009-08-09 17:20:27 -07008193 } else if (w.mIsWallpaper) {
8194 w.mAnimLayer += mWallpaperAnimLayerAdjustment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008195 }
8196 if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
8197 + w.mAnimLayer);
8198 //System.out.println(
8199 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
8200 }
8201 }
8202
8203 private boolean mInLayout = false;
8204 private final void performLayoutAndPlaceSurfacesLocked() {
8205 if (mInLayout) {
Dave Bortcfe65242009-04-09 14:51:04 -07008206 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008207 throw new RuntimeException("Recursive call!");
8208 }
8209 Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
8210 return;
8211 }
8212
8213 boolean recoveringMemory = false;
8214 if (mForceRemoves != null) {
8215 recoveringMemory = true;
8216 // Wait a little it for things to settle down, and off we go.
8217 for (int i=0; i<mForceRemoves.size(); i++) {
8218 WindowState ws = mForceRemoves.get(i);
8219 Log.i(TAG, "Force removing: " + ws);
8220 removeWindowInnerLocked(ws.mSession, ws);
8221 }
8222 mForceRemoves = null;
8223 Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
8224 Object tmp = new Object();
8225 synchronized (tmp) {
8226 try {
8227 tmp.wait(250);
8228 } catch (InterruptedException e) {
8229 }
8230 }
8231 }
Romain Guy06882f82009-06-10 13:36:04 -07008232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008233 mInLayout = true;
8234 try {
8235 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
Romain Guy06882f82009-06-10 13:36:04 -07008236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008237 int i = mPendingRemove.size()-1;
8238 if (i >= 0) {
8239 while (i >= 0) {
8240 WindowState w = mPendingRemove.get(i);
8241 removeWindowInnerLocked(w.mSession, w);
8242 i--;
8243 }
8244 mPendingRemove.clear();
8245
8246 mInLayout = false;
8247 assignLayersLocked();
8248 mLayoutNeeded = true;
8249 performLayoutAndPlaceSurfacesLocked();
8250
8251 } else {
8252 mInLayout = false;
8253 if (mLayoutNeeded) {
8254 requestAnimationLocked(0);
8255 }
8256 }
8257 } catch (RuntimeException e) {
8258 mInLayout = false;
8259 Log.e(TAG, "Unhandled exception while layout out windows", e);
8260 }
8261 }
8262
8263 private final void performLayoutLockedInner() {
8264 final int dw = mDisplay.getWidth();
8265 final int dh = mDisplay.getHeight();
8266
8267 final int N = mWindows.size();
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07008268 int repeats = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008269 int i;
8270
8271 // FIRST LOOP: Perform a layout, if needed.
Romain Guy06882f82009-06-10 13:36:04 -07008272
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07008273 while (mLayoutNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008274 mPolicy.beginLayoutLw(dw, dh);
8275
8276 // First perform layout of any root windows (not attached
8277 // to another window).
8278 int topAttached = -1;
8279 for (i = N-1; i >= 0; i--) {
8280 WindowState win = (WindowState) mWindows.get(i);
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07008281
8282 // Don't do layout of a window if it is not visible, or
8283 // soon won't be visible, to avoid wasting time and funky
8284 // changes while a window is animating away.
8285 final AppWindowToken atoken = win.mAppToken;
8286 final boolean gone = win.mViewVisibility == View.GONE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008287 || !win.mRelayoutCalled
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07008288 || win.mRootToken.hidden
8289 || (atoken != null && atoken.hiddenRequested)
8290 || !win.mPolicyVisibility
8291 || win.mAttachedHidden
8292 || win.mExiting || win.mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008293
8294 // If this view is GONE, then skip it -- keep the current
8295 // frame, and let the caller know so they can ignore it
8296 // if they want. (We do the normal layout for INVISIBLE
8297 // windows, since that means "perform layout as normal,
8298 // just don't display").
8299 if (!gone || !win.mHaveFrame) {
8300 if (!win.mLayoutAttached) {
8301 mPolicy.layoutWindowLw(win, win.mAttrs, null);
8302 } else {
8303 if (topAttached < 0) topAttached = i;
8304 }
8305 }
8306 }
Romain Guy06882f82009-06-10 13:36:04 -07008307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008308 // Now perform layout of attached windows, which usually
8309 // depend on the position of the window they are attached to.
8310 // XXX does not deal with windows that are attached to windows
8311 // that are themselves attached.
8312 for (i = topAttached; i >= 0; i--) {
8313 WindowState win = (WindowState) mWindows.get(i);
8314
8315 // If this view is GONE, then skip it -- keep the current
8316 // frame, and let the caller know so they can ignore it
8317 // if they want. (We do the normal layout for INVISIBLE
8318 // windows, since that means "perform layout as normal,
8319 // just don't display").
8320 if (win.mLayoutAttached) {
8321 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8322 || !win.mHaveFrame) {
8323 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8324 }
8325 }
8326 }
8327
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07008328 if (!mPolicy.finishLayoutLw()) {
8329 mLayoutNeeded = false;
8330 } else if (repeats > 2) {
8331 Log.w(TAG, "Layout repeat aborted after too many iterations");
8332 mLayoutNeeded = false;
8333 } else {
8334 repeats++;
8335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008336 }
8337 }
Romain Guy06882f82009-06-10 13:36:04 -07008338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008339 private final void performLayoutAndPlaceSurfacesLockedInner(
8340 boolean recoveringMemory) {
8341 final long currentTime = SystemClock.uptimeMillis();
8342 final int dw = mDisplay.getWidth();
8343 final int dh = mDisplay.getHeight();
8344
8345 final int N = mWindows.size();
8346 int i;
8347
8348 // FIRST LOOP: Perform a layout, if needed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008349 performLayoutLockedInner();
Romain Guy06882f82009-06-10 13:36:04 -07008350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008351 if (mFxSession == null) {
8352 mFxSession = new SurfaceSession();
8353 }
Romain Guy06882f82009-06-10 13:36:04 -07008354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008355 if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
8356
8357 // Initialize state of exiting tokens.
8358 for (i=mExitingTokens.size()-1; i>=0; i--) {
8359 mExitingTokens.get(i).hasVisible = false;
8360 }
8361
8362 // Initialize state of exiting applications.
8363 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8364 mExitingAppTokens.get(i).hasVisible = false;
8365 }
8366
8367 // SECOND LOOP: Execute animations and update visibility of windows.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008368 boolean orientationChangeComplete = true;
8369 Session holdScreen = null;
8370 float screenBrightness = -1;
8371 boolean focusDisplayed = false;
8372 boolean animating = false;
8373
8374 Surface.openTransaction();
8375 try {
8376 boolean restart;
8377
8378 do {
8379 final int transactionSequence = ++mTransactionSequence;
8380
8381 // Update animations of all applications, including those
8382 // associated with exiting/removed apps
8383 boolean tokensAnimating = false;
8384 final int NAT = mAppTokens.size();
8385 for (i=0; i<NAT; i++) {
8386 if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
8387 tokensAnimating = true;
8388 }
8389 }
8390 final int NEAT = mExitingAppTokens.size();
8391 for (i=0; i<NEAT; i++) {
8392 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
8393 tokensAnimating = true;
8394 }
8395 }
8396
8397 animating = tokensAnimating;
8398 restart = false;
8399
8400 boolean tokenMayBeDrawn = false;
8401
8402 mPolicy.beginAnimationLw(dw, dh);
8403
8404 for (i=N-1; i>=0; i--) {
8405 WindowState w = (WindowState)mWindows.get(i);
8406
8407 final WindowManager.LayoutParams attrs = w.mAttrs;
8408
8409 if (w.mSurface != null) {
8410 // Execute animation.
8411 w.commitFinishDrawingLocked(currentTime);
8412 if (w.stepAnimationLocked(currentTime, dw, dh)) {
8413 animating = true;
8414 //w.dump(" ");
8415 }
8416
8417 mPolicy.animatingWindowLw(w, attrs);
8418 }
8419
8420 final AppWindowToken atoken = w.mAppToken;
8421 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
8422 if (atoken.lastTransactionSequence != transactionSequence) {
8423 atoken.lastTransactionSequence = transactionSequence;
8424 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
8425 atoken.startingDisplayed = false;
8426 }
8427 if ((w.isOnScreen() || w.mAttrs.type
8428 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
8429 && !w.mExiting && !w.mDestroying) {
8430 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
8431 Log.v(TAG, "Eval win " + w + ": isDisplayed="
8432 + w.isDisplayedLw()
8433 + ", isAnimating=" + w.isAnimating());
8434 if (!w.isDisplayedLw()) {
8435 Log.v(TAG, "Not displayed: s=" + w.mSurface
8436 + " pv=" + w.mPolicyVisibility
8437 + " dp=" + w.mDrawPending
8438 + " cdp=" + w.mCommitDrawPending
8439 + " ah=" + w.mAttachedHidden
8440 + " th=" + atoken.hiddenRequested
8441 + " a=" + w.mAnimating);
8442 }
8443 }
8444 if (w != atoken.startingWindow) {
8445 if (!atoken.freezingScreen || !w.mAppFreezing) {
8446 atoken.numInterestingWindows++;
8447 if (w.isDisplayedLw()) {
8448 atoken.numDrawnWindows++;
8449 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
8450 "tokenMayBeDrawn: " + atoken
8451 + " freezingScreen=" + atoken.freezingScreen
8452 + " mAppFreezing=" + w.mAppFreezing);
8453 tokenMayBeDrawn = true;
8454 }
8455 }
8456 } else if (w.isDisplayedLw()) {
8457 atoken.startingDisplayed = true;
8458 }
8459 }
8460 } else if (w.mReadyToShow) {
8461 w.performShowLocked();
8462 }
8463 }
8464
8465 if (mPolicy.finishAnimationLw()) {
8466 restart = true;
8467 }
8468
8469 if (tokenMayBeDrawn) {
8470 // See if any windows have been drawn, so they (and others
8471 // associated with them) can now be shown.
8472 final int NT = mTokenList.size();
8473 for (i=0; i<NT; i++) {
8474 AppWindowToken wtoken = mTokenList.get(i).appWindowToken;
8475 if (wtoken == null) {
8476 continue;
8477 }
8478 if (wtoken.freezingScreen) {
8479 int numInteresting = wtoken.numInterestingWindows;
8480 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8481 if (DEBUG_VISIBILITY) Log.v(TAG,
8482 "allDrawn: " + wtoken
8483 + " interesting=" + numInteresting
8484 + " drawn=" + wtoken.numDrawnWindows);
8485 wtoken.showAllWindowsLocked();
8486 unsetAppFreezingScreenLocked(wtoken, false, true);
8487 orientationChangeComplete = true;
8488 }
8489 } else if (!wtoken.allDrawn) {
8490 int numInteresting = wtoken.numInterestingWindows;
8491 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8492 if (DEBUG_VISIBILITY) Log.v(TAG,
8493 "allDrawn: " + wtoken
8494 + " interesting=" + numInteresting
8495 + " drawn=" + wtoken.numDrawnWindows);
8496 wtoken.allDrawn = true;
8497 restart = true;
8498
8499 // We can now show all of the drawn windows!
8500 if (!mOpeningApps.contains(wtoken)) {
8501 wtoken.showAllWindowsLocked();
8502 }
8503 }
8504 }
8505 }
8506 }
8507
8508 // If we are ready to perform an app transition, check through
8509 // all of the app tokens to be shown and see if they are ready
8510 // to go.
8511 if (mAppTransitionReady) {
8512 int NN = mOpeningApps.size();
8513 boolean goodToGo = true;
8514 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8515 "Checking " + NN + " opening apps (frozen="
8516 + mDisplayFrozen + " timeout="
8517 + mAppTransitionTimeout + ")...");
8518 if (!mDisplayFrozen && !mAppTransitionTimeout) {
8519 // If the display isn't frozen, wait to do anything until
8520 // all of the apps are ready. Otherwise just go because
8521 // we'll unfreeze the display when everyone is ready.
8522 for (i=0; i<NN && goodToGo; i++) {
8523 AppWindowToken wtoken = mOpeningApps.get(i);
8524 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8525 "Check opening app" + wtoken + ": allDrawn="
8526 + wtoken.allDrawn + " startingDisplayed="
8527 + wtoken.startingDisplayed);
8528 if (!wtoken.allDrawn && !wtoken.startingDisplayed
8529 && !wtoken.startingMoved) {
8530 goodToGo = false;
8531 }
8532 }
8533 }
8534 if (goodToGo) {
8535 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
8536 int transit = mNextAppTransition;
8537 if (mSkipAppTransitionAnimation) {
8538 transit = WindowManagerPolicy.TRANSIT_NONE;
8539 }
8540 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8541 mAppTransitionReady = false;
8542 mAppTransitionTimeout = false;
8543 mStartingIconInTransition = false;
8544 mSkipAppTransitionAnimation = false;
8545
8546 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8547
8548 // We need to figure out which animation to use...
8549 WindowManager.LayoutParams lp = findAnimations(mAppTokens,
8550 mOpeningApps, mClosingApps);
8551
8552 NN = mOpeningApps.size();
8553 for (i=0; i<NN; i++) {
8554 AppWindowToken wtoken = mOpeningApps.get(i);
8555 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8556 "Now opening app" + wtoken);
8557 wtoken.reportedVisible = false;
8558 wtoken.inPendingTransaction = false;
8559 setTokenVisibilityLocked(wtoken, lp, true, transit, false);
8560 wtoken.updateReportedVisibilityLocked();
8561 wtoken.showAllWindowsLocked();
8562 }
8563 NN = mClosingApps.size();
8564 for (i=0; i<NN; i++) {
8565 AppWindowToken wtoken = mClosingApps.get(i);
8566 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8567 "Now closing app" + wtoken);
8568 wtoken.inPendingTransaction = false;
8569 setTokenVisibilityLocked(wtoken, lp, false, transit, false);
8570 wtoken.updateReportedVisibilityLocked();
8571 // Force the allDrawn flag, because we want to start
8572 // this guy's animations regardless of whether it's
8573 // gotten drawn.
8574 wtoken.allDrawn = true;
8575 }
8576
8577 mOpeningApps.clear();
8578 mClosingApps.clear();
8579
8580 // This has changed the visibility of windows, so perform
8581 // a new layout to get them all up-to-date.
8582 mLayoutNeeded = true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07008583 adjustWallpaperWindowsLocked();
Dianne Hackborn20583ff2009-07-27 21:51:05 -07008584 if (!moveInputMethodWindowsIfNeededLocked(true)) {
8585 assignLayersLocked();
8586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008587 performLayoutLockedInner();
8588 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
8589
8590 restart = true;
8591 }
8592 }
8593 } while (restart);
8594
8595 // THIRD LOOP: Update the surfaces of all windows.
8596
8597 final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8598
8599 boolean obscured = false;
8600 boolean blurring = false;
8601 boolean dimming = false;
8602 boolean covered = false;
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008603 boolean syswin = false;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008604 boolean backgroundFillerShown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605
8606 for (i=N-1; i>=0; i--) {
8607 WindowState w = (WindowState)mWindows.get(i);
8608
8609 boolean displayed = false;
8610 final WindowManager.LayoutParams attrs = w.mAttrs;
8611 final int attrFlags = attrs.flags;
8612
8613 if (w.mSurface != null) {
8614 w.computeShownFrameLocked();
8615 if (localLOGV) Log.v(
8616 TAG, "Placing surface #" + i + " " + w.mSurface
8617 + ": new=" + w.mShownFrame + ", old="
8618 + w.mLastShownFrame);
8619
8620 boolean resize;
8621 int width, height;
8622 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8623 resize = w.mLastRequestedWidth != w.mRequestedWidth ||
8624 w.mLastRequestedHeight != w.mRequestedHeight;
8625 // for a scaled surface, we just want to use
8626 // the requested size.
8627 width = w.mRequestedWidth;
8628 height = w.mRequestedHeight;
8629 w.mLastRequestedWidth = width;
8630 w.mLastRequestedHeight = height;
8631 w.mLastShownFrame.set(w.mShownFrame);
8632 try {
8633 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8634 } catch (RuntimeException e) {
8635 Log.w(TAG, "Error positioning surface in " + w, e);
8636 if (!recoveringMemory) {
8637 reclaimSomeSurfaceMemoryLocked(w, "position");
8638 }
8639 }
8640 } else {
8641 resize = !w.mLastShownFrame.equals(w.mShownFrame);
8642 width = w.mShownFrame.width();
8643 height = w.mShownFrame.height();
8644 w.mLastShownFrame.set(w.mShownFrame);
8645 if (resize) {
8646 if (SHOW_TRANSACTIONS) Log.i(
8647 TAG, " SURFACE " + w.mSurface + ": ("
8648 + w.mShownFrame.left + ","
8649 + w.mShownFrame.top + ") ("
8650 + w.mShownFrame.width() + "x"
8651 + w.mShownFrame.height() + ")");
8652 }
8653 }
8654
8655 if (resize) {
8656 if (width < 1) width = 1;
8657 if (height < 1) height = 1;
8658 if (w.mSurface != null) {
8659 try {
8660 w.mSurface.setSize(width, height);
8661 w.mSurface.setPosition(w.mShownFrame.left,
8662 w.mShownFrame.top);
8663 } catch (RuntimeException e) {
8664 // If something goes wrong with the surface (such
8665 // as running out of memory), don't take down the
8666 // entire system.
8667 Log.e(TAG, "Failure updating surface of " + w
8668 + "size=(" + width + "x" + height
8669 + "), pos=(" + w.mShownFrame.left
8670 + "," + w.mShownFrame.top + ")", e);
8671 if (!recoveringMemory) {
8672 reclaimSomeSurfaceMemoryLocked(w, "size");
8673 }
8674 }
8675 }
8676 }
8677 if (!w.mAppFreezing) {
8678 w.mContentInsetsChanged =
8679 !w.mLastContentInsets.equals(w.mContentInsets);
8680 w.mVisibleInsetsChanged =
8681 !w.mLastVisibleInsets.equals(w.mVisibleInsets);
Romain Guy06882f82009-06-10 13:36:04 -07008682 if (!w.mLastFrame.equals(w.mFrame)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008683 || w.mContentInsetsChanged
8684 || w.mVisibleInsetsChanged) {
8685 w.mLastFrame.set(w.mFrame);
8686 w.mLastContentInsets.set(w.mContentInsets);
8687 w.mLastVisibleInsets.set(w.mVisibleInsets);
8688 // If the orientation is changing, then we need to
8689 // hold off on unfreezing the display until this
8690 // window has been redrawn; to do that, we need
8691 // to go through the process of getting informed
8692 // by the application when it has finished drawing.
8693 if (w.mOrientationChanging) {
8694 if (DEBUG_ORIENTATION) Log.v(TAG,
8695 "Orientation start waiting for draw in "
8696 + w + ", surface " + w.mSurface);
8697 w.mDrawPending = true;
8698 w.mCommitDrawPending = false;
8699 w.mReadyToShow = false;
8700 if (w.mAppToken != null) {
8701 w.mAppToken.allDrawn = false;
8702 }
8703 }
Romain Guy06882f82009-06-10 13:36:04 -07008704 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008705 "Resizing window " + w + " to " + w.mFrame);
8706 mResizingWindows.add(w);
8707 } else if (w.mOrientationChanging) {
8708 if (!w.mDrawPending && !w.mCommitDrawPending) {
8709 if (DEBUG_ORIENTATION) Log.v(TAG,
8710 "Orientation not waiting for draw in "
8711 + w + ", surface " + w.mSurface);
8712 w.mOrientationChanging = false;
8713 }
8714 }
8715 }
8716
8717 if (w.mAttachedHidden) {
8718 if (!w.mLastHidden) {
8719 //dump();
8720 w.mLastHidden = true;
8721 if (SHOW_TRANSACTIONS) Log.i(
8722 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)");
8723 if (w.mSurface != null) {
8724 try {
8725 w.mSurface.hide();
8726 } catch (RuntimeException e) {
8727 Log.w(TAG, "Exception hiding surface in " + w);
8728 }
8729 }
8730 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8731 }
8732 // If we are waiting for this window to handle an
8733 // orientation change, well, it is hidden, so
8734 // doesn't really matter. Note that this does
8735 // introduce a potential glitch if the window
8736 // becomes unhidden before it has drawn for the
8737 // new orientation.
8738 if (w.mOrientationChanging) {
8739 w.mOrientationChanging = false;
8740 if (DEBUG_ORIENTATION) Log.v(TAG,
8741 "Orientation change skips hidden " + w);
8742 }
8743 } else if (!w.isReadyForDisplay()) {
8744 if (!w.mLastHidden) {
8745 //dump();
8746 w.mLastHidden = true;
8747 if (SHOW_TRANSACTIONS) Log.i(
8748 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)");
8749 if (w.mSurface != null) {
8750 try {
8751 w.mSurface.hide();
8752 } catch (RuntimeException e) {
8753 Log.w(TAG, "Exception exception hiding surface in " + w);
8754 }
8755 }
8756 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8757 }
8758 // If we are waiting for this window to handle an
8759 // orientation change, well, it is hidden, so
8760 // doesn't really matter. Note that this does
8761 // introduce a potential glitch if the window
8762 // becomes unhidden before it has drawn for the
8763 // new orientation.
8764 if (w.mOrientationChanging) {
8765 w.mOrientationChanging = false;
8766 if (DEBUG_ORIENTATION) Log.v(TAG,
8767 "Orientation change skips hidden " + w);
8768 }
8769 } else if (w.mLastLayer != w.mAnimLayer
8770 || w.mLastAlpha != w.mShownAlpha
8771 || w.mLastDsDx != w.mDsDx
8772 || w.mLastDtDx != w.mDtDx
8773 || w.mLastDsDy != w.mDsDy
8774 || w.mLastDtDy != w.mDtDy
8775 || w.mLastHScale != w.mHScale
8776 || w.mLastVScale != w.mVScale
8777 || w.mLastHidden) {
8778 displayed = true;
8779 w.mLastAlpha = w.mShownAlpha;
8780 w.mLastLayer = w.mAnimLayer;
8781 w.mLastDsDx = w.mDsDx;
8782 w.mLastDtDx = w.mDtDx;
8783 w.mLastDsDy = w.mDsDy;
8784 w.mLastDtDy = w.mDtDy;
8785 w.mLastHScale = w.mHScale;
8786 w.mLastVScale = w.mVScale;
8787 if (SHOW_TRANSACTIONS) Log.i(
8788 TAG, " SURFACE " + w.mSurface + ": alpha="
8789 + w.mShownAlpha + " layer=" + w.mAnimLayer);
8790 if (w.mSurface != null) {
8791 try {
8792 w.mSurface.setAlpha(w.mShownAlpha);
8793 w.mSurface.setLayer(w.mAnimLayer);
8794 w.mSurface.setMatrix(
8795 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8796 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8797 } catch (RuntimeException e) {
8798 Log.w(TAG, "Error updating surface in " + w, e);
8799 if (!recoveringMemory) {
8800 reclaimSomeSurfaceMemoryLocked(w, "update");
8801 }
8802 }
8803 }
8804
8805 if (w.mLastHidden && !w.mDrawPending
8806 && !w.mCommitDrawPending
8807 && !w.mReadyToShow) {
8808 if (SHOW_TRANSACTIONS) Log.i(
8809 TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)");
8810 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w
8811 + " during relayout");
8812 if (showSurfaceRobustlyLocked(w)) {
8813 w.mHasDrawn = true;
8814 w.mLastHidden = false;
8815 } else {
8816 w.mOrientationChanging = false;
8817 }
8818 }
8819 if (w.mSurface != null) {
8820 w.mToken.hasVisible = true;
8821 }
8822 } else {
8823 displayed = true;
8824 }
8825
8826 if (displayed) {
8827 if (!covered) {
8828 if (attrs.width == LayoutParams.FILL_PARENT
8829 && attrs.height == LayoutParams.FILL_PARENT) {
8830 covered = true;
8831 }
8832 }
8833 if (w.mOrientationChanging) {
8834 if (w.mDrawPending || w.mCommitDrawPending) {
8835 orientationChangeComplete = false;
8836 if (DEBUG_ORIENTATION) Log.v(TAG,
8837 "Orientation continue waiting for draw in " + w);
8838 } else {
8839 w.mOrientationChanging = false;
8840 if (DEBUG_ORIENTATION) Log.v(TAG,
8841 "Orientation change complete in " + w);
8842 }
8843 }
8844 w.mToken.hasVisible = true;
8845 }
8846 } else if (w.mOrientationChanging) {
8847 if (DEBUG_ORIENTATION) Log.v(TAG,
8848 "Orientation change skips hidden " + w);
8849 w.mOrientationChanging = false;
8850 }
8851
8852 final boolean canBeSeen = w.isDisplayedLw();
8853
8854 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8855 focusDisplayed = true;
8856 }
8857
8858 // Update effect.
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07008859 if (!(w.mObscured=obscured)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008860 if (w.mSurface != null) {
8861 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8862 holdScreen = w.mSession;
8863 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008864 if (!syswin && w.mAttrs.screenBrightness >= 0
8865 && screenBrightness < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008866 screenBrightness = w.mAttrs.screenBrightness;
8867 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008868 if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8869 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8870 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
8871 syswin = true;
8872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008873 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008874
8875 boolean opaqueDrawn = w.isOpaqueDrawn();
Dianne Hackborn759a39e2009-08-09 17:20:27 -07008876 if ((opaqueDrawn && w.isFullscreen(dw, dh))
8877 || attrs.type == TYPE_WALLPAPER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008878 // This window completely covers everything behind it,
8879 // so we want to leave all of them as unblurred (for
8880 // performance reasons).
8881 obscured = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008882 } else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
8883 if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008884 // This window is in compatibility mode, and needs background filler.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008885 obscured = true;
8886 if (mBackgroundFillerSurface == null) {
8887 try {
8888 mBackgroundFillerSurface = new Surface(mFxSession, 0,
8889 0, dw, dh,
8890 PixelFormat.OPAQUE,
8891 Surface.FX_SURFACE_NORMAL);
8892 } catch (Exception e) {
8893 Log.e(TAG, "Exception creating filler surface", e);
8894 }
8895 }
8896 try {
8897 mBackgroundFillerSurface.setPosition(0, 0);
8898 mBackgroundFillerSurface.setSize(dw, dh);
8899 // Using the same layer as Dim because they will never be shown at the
8900 // same time.
8901 mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
8902 mBackgroundFillerSurface.show();
8903 } catch (RuntimeException e) {
8904 Log.e(TAG, "Exception showing filler surface");
8905 }
8906 backgroundFillerShown = true;
8907 mBackgroundFillerShown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008908 } else if (canBeSeen && !obscured &&
8909 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8910 if (localLOGV) Log.v(TAG, "Win " + w
8911 + ": blurring=" + blurring
8912 + " obscured=" + obscured
8913 + " displayed=" + displayed);
8914 if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8915 if (!dimming) {
8916 //Log.i(TAG, "DIM BEHIND: " + w);
8917 dimming = true;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008918 if (mDimAnimator == null) {
8919 mDimAnimator = new DimAnimator(mFxSession);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008920 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008921 mDimAnimator.show(dw, dh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008922 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008923 mDimAnimator.updateParameters(w, currentTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008924 }
8925 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8926 if (!blurring) {
8927 //Log.i(TAG, "BLUR BEHIND: " + w);
8928 blurring = true;
8929 mBlurShown = true;
8930 if (mBlurSurface == null) {
8931 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8932 + mBlurSurface + ": CREATE");
8933 try {
Romain Guy06882f82009-06-10 13:36:04 -07008934 mBlurSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008935 -1, 16, 16,
8936 PixelFormat.OPAQUE,
8937 Surface.FX_SURFACE_BLUR);
8938 } catch (Exception e) {
8939 Log.e(TAG, "Exception creating Blur surface", e);
8940 }
8941 }
8942 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8943 + mBlurSurface + ": SHOW pos=(0,0) (" +
8944 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8945 if (mBlurSurface != null) {
8946 mBlurSurface.setPosition(0, 0);
8947 mBlurSurface.setSize(dw, dh);
8948 try {
8949 mBlurSurface.show();
8950 } catch (RuntimeException e) {
8951 Log.w(TAG, "Failure showing blur surface", e);
8952 }
8953 }
8954 }
8955 mBlurSurface.setLayer(w.mAnimLayer-2);
8956 }
8957 }
8958 }
8959 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008960
8961 if (backgroundFillerShown == false && mBackgroundFillerShown) {
8962 mBackgroundFillerShown = false;
8963 if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
8964 try {
8965 mBackgroundFillerSurface.hide();
8966 } catch (RuntimeException e) {
8967 Log.e(TAG, "Exception hiding filler surface", e);
8968 }
8969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008971 if (mDimAnimator != null && mDimAnimator.mDimShown) {
8972 animating |= mDimAnimator.updateSurface(dimming, currentTime, mDisplayFrozen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008973 }
Romain Guy06882f82009-06-10 13:36:04 -07008974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008975 if (!blurring && mBlurShown) {
8976 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
8977 + ": HIDE");
8978 try {
8979 mBlurSurface.hide();
8980 } catch (IllegalArgumentException e) {
8981 Log.w(TAG, "Illegal argument exception hiding blur surface");
8982 }
8983 mBlurShown = false;
8984 }
8985
8986 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
8987 } catch (RuntimeException e) {
8988 Log.e(TAG, "Unhandled exception in Window Manager", e);
8989 }
8990
8991 Surface.closeTransaction();
Romain Guy06882f82009-06-10 13:36:04 -07008992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008993 if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
8994 "With display frozen, orientationChangeComplete="
8995 + orientationChangeComplete);
8996 if (orientationChangeComplete) {
8997 if (mWindowsFreezingScreen) {
8998 mWindowsFreezingScreen = false;
8999 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9000 }
9001 if (mAppsFreezingScreen == 0) {
9002 stopFreezingDisplayLocked();
9003 }
9004 }
Romain Guy06882f82009-06-10 13:36:04 -07009005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009006 i = mResizingWindows.size();
9007 if (i > 0) {
9008 do {
9009 i--;
9010 WindowState win = mResizingWindows.get(i);
9011 try {
9012 win.mClient.resized(win.mFrame.width(),
9013 win.mFrame.height(), win.mLastContentInsets,
9014 win.mLastVisibleInsets, win.mDrawPending);
9015 win.mContentInsetsChanged = false;
9016 win.mVisibleInsetsChanged = false;
9017 } catch (RemoteException e) {
9018 win.mOrientationChanging = false;
9019 }
9020 } while (i > 0);
9021 mResizingWindows.clear();
9022 }
Romain Guy06882f82009-06-10 13:36:04 -07009023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024 // Destroy the surface of any windows that are no longer visible.
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07009025 boolean wallpaperDestroyed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009026 i = mDestroySurface.size();
9027 if (i > 0) {
9028 do {
9029 i--;
9030 WindowState win = mDestroySurface.get(i);
9031 win.mDestroying = false;
9032 if (mInputMethodWindow == win) {
9033 mInputMethodWindow = null;
9034 }
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07009035 if (win == mWallpaperTarget) {
9036 wallpaperDestroyed = true;
9037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009038 win.destroySurfaceLocked();
9039 } while (i > 0);
9040 mDestroySurface.clear();
9041 }
9042
9043 // Time to remove any exiting tokens?
9044 for (i=mExitingTokens.size()-1; i>=0; i--) {
9045 WindowToken token = mExitingTokens.get(i);
9046 if (!token.hasVisible) {
9047 mExitingTokens.remove(i);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07009048 if (token.windowType == TYPE_WALLPAPER) {
9049 mWallpaperTokens.remove(token);
9050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009051 }
9052 }
9053
9054 // Time to remove any exiting applications?
9055 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
9056 AppWindowToken token = mExitingAppTokens.get(i);
9057 if (!token.hasVisible && !mClosingApps.contains(token)) {
9058 mAppTokens.remove(token);
9059 mExitingAppTokens.remove(i);
9060 }
9061 }
9062
9063 if (focusDisplayed) {
9064 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9065 }
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07009066 if (wallpaperDestroyed) {
9067 wallpaperDestroyed = adjustWallpaperWindowsLocked();
9068 }
9069 if (wallpaperDestroyed) {
9070 requestAnimationLocked(0);
9071 } else if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009072 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
9073 }
9074 mQueue.setHoldScreenLocked(holdScreen != null);
9075 if (screenBrightness < 0 || screenBrightness > 1.0f) {
9076 mPowerManager.setScreenBrightnessOverride(-1);
9077 } else {
9078 mPowerManager.setScreenBrightnessOverride((int)
9079 (screenBrightness * Power.BRIGHTNESS_ON));
9080 }
9081 if (holdScreen != mHoldingScreenOn) {
9082 mHoldingScreenOn = holdScreen;
9083 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
9084 mH.sendMessage(m);
9085 }
9086 }
9087
9088 void requestAnimationLocked(long delay) {
9089 if (!mAnimationPending) {
9090 mAnimationPending = true;
9091 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
9092 }
9093 }
Romain Guy06882f82009-06-10 13:36:04 -07009094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 /**
9096 * Have the surface flinger show a surface, robustly dealing with
9097 * error conditions. In particular, if there is not enough memory
9098 * to show the surface, then we will try to get rid of other surfaces
9099 * in order to succeed.
Romain Guy06882f82009-06-10 13:36:04 -07009100 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009101 * @return Returns true if the surface was successfully shown.
9102 */
9103 boolean showSurfaceRobustlyLocked(WindowState win) {
9104 try {
9105 if (win.mSurface != null) {
9106 win.mSurface.show();
9107 }
9108 return true;
9109 } catch (RuntimeException e) {
9110 Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
9111 }
Romain Guy06882f82009-06-10 13:36:04 -07009112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009113 reclaimSomeSurfaceMemoryLocked(win, "show");
Romain Guy06882f82009-06-10 13:36:04 -07009114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009115 return false;
9116 }
Romain Guy06882f82009-06-10 13:36:04 -07009117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009118 void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
9119 final Surface surface = win.mSurface;
Romain Guy06882f82009-06-10 13:36:04 -07009120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009121 EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
9122 win.mSession.mPid, operation);
Romain Guy06882f82009-06-10 13:36:04 -07009123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009124 if (mForceRemoves == null) {
9125 mForceRemoves = new ArrayList<WindowState>();
9126 }
Romain Guy06882f82009-06-10 13:36:04 -07009127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009128 long callingIdentity = Binder.clearCallingIdentity();
9129 try {
9130 // There was some problem... first, do a sanity check of the
9131 // window list to make sure we haven't left any dangling surfaces
9132 // around.
9133 int N = mWindows.size();
9134 boolean leakedSurface = false;
9135 Log.i(TAG, "Out of memory for surface! Looking for leaks...");
9136 for (int i=0; i<N; i++) {
9137 WindowState ws = (WindowState)mWindows.get(i);
9138 if (ws.mSurface != null) {
9139 if (!mSessions.contains(ws.mSession)) {
9140 Log.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9141 + ws + " surface=" + ws.mSurface
9142 + " token=" + win.mToken
9143 + " pid=" + ws.mSession.mPid
9144 + " uid=" + ws.mSession.mUid);
9145 ws.mSurface.clear();
9146 ws.mSurface = null;
9147 mForceRemoves.add(ws);
9148 i--;
9149 N--;
9150 leakedSurface = true;
9151 } else if (win.mAppToken != null && win.mAppToken.clientHidden) {
9152 Log.w(TAG, "LEAKED SURFACE (app token hidden): "
9153 + ws + " surface=" + ws.mSurface
9154 + " token=" + win.mAppToken);
9155 ws.mSurface.clear();
9156 ws.mSurface = null;
9157 leakedSurface = true;
9158 }
9159 }
9160 }
Romain Guy06882f82009-06-10 13:36:04 -07009161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009162 boolean killedApps = false;
9163 if (!leakedSurface) {
9164 Log.w(TAG, "No leaked surfaces; killing applicatons!");
9165 SparseIntArray pidCandidates = new SparseIntArray();
9166 for (int i=0; i<N; i++) {
9167 WindowState ws = (WindowState)mWindows.get(i);
9168 if (ws.mSurface != null) {
9169 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
9170 }
9171 }
9172 if (pidCandidates.size() > 0) {
9173 int[] pids = new int[pidCandidates.size()];
9174 for (int i=0; i<pids.length; i++) {
9175 pids[i] = pidCandidates.keyAt(i);
9176 }
9177 try {
9178 if (mActivityManager.killPidsForMemory(pids)) {
9179 killedApps = true;
9180 }
9181 } catch (RemoteException e) {
9182 }
9183 }
9184 }
Romain Guy06882f82009-06-10 13:36:04 -07009185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009186 if (leakedSurface || killedApps) {
9187 // We managed to reclaim some memory, so get rid of the trouble
9188 // surface and ask the app to request another one.
9189 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9190 if (surface != null) {
9191 surface.clear();
9192 win.mSurface = null;
9193 }
Romain Guy06882f82009-06-10 13:36:04 -07009194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009195 try {
9196 win.mClient.dispatchGetNewSurface();
9197 } catch (RemoteException e) {
9198 }
9199 }
9200 } finally {
9201 Binder.restoreCallingIdentity(callingIdentity);
9202 }
9203 }
Romain Guy06882f82009-06-10 13:36:04 -07009204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009205 private boolean updateFocusedWindowLocked(int mode) {
9206 WindowState newFocus = computeFocusedWindowLocked();
9207 if (mCurrentFocus != newFocus) {
9208 // This check makes sure that we don't already have the focus
9209 // change message pending.
9210 mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9211 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9212 if (localLOGV) Log.v(
9213 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9214 final WindowState oldFocus = mCurrentFocus;
9215 mCurrentFocus = newFocus;
9216 mLosingFocus.remove(newFocus);
Romain Guy06882f82009-06-10 13:36:04 -07009217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009218 final WindowState imWindow = mInputMethodWindow;
9219 if (newFocus != imWindow && oldFocus != imWindow) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08009220 if (moveInputMethodWindowsIfNeededLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009221 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08009222 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9223 mLayoutNeeded = true;
9224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009225 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9226 performLayoutLockedInner();
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08009227 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9228 // Client will do the layout, but we need to assign layers
9229 // for handleNewWindowLocked() below.
9230 assignLayersLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009231 }
9232 }
Romain Guy06882f82009-06-10 13:36:04 -07009233
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08009234 if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9235 mKeyWaiter.handleNewWindowLocked(newFocus);
9236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009237 return true;
9238 }
9239 return false;
9240 }
9241
9242 private WindowState computeFocusedWindowLocked() {
9243 WindowState result = null;
9244 WindowState win;
9245
9246 int i = mWindows.size() - 1;
9247 int nextAppIndex = mAppTokens.size()-1;
9248 WindowToken nextApp = nextAppIndex >= 0
9249 ? mAppTokens.get(nextAppIndex) : null;
9250
9251 while (i >= 0) {
9252 win = (WindowState)mWindows.get(i);
9253
9254 if (localLOGV || DEBUG_FOCUS) Log.v(
9255 TAG, "Looking for focus: " + i
9256 + " = " + win
9257 + ", flags=" + win.mAttrs.flags
9258 + ", canReceive=" + win.canReceiveKeys());
9259
9260 AppWindowToken thisApp = win.mAppToken;
Romain Guy06882f82009-06-10 13:36:04 -07009261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009262 // If this window's application has been removed, just skip it.
9263 if (thisApp != null && thisApp.removed) {
9264 i--;
9265 continue;
9266 }
Romain Guy06882f82009-06-10 13:36:04 -07009267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009268 // If there is a focused app, don't allow focus to go to any
9269 // windows below it. If this is an application window, step
9270 // through the app tokens until we find its app.
9271 if (thisApp != null && nextApp != null && thisApp != nextApp
9272 && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9273 int origAppIndex = nextAppIndex;
9274 while (nextAppIndex > 0) {
9275 if (nextApp == mFocusedApp) {
9276 // Whoops, we are below the focused app... no focus
9277 // for you!
9278 if (localLOGV || DEBUG_FOCUS) Log.v(
9279 TAG, "Reached focused app: " + mFocusedApp);
9280 return null;
9281 }
9282 nextAppIndex--;
9283 nextApp = mAppTokens.get(nextAppIndex);
9284 if (nextApp == thisApp) {
9285 break;
9286 }
9287 }
9288 if (thisApp != nextApp) {
9289 // Uh oh, the app token doesn't exist! This shouldn't
9290 // happen, but if it does we can get totally hosed...
9291 // so restart at the original app.
9292 nextAppIndex = origAppIndex;
9293 nextApp = mAppTokens.get(nextAppIndex);
9294 }
9295 }
9296
9297 // Dispatch to this window if it is wants key events.
9298 if (win.canReceiveKeys()) {
9299 if (DEBUG_FOCUS) Log.v(
9300 TAG, "Found focus @ " + i + " = " + win);
9301 result = win;
9302 break;
9303 }
9304
9305 i--;
9306 }
9307
9308 return result;
9309 }
9310
9311 private void startFreezingDisplayLocked() {
9312 if (mDisplayFrozen) {
Chris Tate2ad63a92009-03-25 17:36:48 -07009313 // Freezing the display also suspends key event delivery, to
9314 // keep events from going astray while the display is reconfigured.
9315 // If someone has changed orientation again while the screen is
9316 // still frozen, the events will continue to be blocked while the
9317 // successive orientation change is processed. To prevent spurious
9318 // ANRs, we reset the event dispatch timeout in this case.
9319 synchronized (mKeyWaiter) {
9320 mKeyWaiter.mWasFrozen = true;
9321 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009322 return;
9323 }
Romain Guy06882f82009-06-10 13:36:04 -07009324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009325 mScreenFrozenLock.acquire();
Romain Guy06882f82009-06-10 13:36:04 -07009326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009327 long now = SystemClock.uptimeMillis();
9328 //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
9329 if (mFreezeGcPending != 0) {
9330 if (now > (mFreezeGcPending+1000)) {
9331 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
9332 mH.removeMessages(H.FORCE_GC);
9333 Runtime.getRuntime().gc();
9334 mFreezeGcPending = now;
9335 }
9336 } else {
9337 mFreezeGcPending = now;
9338 }
Romain Guy06882f82009-06-10 13:36:04 -07009339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009340 mDisplayFrozen = true;
9341 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
9342 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
9343 mAppTransitionReady = true;
9344 }
Romain Guy06882f82009-06-10 13:36:04 -07009345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009346 if (PROFILE_ORIENTATION) {
9347 File file = new File("/data/system/frozen");
9348 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9349 }
9350 Surface.freezeDisplay(0);
9351 }
Romain Guy06882f82009-06-10 13:36:04 -07009352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009353 private void stopFreezingDisplayLocked() {
9354 if (!mDisplayFrozen) {
9355 return;
9356 }
Romain Guy06882f82009-06-10 13:36:04 -07009357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009358 mDisplayFrozen = false;
9359 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9360 if (PROFILE_ORIENTATION) {
9361 Debug.stopMethodTracing();
9362 }
9363 Surface.unfreezeDisplay(0);
Romain Guy06882f82009-06-10 13:36:04 -07009364
Chris Tate2ad63a92009-03-25 17:36:48 -07009365 // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
9366 // too because regular key delivery processing should resume immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009367 synchronized (mKeyWaiter) {
9368 mKeyWaiter.mWasFrozen = true;
9369 mKeyWaiter.notifyAll();
9370 }
9371
9372 // A little kludge: a lot could have happened while the
9373 // display was frozen, so now that we are coming back we
9374 // do a gc so that any remote references the system
9375 // processes holds on others can be released if they are
9376 // no longer needed.
9377 mH.removeMessages(H.FORCE_GC);
9378 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9379 2000);
Romain Guy06882f82009-06-10 13:36:04 -07009380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009381 mScreenFrozenLock.release();
9382 }
Romain Guy06882f82009-06-10 13:36:04 -07009383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009384 @Override
9385 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9386 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9387 != PackageManager.PERMISSION_GRANTED) {
9388 pw.println("Permission Denial: can't dump WindowManager from from pid="
9389 + Binder.getCallingPid()
9390 + ", uid=" + Binder.getCallingUid());
9391 return;
9392 }
Romain Guy06882f82009-06-10 13:36:04 -07009393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009394 synchronized(mWindowMap) {
9395 pw.println("Current Window Manager state:");
9396 for (int i=mWindows.size()-1; i>=0; i--) {
9397 WindowState w = (WindowState)mWindows.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009398 pw.print(" Window #"); pw.print(i); pw.print(' ');
9399 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009400 w.dump(pw, " ");
9401 }
9402 if (mInputMethodDialogs.size() > 0) {
9403 pw.println(" ");
9404 pw.println(" Input method dialogs:");
9405 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9406 WindowState w = mInputMethodDialogs.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009407 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009408 }
9409 }
9410 if (mPendingRemove.size() > 0) {
9411 pw.println(" ");
9412 pw.println(" Remove pending for:");
9413 for (int i=mPendingRemove.size()-1; i>=0; i--) {
9414 WindowState w = mPendingRemove.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009415 pw.print(" Remove #"); pw.print(i); pw.print(' ');
9416 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009417 w.dump(pw, " ");
9418 }
9419 }
9420 if (mForceRemoves != null && mForceRemoves.size() > 0) {
9421 pw.println(" ");
9422 pw.println(" Windows force removing:");
9423 for (int i=mForceRemoves.size()-1; i>=0; i--) {
9424 WindowState w = mForceRemoves.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009425 pw.print(" Removing #"); pw.print(i); pw.print(' ');
9426 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009427 w.dump(pw, " ");
9428 }
9429 }
9430 if (mDestroySurface.size() > 0) {
9431 pw.println(" ");
9432 pw.println(" Windows waiting to destroy their surface:");
9433 for (int i=mDestroySurface.size()-1; i>=0; i--) {
9434 WindowState w = mDestroySurface.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009435 pw.print(" Destroy #"); pw.print(i); pw.print(' ');
9436 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009437 w.dump(pw, " ");
9438 }
9439 }
9440 if (mLosingFocus.size() > 0) {
9441 pw.println(" ");
9442 pw.println(" Windows losing focus:");
9443 for (int i=mLosingFocus.size()-1; i>=0; i--) {
9444 WindowState w = mLosingFocus.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009445 pw.print(" Losing #"); pw.print(i); pw.print(' ');
9446 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009447 w.dump(pw, " ");
9448 }
9449 }
9450 if (mSessions.size() > 0) {
9451 pw.println(" ");
9452 pw.println(" All active sessions:");
9453 Iterator<Session> it = mSessions.iterator();
9454 while (it.hasNext()) {
9455 Session s = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009456 pw.print(" Session "); pw.print(s); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 s.dump(pw, " ");
9458 }
9459 }
9460 if (mTokenMap.size() > 0) {
9461 pw.println(" ");
9462 pw.println(" All tokens:");
9463 Iterator<WindowToken> it = mTokenMap.values().iterator();
9464 while (it.hasNext()) {
9465 WindowToken token = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009466 pw.print(" Token "); pw.print(token.token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009467 token.dump(pw, " ");
9468 }
9469 }
9470 if (mTokenList.size() > 0) {
9471 pw.println(" ");
9472 pw.println(" Window token list:");
9473 for (int i=0; i<mTokenList.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009474 pw.print(" #"); pw.print(i); pw.print(": ");
9475 pw.println(mTokenList.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 }
9477 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07009478 if (mWallpaperTokens.size() > 0) {
9479 pw.println(" ");
9480 pw.println(" Wallpaper tokens:");
9481 for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9482 WindowToken token = mWallpaperTokens.get(i);
9483 pw.print(" Wallpaper #"); pw.print(i);
9484 pw.print(' '); pw.print(token); pw.println(':');
9485 token.dump(pw, " ");
9486 }
9487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009488 if (mAppTokens.size() > 0) {
9489 pw.println(" ");
9490 pw.println(" Application tokens in Z order:");
9491 for (int i=mAppTokens.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009492 pw.print(" App #"); pw.print(i); pw.print(": ");
9493 pw.println(mAppTokens.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009494 }
9495 }
9496 if (mFinishedStarting.size() > 0) {
9497 pw.println(" ");
9498 pw.println(" Finishing start of application tokens:");
9499 for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9500 WindowToken token = mFinishedStarting.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009501 pw.print(" Finished Starting #"); pw.print(i);
9502 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009503 token.dump(pw, " ");
9504 }
9505 }
9506 if (mExitingTokens.size() > 0) {
9507 pw.println(" ");
9508 pw.println(" Exiting tokens:");
9509 for (int i=mExitingTokens.size()-1; i>=0; i--) {
9510 WindowToken token = mExitingTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009511 pw.print(" Exiting #"); pw.print(i);
9512 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009513 token.dump(pw, " ");
9514 }
9515 }
9516 if (mExitingAppTokens.size() > 0) {
9517 pw.println(" ");
9518 pw.println(" Exiting application tokens:");
9519 for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9520 WindowToken token = mExitingAppTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009521 pw.print(" Exiting App #"); pw.print(i);
9522 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009523 token.dump(pw, " ");
9524 }
9525 }
9526 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009527 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
9528 pw.print(" mLastFocus="); pw.println(mLastFocus);
9529 pw.print(" mFocusedApp="); pw.println(mFocusedApp);
9530 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
9531 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
Dianne Hackbornf21adf62009-08-13 10:20:21 -07009532 pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009533 pw.print(" mInTouchMode="); pw.println(mInTouchMode);
9534 pw.print(" mSystemBooted="); pw.print(mSystemBooted);
9535 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9536 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
9537 pw.print(" mBlurShown="); pw.println(mBlurShown);
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009538 if (mDimAnimator != null) {
9539 mDimAnimator.printTo(pw);
9540 } else {
9541 pw.print( " no DimAnimator ");
9542 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009543 pw.print(" mInputMethodAnimLayerAdjustment=");
Dianne Hackborn759a39e2009-08-09 17:20:27 -07009544 pw.print(mInputMethodAnimLayerAdjustment);
9545 pw.print(" mWallpaperAnimLayerAdjustment=");
9546 pw.println(mWallpaperAnimLayerAdjustment);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009547 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
9548 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9549 pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
9550 pw.print(" mRotation="); pw.print(mRotation);
9551 pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
9552 pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
9553 pw.print(" mAnimationPending="); pw.print(mAnimationPending);
9554 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9555 pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9556 pw.print(" mNextAppTransition=0x");
9557 pw.print(Integer.toHexString(mNextAppTransition));
9558 pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
9559 pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9560 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9561 pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9562 if (mOpeningApps.size() > 0) {
9563 pw.print(" mOpeningApps="); pw.println(mOpeningApps);
9564 }
9565 if (mClosingApps.size() > 0) {
9566 pw.print(" mClosingApps="); pw.println(mClosingApps);
9567 }
9568 pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth());
9569 pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009570 pw.println(" KeyWaiter state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009571 pw.print(" mLastWin="); pw.print(mKeyWaiter.mLastWin);
9572 pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
9573 pw.print(" mFinished="); pw.print(mKeyWaiter.mFinished);
9574 pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
9575 pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
9576 pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009577 }
9578 }
9579
9580 public void monitor() {
9581 synchronized (mWindowMap) { }
9582 synchronized (mKeyguardDisabled) { }
9583 synchronized (mKeyWaiter) { }
9584 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009585
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07009586 public void virtualKeyFeedback(KeyEvent event) {
9587 mPolicy.keyFeedbackFromInput(event);
9588 }
9589
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009590 /**
9591 * DimAnimator class that controls the dim animation. This holds the surface and
9592 * all state used for dim animation.
9593 */
9594 private static class DimAnimator {
9595 Surface mDimSurface;
9596 boolean mDimShown = false;
9597 float mDimCurrentAlpha;
9598 float mDimTargetAlpha;
9599 float mDimDeltaPerMs;
9600 long mLastDimAnimTime;
9601
9602 DimAnimator (SurfaceSession session) {
9603 if (mDimSurface == null) {
9604 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9605 + mDimSurface + ": CREATE");
9606 try {
9607 mDimSurface = new Surface(session, 0, -1, 16, 16, PixelFormat.OPAQUE,
9608 Surface.FX_SURFACE_DIM);
9609 } catch (Exception e) {
9610 Log.e(TAG, "Exception creating Dim surface", e);
9611 }
9612 }
9613 }
9614
9615 /**
9616 * Show the dim surface.
9617 */
9618 void show(int dw, int dh) {
9619 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
9620 dw + "x" + dh + ")");
9621 mDimShown = true;
9622 try {
9623 mDimSurface.setPosition(0, 0);
9624 mDimSurface.setSize(dw, dh);
9625 mDimSurface.show();
9626 } catch (RuntimeException e) {
9627 Log.w(TAG, "Failure showing dim surface", e);
9628 }
9629 }
9630
9631 /**
9632 * Set's the dim surface's layer and update dim parameters that will be used in
9633 * {@link updateSurface} after all windows are examined.
9634 */
9635 void updateParameters(WindowState w, long currentTime) {
9636 mDimSurface.setLayer(w.mAnimLayer-1);
9637
9638 final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
9639 if (SHOW_TRANSACTIONS) Log.i(TAG, "layer=" + (w.mAnimLayer-1) + ", target=" + target);
9640 if (mDimTargetAlpha != target) {
9641 // If the desired dim level has changed, then
9642 // start an animation to it.
9643 mLastDimAnimTime = currentTime;
9644 long duration = (w.mAnimating && w.mAnimation != null)
9645 ? w.mAnimation.computeDurationHint()
9646 : DEFAULT_DIM_DURATION;
9647 if (target > mDimTargetAlpha) {
9648 // This is happening behind the activity UI,
9649 // so we can make it run a little longer to
9650 // give a stronger impression without disrupting
9651 // the user.
9652 duration *= DIM_DURATION_MULTIPLIER;
9653 }
9654 if (duration < 1) {
9655 // Don't divide by zero
9656 duration = 1;
9657 }
9658 mDimTargetAlpha = target;
9659 mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
9660 }
9661 }
9662
9663 /**
9664 * Updating the surface's alpha. Returns true if the animation continues, or returns
9665 * false when the animation is finished and the dim surface is hidden.
9666 */
9667 boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
9668 if (!dimming) {
9669 if (mDimTargetAlpha != 0) {
9670 mLastDimAnimTime = currentTime;
9671 mDimTargetAlpha = 0;
9672 mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
9673 }
9674 }
9675
9676 boolean animating = false;
9677 if (mLastDimAnimTime != 0) {
9678 mDimCurrentAlpha += mDimDeltaPerMs
9679 * (currentTime-mLastDimAnimTime);
9680 boolean more = true;
9681 if (displayFrozen) {
9682 // If the display is frozen, there is no reason to animate.
9683 more = false;
9684 } else if (mDimDeltaPerMs > 0) {
9685 if (mDimCurrentAlpha > mDimTargetAlpha) {
9686 more = false;
9687 }
9688 } else if (mDimDeltaPerMs < 0) {
9689 if (mDimCurrentAlpha < mDimTargetAlpha) {
9690 more = false;
9691 }
9692 } else {
9693 more = false;
9694 }
9695
9696 // Do we need to continue animating?
9697 if (more) {
9698 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9699 + mDimSurface + ": alpha=" + mDimCurrentAlpha);
9700 mLastDimAnimTime = currentTime;
9701 mDimSurface.setAlpha(mDimCurrentAlpha);
9702 animating = true;
9703 } else {
9704 mDimCurrentAlpha = mDimTargetAlpha;
9705 mLastDimAnimTime = 0;
9706 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9707 + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
9708 mDimSurface.setAlpha(mDimCurrentAlpha);
9709 if (!dimming) {
9710 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
9711 + ": HIDE");
9712 try {
9713 mDimSurface.hide();
9714 } catch (RuntimeException e) {
9715 Log.w(TAG, "Illegal argument exception hiding dim surface");
9716 }
9717 mDimShown = false;
9718 }
9719 }
9720 }
9721 return animating;
9722 }
9723
9724 public void printTo(PrintWriter pw) {
9725 pw.print(" mDimShown="); pw.print(mDimShown);
9726 pw.print(" current="); pw.print(mDimCurrentAlpha);
9727 pw.print(" target="); pw.print(mDimTargetAlpha);
9728 pw.print(" delta="); pw.print(mDimDeltaPerMs);
9729 pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
9730 }
9731 }
9732
9733 /**
9734 * Animation that fade in after 0.5 interpolate time, or fade out in reverse order.
9735 * This is used for opening/closing transition for apps in compatible mode.
9736 */
9737 private static class FadeInOutAnimation extends Animation {
9738 int mWidth;
9739 boolean mFadeIn;
9740
9741 public FadeInOutAnimation(boolean fadeIn) {
9742 setInterpolator(new AccelerateInterpolator());
9743 setDuration(DEFAULT_FADE_IN_OUT_DURATION);
9744 mFadeIn = fadeIn;
9745 }
9746
9747 @Override
9748 protected void applyTransformation(float interpolatedTime, Transformation t) {
9749 float x = interpolatedTime;
9750 if (!mFadeIn) {
9751 x = 1.0f - x; // reverse the interpolation for fade out
9752 }
9753 if (x < 0.5) {
9754 // move the window out of the screen.
9755 t.getMatrix().setTranslate(mWidth, 0);
9756 } else {
9757 t.getMatrix().setTranslate(0, 0);// show
9758 t.setAlpha((x - 0.5f) * 2);
9759 }
9760 }
9761
9762 @Override
9763 public void initialize(int width, int height, int parentWidth, int parentHeight) {
9764 // width is the screen width {@see AppWindowToken#stepAnimatinoLocked}
9765 mWidth = width;
9766 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009767
9768 @Override
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07009769 public int getZAdjustment() {
9770 return Animation.ZORDER_TOP;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009771 }
9772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009773}