blob: ceb9c418fbe1573fe8df9235bbe42a43f50c49d2 [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;
34import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
35import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
36import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
37import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
38import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
39import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
40import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
41import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
42import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
43
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;
142 static final boolean SHOW_TRANSACTIONS = false;
Michael Chan53071d62009-05-13 17:29:48 -0700143 static final boolean MEASURE_LATENCY = false;
144 static private LatencyTimer lt;
145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 static final boolean PROFILE_ORIENTATION = false;
147 static final boolean BLUR = true;
Dave Bortcfe65242009-04-09 14:51:04 -0700148 static final boolean localLOGV = DEBUG;
Romain Guy06882f82009-06-10 13:36:04 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
Romain Guy06882f82009-06-10 13:36:04 -0700151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 /** How long to wait for first key repeat, in milliseconds */
153 static final int KEY_REPEAT_FIRST_DELAY = 750;
Romain Guy06882f82009-06-10 13:36:04 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 /** How long to wait for subsequent key repeats, in milliseconds */
156 static final int KEY_REPEAT_DELAY = 50;
157
158 /** How much to multiply the policy's type layer, to reserve room
159 * for multiple windows of the same type and Z-ordering adjustment
160 * with TYPE_LAYER_OFFSET. */
161 static final int TYPE_LAYER_MULTIPLIER = 10000;
Romain Guy06882f82009-06-10 13:36:04 -0700162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
164 * or below others in the same layer. */
165 static final int TYPE_LAYER_OFFSET = 1000;
Romain Guy06882f82009-06-10 13:36:04 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 /** How much to increment the layer for each window, to reserve room
168 * for effect surfaces between them.
169 */
170 static final int WINDOW_LAYER_MULTIPLIER = 5;
Romain Guy06882f82009-06-10 13:36:04 -0700171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /** The maximum length we will accept for a loaded animation duration:
173 * this is 10 seconds.
174 */
175 static final int MAX_ANIMATION_DURATION = 10*1000;
176
177 /** Amount of time (in milliseconds) to animate the dim surface from one
178 * value to another, when no window animation is driving it.
179 */
180 static final int DEFAULT_DIM_DURATION = 200;
181
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700182 /** Amount of time (in milliseconds) to animate the fade-in-out transition for
183 * compatible windows.
184 */
185 static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 /** Adjustment to time to perform a dim, to make it more dramatic.
188 */
189 static final int DIM_DURATION_MULTIPLIER = 6;
Romain Guy06882f82009-06-10 13:36:04 -0700190
Dianne Hackborncfaef692009-06-15 14:24:44 -0700191 static final int INJECT_FAILED = 0;
192 static final int INJECT_SUCCEEDED = 1;
193 static final int INJECT_NO_PERMISSION = -1;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 static final int UPDATE_FOCUS_NORMAL = 0;
196 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
197 static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
198 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
Romain Guy06882f82009-06-10 13:36:04 -0700199
Michael Chane96440f2009-05-06 10:27:36 -0700200 /** The minimum time between dispatching touch events. */
201 int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
202
203 // Last touch event time
204 long mLastTouchEventTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700205
Michael Chane96440f2009-05-06 10:27:36 -0700206 // Last touch event type
207 int mLastTouchEventType = OTHER_EVENT;
Romain Guy06882f82009-06-10 13:36:04 -0700208
Michael Chane96440f2009-05-06 10:27:36 -0700209 // Time to wait before calling useractivity again. This saves CPU usage
210 // when we get a flood of touch events.
211 static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
212
213 // Last time we call user activity
214 long mLastUserActivityCallTime = 0;
215
Romain Guy06882f82009-06-10 13:36:04 -0700216 // Last time we updated battery stats
Michael Chane96440f2009-05-06 10:27:36 -0700217 long mLastBatteryStatsCallTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 private static final String SYSTEM_SECURE = "ro.secure";
Romain Guy06882f82009-06-10 13:36:04 -0700220 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221
222 /**
223 * Condition waited on by {@link #reenableKeyguard} to know the call to
224 * the window policy has finished.
225 */
226 private boolean mWaitingUntilKeyguardReenabled = false;
227
228
229 final TokenWatcher mKeyguardDisabled = new TokenWatcher(
230 new Handler(), "WindowManagerService.mKeyguardDisabled") {
231 public void acquired() {
232 mPolicy.enableKeyguard(false);
233 }
234 public void released() {
235 synchronized (mKeyguardDisabled) {
236 mPolicy.enableKeyguard(true);
237 mWaitingUntilKeyguardReenabled = false;
238 mKeyguardDisabled.notifyAll();
239 }
240 }
241 };
242
243 final Context mContext;
244
245 final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 final boolean mLimitedAlphaCompositing;
Romain Guy06882f82009-06-10 13:36:04 -0700248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
250
251 final IActivityManager mActivityManager;
Romain Guy06882f82009-06-10 13:36:04 -0700252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 final IBatteryStats mBatteryStats;
Romain Guy06882f82009-06-10 13:36:04 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 /**
256 * All currently active sessions with clients.
257 */
258 final HashSet<Session> mSessions = new HashSet<Session>();
Romain Guy06882f82009-06-10 13:36:04 -0700259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 /**
261 * Mapping from an IWindow IBinder to the server's Window object.
262 * This is also used as the lock for all of our state.
263 */
264 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
265
266 /**
267 * Mapping from a token IBinder to a WindowToken object.
268 */
269 final HashMap<IBinder, WindowToken> mTokenMap =
270 new HashMap<IBinder, WindowToken>();
271
272 /**
273 * The same tokens as mTokenMap, stored in a list for efficient iteration
274 * over them.
275 */
276 final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 /**
279 * Window tokens that are in the process of exiting, but still
280 * on screen for animations.
281 */
282 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
283
284 /**
285 * Z-ordered (bottom-most first) list of all application tokens, for
286 * controlling the ordering of windows in different applications. This
287 * contains WindowToken objects.
288 */
289 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
290
291 /**
292 * Application tokens that are in the process of exiting, but still
293 * on screen for animations.
294 */
295 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
296
297 /**
298 * List of window tokens that have finished starting their application,
299 * and now need to have the policy remove their windows.
300 */
301 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
302
303 /**
304 * Z-ordered (bottom-most first) list of all Window objects.
305 */
306 final ArrayList mWindows = new ArrayList();
307
308 /**
309 * Windows that are being resized. Used so we can tell the client about
310 * the resize after closing the transaction in which we resized the
311 * underlying surface.
312 */
313 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
314
315 /**
316 * Windows whose animations have ended and now must be removed.
317 */
318 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
319
320 /**
321 * Windows whose surface should be destroyed.
322 */
323 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
324
325 /**
326 * Windows that have lost input focus and are waiting for the new
327 * focus window to be displayed before they are told about this.
328 */
329 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
330
331 /**
332 * This is set when we have run out of memory, and will either be an empty
333 * list or contain windows that need to be force removed.
334 */
335 ArrayList<WindowState> mForceRemoves;
Romain Guy06882f82009-06-10 13:36:04 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 IInputMethodManager mInputMethodManager;
Romain Guy06882f82009-06-10 13:36:04 -0700338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 SurfaceSession mFxSession;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -0700340 private DimAnimator mDimAnimator = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 Surface mBlurSurface;
342 boolean mBlurShown;
Romain Guy06882f82009-06-10 13:36:04 -0700343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 int mTransactionSequence = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 final float[] mTmpFloats = new float[9];
347
348 boolean mSafeMode;
349 boolean mDisplayEnabled = false;
350 boolean mSystemBooted = false;
351 int mRotation = 0;
352 int mRequestedRotation = 0;
353 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Dianne Hackborn321ae682009-03-27 16:16:03 -0700354 int mLastRotationFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 ArrayList<IRotationWatcher> mRotationWatchers
356 = new ArrayList<IRotationWatcher>();
Romain Guy06882f82009-06-10 13:36:04 -0700357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 boolean mLayoutNeeded = true;
359 boolean mAnimationPending = false;
360 boolean mDisplayFrozen = false;
361 boolean mWindowsFreezingScreen = false;
362 long mFreezeGcPending = 0;
363 int mAppsFreezingScreen = 0;
364
365 // This is held as long as we have the screen frozen, to give us time to
366 // perform a rotation animation when turning off shows the lock screen which
367 // changes the orientation.
368 PowerManager.WakeLock mScreenFrozenLock;
Romain Guy06882f82009-06-10 13:36:04 -0700369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 // State management of app transitions. When we are preparing for a
371 // transition, mNextAppTransition will be the kind of transition to
372 // perform or TRANSIT_NONE if we are not waiting. If we are waiting,
373 // mOpeningApps and mClosingApps are the lists of tokens that will be
374 // made visible or hidden at the next transition.
375 int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
376 boolean mAppTransitionReady = false;
377 boolean mAppTransitionTimeout = false;
378 boolean mStartingIconInTransition = false;
379 boolean mSkipAppTransitionAnimation = false;
380 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
381 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 //flag to detect fat touch events
384 boolean mFatTouch = false;
385 Display mDisplay;
Romain Guy06882f82009-06-10 13:36:04 -0700386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 H mH = new H();
388
389 WindowState mCurrentFocus = null;
390 WindowState mLastFocus = null;
Romain Guy06882f82009-06-10 13:36:04 -0700391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 // This just indicates the window the input method is on top of, not
393 // necessarily the window its input is going to.
394 WindowState mInputMethodTarget = null;
395 WindowState mUpcomingInputMethodTarget = null;
396 boolean mInputMethodTargetWaitingAnim;
397 int mInputMethodAnimLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -0700398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 WindowState mInputMethodWindow = null;
400 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
401
402 AppWindowToken mFocusedApp = null;
403
404 PowerManagerService mPowerManager;
Romain Guy06882f82009-06-10 13:36:04 -0700405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 float mWindowAnimationScale = 1.0f;
407 float mTransitionAnimationScale = 1.0f;
Romain Guy06882f82009-06-10 13:36:04 -0700408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 final KeyWaiter mKeyWaiter = new KeyWaiter();
410 final KeyQ mQueue;
411 final InputDispatcherThread mInputThread;
412
413 // Who is holding the screen on.
414 Session mHoldingScreenOn;
Romain Guy06882f82009-06-10 13:36:04 -0700415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 /**
417 * Whether the UI is currently running in touch mode (not showing
418 * navigational focus because the user is directly pressing the screen).
419 */
420 boolean mInTouchMode = false;
421
422 private ViewServer mViewServer;
423
424 final Rect mTempRect = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -0700425
Dianne Hackbornc485a602009-03-24 22:39:49 -0700426 final Configuration mTempConfiguration = new Configuration();
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700427 int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700428
429 // The frame use to limit the size of the app running in compatibility mode.
430 Rect mCompatibleScreenFrame = new Rect();
431 // The surface used to fill the outer rim of the app running in compatibility mode.
432 Surface mBackgroundFillerSurface = null;
433 boolean mBackgroundFillerShown = false;
434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 public static WindowManagerService main(Context context,
436 PowerManagerService pm, boolean haveInputMethods) {
437 WMThread thr = new WMThread(context, pm, haveInputMethods);
438 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 synchronized (thr) {
441 while (thr.mService == null) {
442 try {
443 thr.wait();
444 } catch (InterruptedException e) {
445 }
446 }
447 }
Romain Guy06882f82009-06-10 13:36:04 -0700448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 return thr.mService;
450 }
Romain Guy06882f82009-06-10 13:36:04 -0700451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 static class WMThread extends Thread {
453 WindowManagerService mService;
Romain Guy06882f82009-06-10 13:36:04 -0700454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 private final Context mContext;
456 private final PowerManagerService mPM;
457 private final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 public WMThread(Context context, PowerManagerService pm,
460 boolean haveInputMethods) {
461 super("WindowManager");
462 mContext = context;
463 mPM = pm;
464 mHaveInputMethods = haveInputMethods;
465 }
Romain Guy06882f82009-06-10 13:36:04 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 public void run() {
468 Looper.prepare();
469 WindowManagerService s = new WindowManagerService(mContext, mPM,
470 mHaveInputMethods);
471 android.os.Process.setThreadPriority(
472 android.os.Process.THREAD_PRIORITY_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -0700473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 synchronized (this) {
475 mService = s;
476 notifyAll();
477 }
Romain Guy06882f82009-06-10 13:36:04 -0700478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 Looper.loop();
480 }
481 }
482
483 static class PolicyThread extends Thread {
484 private final WindowManagerPolicy mPolicy;
485 private final WindowManagerService mService;
486 private final Context mContext;
487 private final PowerManagerService mPM;
488 boolean mRunning = false;
Romain Guy06882f82009-06-10 13:36:04 -0700489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 public PolicyThread(WindowManagerPolicy policy,
491 WindowManagerService service, Context context,
492 PowerManagerService pm) {
493 super("WindowManagerPolicy");
494 mPolicy = policy;
495 mService = service;
496 mContext = context;
497 mPM = pm;
498 }
Romain Guy06882f82009-06-10 13:36:04 -0700499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 public void run() {
501 Looper.prepare();
502 //Looper.myLooper().setMessageLogging(new LogPrinter(
503 // Log.VERBOSE, "WindowManagerPolicy"));
504 android.os.Process.setThreadPriority(
505 android.os.Process.THREAD_PRIORITY_FOREGROUND);
506 mPolicy.init(mContext, mService, mPM);
Romain Guy06882f82009-06-10 13:36:04 -0700507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 synchronized (this) {
509 mRunning = true;
510 notifyAll();
511 }
Romain Guy06882f82009-06-10 13:36:04 -0700512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 Looper.loop();
514 }
515 }
516
517 private WindowManagerService(Context context, PowerManagerService pm,
518 boolean haveInputMethods) {
Michael Chan53071d62009-05-13 17:29:48 -0700519 if (MEASURE_LATENCY) {
520 lt = new LatencyTimer(100, 1000);
521 }
522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 mContext = context;
524 mHaveInputMethods = haveInputMethods;
525 mLimitedAlphaCompositing = context.getResources().getBoolean(
526 com.android.internal.R.bool.config_sf_limitedAlpha);
Romain Guy06882f82009-06-10 13:36:04 -0700527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 mPowerManager = pm;
529 mPowerManager.setPolicy(mPolicy);
530 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
531 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
532 "SCREEN_FROZEN");
533 mScreenFrozenLock.setReferenceCounted(false);
534
535 mActivityManager = ActivityManagerNative.getDefault();
536 mBatteryStats = BatteryStatsService.getService();
537
538 // Get persisted window scale setting
539 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
540 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
541 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
542 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
Romain Guy06882f82009-06-10 13:36:04 -0700543
Michael Chan9f028e62009-08-04 17:37:46 -0700544 int max_events_per_sec = 35;
545 try {
546 max_events_per_sec = Integer.parseInt(SystemProperties
547 .get("windowsmgr.max_events_per_sec"));
548 if (max_events_per_sec < 1) {
549 max_events_per_sec = 35;
550 }
551 } catch (NumberFormatException e) {
552 }
553 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 mQueue = new KeyQ();
556
557 mInputThread = new InputDispatcherThread();
Romain Guy06882f82009-06-10 13:36:04 -0700558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
560 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 synchronized (thr) {
563 while (!thr.mRunning) {
564 try {
565 thr.wait();
566 } catch (InterruptedException e) {
567 }
568 }
569 }
Romain Guy06882f82009-06-10 13:36:04 -0700570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 mInputThread.start();
Romain Guy06882f82009-06-10 13:36:04 -0700572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 // Add ourself to the Watchdog monitors.
574 Watchdog.getInstance().addMonitor(this);
575 }
576
577 @Override
578 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
579 throws RemoteException {
580 try {
581 return super.onTransact(code, data, reply, flags);
582 } catch (RuntimeException e) {
583 // The window manager only throws security exceptions, so let's
584 // log all others.
585 if (!(e instanceof SecurityException)) {
586 Log.e(TAG, "Window Manager Crash", e);
587 }
588 throw e;
589 }
590 }
591
592 private void placeWindowAfter(Object pos, WindowState window) {
593 final int i = mWindows.indexOf(pos);
594 if (localLOGV || DEBUG_FOCUS) Log.v(
595 TAG, "Adding window " + window + " at "
596 + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
597 mWindows.add(i+1, window);
598 }
599
600 private void placeWindowBefore(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 + " of " + mWindows.size() + " (before " + pos + ")");
605 mWindows.add(i, window);
606 }
607
608 //This method finds out the index of a window that has the same app token as
609 //win. used for z ordering the windows in mWindows
610 private int findIdxBasedOnAppTokens(WindowState win) {
611 //use a local variable to cache mWindows
612 ArrayList localmWindows = mWindows;
613 int jmax = localmWindows.size();
614 if(jmax == 0) {
615 return -1;
616 }
617 for(int j = (jmax-1); j >= 0; j--) {
618 WindowState wentry = (WindowState)localmWindows.get(j);
619 if(wentry.mAppToken == win.mAppToken) {
620 return j;
621 }
622 }
623 return -1;
624 }
Romain Guy06882f82009-06-10 13:36:04 -0700625
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
627 final IWindow client = win.mClient;
628 final WindowToken token = win.mToken;
629 final ArrayList localmWindows = mWindows;
Romain Guy06882f82009-06-10 13:36:04 -0700630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 final int N = localmWindows.size();
632 final WindowState attached = win.mAttachedWindow;
633 int i;
634 if (attached == null) {
635 int tokenWindowsPos = token.windows.size();
636 if (token.appWindowToken != null) {
637 int index = tokenWindowsPos-1;
638 if (index >= 0) {
639 // If this application has existing windows, we
640 // simply place the new window on top of them... but
641 // keep the starting window on top.
642 if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
643 // Base windows go behind everything else.
644 placeWindowBefore(token.windows.get(0), win);
645 tokenWindowsPos = 0;
646 } else {
647 AppWindowToken atoken = win.mAppToken;
648 if (atoken != null &&
649 token.windows.get(index) == atoken.startingWindow) {
650 placeWindowBefore(token.windows.get(index), win);
651 tokenWindowsPos--;
652 } else {
653 int newIdx = findIdxBasedOnAppTokens(win);
654 if(newIdx != -1) {
Romain Guy06882f82009-06-10 13:36:04 -0700655 //there is a window above this one associated with the same
656 //apptoken note that the window could be a floating window
657 //that was created later or a window at the top of the list of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 //windows associated with this token.
659 localmWindows.add(newIdx+1, win);
Romain Guy06882f82009-06-10 13:36:04 -0700660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 }
662 }
663 } else {
664 if (localLOGV) Log.v(
665 TAG, "Figuring out where to add app window "
666 + client.asBinder() + " (token=" + token + ")");
667 // Figure out where the window should go, based on the
668 // order of applications.
669 final int NA = mAppTokens.size();
670 Object pos = null;
671 for (i=NA-1; i>=0; i--) {
672 AppWindowToken t = mAppTokens.get(i);
673 if (t == token) {
674 i--;
675 break;
676 }
677 if (t.windows.size() > 0) {
678 pos = t.windows.get(0);
679 }
680 }
681 // We now know the index into the apps. If we found
682 // an app window above, that gives us the position; else
683 // we need to look some more.
684 if (pos != null) {
685 // Move behind any windows attached to this one.
Romain Guy06882f82009-06-10 13:36:04 -0700686 WindowToken atoken =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 mTokenMap.get(((WindowState)pos).mClient.asBinder());
688 if (atoken != null) {
689 final int NC = atoken.windows.size();
690 if (NC > 0) {
691 WindowState bottom = atoken.windows.get(0);
692 if (bottom.mSubLayer < 0) {
693 pos = bottom;
694 }
695 }
696 }
697 placeWindowBefore(pos, win);
698 } else {
699 while (i >= 0) {
700 AppWindowToken t = mAppTokens.get(i);
701 final int NW = t.windows.size();
702 if (NW > 0) {
703 pos = t.windows.get(NW-1);
704 break;
705 }
706 i--;
707 }
708 if (pos != null) {
709 // Move in front of any windows attached to this
710 // one.
711 WindowToken atoken =
712 mTokenMap.get(((WindowState)pos).mClient.asBinder());
713 if (atoken != null) {
714 final int NC = atoken.windows.size();
715 if (NC > 0) {
716 WindowState top = atoken.windows.get(NC-1);
717 if (top.mSubLayer >= 0) {
718 pos = top;
719 }
720 }
721 }
722 placeWindowAfter(pos, win);
723 } else {
724 // Just search for the start of this layer.
725 final int myLayer = win.mBaseLayer;
726 for (i=0; i<N; i++) {
727 WindowState w = (WindowState)localmWindows.get(i);
728 if (w.mBaseLayer > myLayer) {
729 break;
730 }
731 }
732 if (localLOGV || DEBUG_FOCUS) Log.v(
733 TAG, "Adding window " + win + " at "
734 + i + " of " + N);
735 localmWindows.add(i, win);
736 }
737 }
738 }
739 } else {
740 // Figure out where window should go, based on layer.
741 final int myLayer = win.mBaseLayer;
742 for (i=N-1; i>=0; i--) {
743 if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
744 i++;
745 break;
746 }
747 }
748 if (i < 0) i = 0;
749 if (localLOGV || DEBUG_FOCUS) Log.v(
750 TAG, "Adding window " + win + " at "
751 + i + " of " + N);
752 localmWindows.add(i, win);
753 }
754 if (addToToken) {
755 token.windows.add(tokenWindowsPos, win);
756 }
757
758 } else {
759 // Figure out this window's ordering relative to the window
760 // it is attached to.
761 final int NA = token.windows.size();
762 final int sublayer = win.mSubLayer;
763 int largestSublayer = Integer.MIN_VALUE;
764 WindowState windowWithLargestSublayer = null;
765 for (i=0; i<NA; i++) {
766 WindowState w = token.windows.get(i);
767 final int wSublayer = w.mSubLayer;
768 if (wSublayer >= largestSublayer) {
769 largestSublayer = wSublayer;
770 windowWithLargestSublayer = w;
771 }
772 if (sublayer < 0) {
773 // For negative sublayers, we go below all windows
774 // in the same sublayer.
775 if (wSublayer >= sublayer) {
776 if (addToToken) {
777 token.windows.add(i, win);
778 }
779 placeWindowBefore(
780 wSublayer >= 0 ? attached : w, win);
781 break;
782 }
783 } else {
784 // For positive sublayers, we go above all windows
785 // in the same sublayer.
786 if (wSublayer > sublayer) {
787 if (addToToken) {
788 token.windows.add(i, win);
789 }
790 placeWindowBefore(w, win);
791 break;
792 }
793 }
794 }
795 if (i >= NA) {
796 if (addToToken) {
797 token.windows.add(win);
798 }
799 if (sublayer < 0) {
800 placeWindowBefore(attached, win);
801 } else {
802 placeWindowAfter(largestSublayer >= 0
803 ? windowWithLargestSublayer
804 : attached,
805 win);
806 }
807 }
808 }
Romain Guy06882f82009-06-10 13:36:04 -0700809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 if (win.mAppToken != null && addToToken) {
811 win.mAppToken.allAppWindows.add(win);
812 }
813 }
Romain Guy06882f82009-06-10 13:36:04 -0700814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 static boolean canBeImeTarget(WindowState w) {
816 final int fl = w.mAttrs.flags
817 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
818 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
819 return w.isVisibleOrAdding();
820 }
821 return false;
822 }
Romain Guy06882f82009-06-10 13:36:04 -0700823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
825 final ArrayList localmWindows = mWindows;
826 final int N = localmWindows.size();
827 WindowState w = null;
828 int i = N;
829 while (i > 0) {
830 i--;
831 w = (WindowState)localmWindows.get(i);
Romain Guy06882f82009-06-10 13:36:04 -0700832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
834 // + Integer.toHexString(w.mAttrs.flags));
835 if (canBeImeTarget(w)) {
836 //Log.i(TAG, "Putting input method here!");
Romain Guy06882f82009-06-10 13:36:04 -0700837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 // Yet more tricksyness! If this window is a "starting"
839 // window, we do actually want to be on top of it, but
840 // it is not -really- where input will go. So if the caller
841 // is not actually looking to move the IME, look down below
842 // for a real window to target...
843 if (!willMove
844 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
845 && i > 0) {
846 WindowState wb = (WindowState)localmWindows.get(i-1);
847 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
848 i--;
849 w = wb;
850 }
851 }
852 break;
853 }
854 }
Romain Guy06882f82009-06-10 13:36:04 -0700855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 mUpcomingInputMethodTarget = w;
Romain Guy06882f82009-06-10 13:36:04 -0700857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
859 + w + " willMove=" + willMove);
Romain Guy06882f82009-06-10 13:36:04 -0700860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 if (willMove && w != null) {
862 final WindowState curTarget = mInputMethodTarget;
863 if (curTarget != null && curTarget.mAppToken != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 // Now some fun for dealing with window animations that
866 // modify the Z order. We need to look at all windows below
867 // the current target that are in this app, finding the highest
868 // visible one in layering.
869 AppWindowToken token = curTarget.mAppToken;
870 WindowState highestTarget = null;
871 int highestPos = 0;
872 if (token.animating || token.animation != null) {
873 int pos = 0;
874 pos = localmWindows.indexOf(curTarget);
875 while (pos >= 0) {
876 WindowState win = (WindowState)localmWindows.get(pos);
877 if (win.mAppToken != token) {
878 break;
879 }
880 if (!win.mRemoved) {
881 if (highestTarget == null || win.mAnimLayer >
882 highestTarget.mAnimLayer) {
883 highestTarget = win;
884 highestPos = pos;
885 }
886 }
887 pos--;
888 }
889 }
Romain Guy06882f82009-06-10 13:36:04 -0700890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 if (highestTarget != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700892 if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 + mNextAppTransition + " " + highestTarget
894 + " animating=" + highestTarget.isAnimating()
895 + " layer=" + highestTarget.mAnimLayer
896 + " new layer=" + w.mAnimLayer);
Romain Guy06882f82009-06-10 13:36:04 -0700897
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
899 // If we are currently setting up for an animation,
900 // hold everything until we can find out what will happen.
901 mInputMethodTargetWaitingAnim = true;
902 mInputMethodTarget = highestTarget;
903 return highestPos + 1;
904 } else if (highestTarget.isAnimating() &&
905 highestTarget.mAnimLayer > w.mAnimLayer) {
906 // If the window we are currently targeting is involved
907 // with an animation, and it is on top of the next target
908 // we will be over, then hold off on moving until
909 // that is done.
910 mInputMethodTarget = highestTarget;
911 return highestPos + 1;
912 }
913 }
914 }
915 }
Romain Guy06882f82009-06-10 13:36:04 -0700916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 //Log.i(TAG, "Placing input method @" + (i+1));
918 if (w != null) {
919 if (willMove) {
920 RuntimeException e = new RuntimeException();
921 e.fillInStackTrace();
922 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
923 + mInputMethodTarget + " to " + w, e);
924 mInputMethodTarget = w;
925 if (w.mAppToken != null) {
926 setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
927 } else {
928 setInputMethodAnimLayerAdjustment(0);
929 }
930 }
931 return i+1;
932 }
933 if (willMove) {
934 RuntimeException e = new RuntimeException();
935 e.fillInStackTrace();
936 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
937 + mInputMethodTarget + " to null", e);
938 mInputMethodTarget = null;
939 setInputMethodAnimLayerAdjustment(0);
940 }
941 return -1;
942 }
Romain Guy06882f82009-06-10 13:36:04 -0700943
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 void addInputMethodWindowToListLocked(WindowState win) {
945 int pos = findDesiredInputMethodWindowIndexLocked(true);
946 if (pos >= 0) {
947 win.mTargetAppToken = mInputMethodTarget.mAppToken;
948 mWindows.add(pos, win);
949 moveInputMethodDialogsLocked(pos+1);
950 return;
951 }
952 win.mTargetAppToken = null;
953 addWindowToListInOrderLocked(win, true);
954 moveInputMethodDialogsLocked(pos);
955 }
Romain Guy06882f82009-06-10 13:36:04 -0700956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 void setInputMethodAnimLayerAdjustment(int adj) {
958 if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
959 mInputMethodAnimLayerAdjustment = adj;
960 WindowState imw = mInputMethodWindow;
961 if (imw != null) {
962 imw.mAnimLayer = imw.mLayer + adj;
963 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
964 + " anim layer: " + imw.mAnimLayer);
965 int wi = imw.mChildWindows.size();
966 while (wi > 0) {
967 wi--;
968 WindowState cw = (WindowState)imw.mChildWindows.get(wi);
969 cw.mAnimLayer = cw.mLayer + adj;
970 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
971 + " anim layer: " + cw.mAnimLayer);
972 }
973 }
974 int di = mInputMethodDialogs.size();
975 while (di > 0) {
976 di --;
977 imw = mInputMethodDialogs.get(di);
978 imw.mAnimLayer = imw.mLayer + adj;
979 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
980 + " anim layer: " + imw.mAnimLayer);
981 }
982 }
Romain Guy06882f82009-06-10 13:36:04 -0700983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
985 int wpos = mWindows.indexOf(win);
986 if (wpos >= 0) {
987 if (wpos < interestingPos) interestingPos--;
988 mWindows.remove(wpos);
989 int NC = win.mChildWindows.size();
990 while (NC > 0) {
991 NC--;
992 WindowState cw = (WindowState)win.mChildWindows.get(NC);
993 int cpos = mWindows.indexOf(cw);
994 if (cpos >= 0) {
995 if (cpos < interestingPos) interestingPos--;
996 mWindows.remove(cpos);
997 }
998 }
999 }
1000 return interestingPos;
1001 }
Romain Guy06882f82009-06-10 13:36:04 -07001002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 private void reAddWindowToListInOrderLocked(WindowState win) {
1004 addWindowToListInOrderLocked(win, false);
1005 // This is a hack to get all of the child windows added as well
1006 // at the right position. Child windows should be rare and
1007 // this case should be rare, so it shouldn't be that big a deal.
1008 int wpos = mWindows.indexOf(win);
1009 if (wpos >= 0) {
1010 mWindows.remove(wpos);
1011 reAddWindowLocked(wpos, win);
1012 }
1013 }
Romain Guy06882f82009-06-10 13:36:04 -07001014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 void logWindowList(String prefix) {
1016 int N = mWindows.size();
1017 while (N > 0) {
1018 N--;
1019 Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
1020 }
1021 }
Romain Guy06882f82009-06-10 13:36:04 -07001022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 void moveInputMethodDialogsLocked(int pos) {
1024 ArrayList<WindowState> dialogs = mInputMethodDialogs;
Romain Guy06882f82009-06-10 13:36:04 -07001025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 final int N = dialogs.size();
1027 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
1028 for (int i=0; i<N; i++) {
1029 pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
1030 }
1031 if (DEBUG_INPUT_METHOD) {
1032 Log.v(TAG, "Window list w/pos=" + pos);
1033 logWindowList(" ");
1034 }
Romain Guy06882f82009-06-10 13:36:04 -07001035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 if (pos >= 0) {
1037 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
1038 if (pos < mWindows.size()) {
1039 WindowState wp = (WindowState)mWindows.get(pos);
1040 if (wp == mInputMethodWindow) {
1041 pos++;
1042 }
1043 }
1044 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
1045 for (int i=0; i<N; i++) {
1046 WindowState win = dialogs.get(i);
1047 win.mTargetAppToken = targetAppToken;
1048 pos = reAddWindowLocked(pos, win);
1049 }
1050 if (DEBUG_INPUT_METHOD) {
1051 Log.v(TAG, "Final window list:");
1052 logWindowList(" ");
1053 }
1054 return;
1055 }
1056 for (int i=0; i<N; i++) {
1057 WindowState win = dialogs.get(i);
1058 win.mTargetAppToken = null;
1059 reAddWindowToListInOrderLocked(win);
1060 if (DEBUG_INPUT_METHOD) {
1061 Log.v(TAG, "No IM target, final list:");
1062 logWindowList(" ");
1063 }
1064 }
1065 }
Romain Guy06882f82009-06-10 13:36:04 -07001066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
1068 final WindowState imWin = mInputMethodWindow;
1069 final int DN = mInputMethodDialogs.size();
1070 if (imWin == null && DN == 0) {
1071 return false;
1072 }
Romain Guy06882f82009-06-10 13:36:04 -07001073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 int imPos = findDesiredInputMethodWindowIndexLocked(true);
1075 if (imPos >= 0) {
1076 // In this case, the input method windows are to be placed
1077 // immediately above the window they are targeting.
Romain Guy06882f82009-06-10 13:36:04 -07001078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 // First check to see if the input method windows are already
1080 // located here, and contiguous.
1081 final int N = mWindows.size();
1082 WindowState firstImWin = imPos < N
1083 ? (WindowState)mWindows.get(imPos) : null;
Romain Guy06882f82009-06-10 13:36:04 -07001084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 // Figure out the actual input method window that should be
1086 // at the bottom of their stack.
1087 WindowState baseImWin = imWin != null
1088 ? imWin : mInputMethodDialogs.get(0);
1089 if (baseImWin.mChildWindows.size() > 0) {
1090 WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
1091 if (cw.mSubLayer < 0) baseImWin = cw;
1092 }
Romain Guy06882f82009-06-10 13:36:04 -07001093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 if (firstImWin == baseImWin) {
1095 // The windows haven't moved... but are they still contiguous?
1096 // First find the top IM window.
1097 int pos = imPos+1;
1098 while (pos < N) {
1099 if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
1100 break;
1101 }
1102 pos++;
1103 }
1104 pos++;
1105 // Now there should be no more input method windows above.
1106 while (pos < N) {
1107 if (((WindowState)mWindows.get(pos)).mIsImWindow) {
1108 break;
1109 }
1110 pos++;
1111 }
1112 if (pos >= N) {
1113 // All is good!
1114 return false;
1115 }
1116 }
Romain Guy06882f82009-06-10 13:36:04 -07001117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 if (imWin != null) {
1119 if (DEBUG_INPUT_METHOD) {
1120 Log.v(TAG, "Moving IM from " + imPos);
1121 logWindowList(" ");
1122 }
1123 imPos = tmpRemoveWindowLocked(imPos, imWin);
1124 if (DEBUG_INPUT_METHOD) {
1125 Log.v(TAG, "List after moving with new pos " + imPos + ":");
1126 logWindowList(" ");
1127 }
1128 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
1129 reAddWindowLocked(imPos, imWin);
1130 if (DEBUG_INPUT_METHOD) {
1131 Log.v(TAG, "List after moving IM to " + imPos + ":");
1132 logWindowList(" ");
1133 }
1134 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
1135 } else {
1136 moveInputMethodDialogsLocked(imPos);
1137 }
Romain Guy06882f82009-06-10 13:36:04 -07001138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 } else {
1140 // In this case, the input method windows go in a fixed layer,
1141 // because they aren't currently associated with a focus window.
Romain Guy06882f82009-06-10 13:36:04 -07001142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 if (imWin != null) {
1144 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
1145 tmpRemoveWindowLocked(0, imWin);
1146 imWin.mTargetAppToken = null;
1147 reAddWindowToListInOrderLocked(imWin);
1148 if (DEBUG_INPUT_METHOD) {
1149 Log.v(TAG, "List with no IM target:");
1150 logWindowList(" ");
1151 }
1152 if (DN > 0) moveInputMethodDialogsLocked(-1);;
1153 } else {
1154 moveInputMethodDialogsLocked(-1);;
1155 }
Romain Guy06882f82009-06-10 13:36:04 -07001156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 }
Romain Guy06882f82009-06-10 13:36:04 -07001158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 if (needAssignLayers) {
1160 assignLayersLocked();
1161 }
Romain Guy06882f82009-06-10 13:36:04 -07001162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 return true;
1164 }
Romain Guy06882f82009-06-10 13:36:04 -07001165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 void adjustInputMethodDialogsLocked() {
1167 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
1168 }
Romain Guy06882f82009-06-10 13:36:04 -07001169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 public int addWindow(Session session, IWindow client,
1171 WindowManager.LayoutParams attrs, int viewVisibility,
1172 Rect outContentInsets) {
1173 int res = mPolicy.checkAddPermission(attrs);
1174 if (res != WindowManagerImpl.ADD_OKAY) {
1175 return res;
1176 }
Romain Guy06882f82009-06-10 13:36:04 -07001177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 boolean reportNewConfig = false;
1179 WindowState attachedWindow = null;
1180 WindowState win = null;
Romain Guy06882f82009-06-10 13:36:04 -07001181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 synchronized(mWindowMap) {
1183 // Instantiating a Display requires talking with the simulator,
1184 // so don't do it until we know the system is mostly up and
1185 // running.
1186 if (mDisplay == null) {
1187 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1188 mDisplay = wm.getDefaultDisplay();
1189 mQueue.setDisplay(mDisplay);
1190 reportNewConfig = true;
1191 }
Romain Guy06882f82009-06-10 13:36:04 -07001192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 if (mWindowMap.containsKey(client.asBinder())) {
1194 Log.w(TAG, "Window " + client + " is already added");
1195 return WindowManagerImpl.ADD_DUPLICATE_ADD;
1196 }
1197
1198 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
Romain Guy06882f82009-06-10 13:36:04 -07001199 attachedWindow = windowForClientLocked(null, attrs.token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 if (attachedWindow == null) {
1201 Log.w(TAG, "Attempted to add window with token that is not a window: "
1202 + attrs.token + ". Aborting.");
1203 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1204 }
1205 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
1206 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1207 Log.w(TAG, "Attempted to add window with token that is a sub-window: "
1208 + attrs.token + ". Aborting.");
1209 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1210 }
1211 }
1212
1213 boolean addToken = false;
1214 WindowToken token = mTokenMap.get(attrs.token);
1215 if (token == null) {
1216 if (attrs.type >= FIRST_APPLICATION_WINDOW
1217 && attrs.type <= LAST_APPLICATION_WINDOW) {
1218 Log.w(TAG, "Attempted to add application window with unknown token "
1219 + attrs.token + ". Aborting.");
1220 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1221 }
1222 if (attrs.type == TYPE_INPUT_METHOD) {
1223 Log.w(TAG, "Attempted to add input method window with unknown token "
1224 + attrs.token + ". Aborting.");
1225 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1226 }
1227 token = new WindowToken(attrs.token, -1, false);
1228 addToken = true;
1229 } else if (attrs.type >= FIRST_APPLICATION_WINDOW
1230 && attrs.type <= LAST_APPLICATION_WINDOW) {
1231 AppWindowToken atoken = token.appWindowToken;
1232 if (atoken == null) {
1233 Log.w(TAG, "Attempted to add window with non-application token "
1234 + token + ". Aborting.");
1235 return WindowManagerImpl.ADD_NOT_APP_TOKEN;
1236 } else if (atoken.removed) {
1237 Log.w(TAG, "Attempted to add window with exiting application token "
1238 + token + ". Aborting.");
1239 return WindowManagerImpl.ADD_APP_EXITING;
1240 }
1241 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
1242 // No need for this guy!
1243 if (localLOGV) Log.v(
1244 TAG, "**** NO NEED TO START: " + attrs.getTitle());
1245 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
1246 }
1247 } else if (attrs.type == TYPE_INPUT_METHOD) {
1248 if (token.windowType != TYPE_INPUT_METHOD) {
1249 Log.w(TAG, "Attempted to add input method window with bad token "
1250 + attrs.token + ". Aborting.");
1251 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1252 }
1253 }
1254
1255 win = new WindowState(session, client, token,
1256 attachedWindow, attrs, viewVisibility);
1257 if (win.mDeathRecipient == null) {
1258 // Client has apparently died, so there is no reason to
1259 // continue.
1260 Log.w(TAG, "Adding window client " + client.asBinder()
1261 + " that is dead, aborting.");
1262 return WindowManagerImpl.ADD_APP_EXITING;
1263 }
1264
1265 mPolicy.adjustWindowParamsLw(win.mAttrs);
Romain Guy06882f82009-06-10 13:36:04 -07001266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 res = mPolicy.prepareAddWindowLw(win, attrs);
1268 if (res != WindowManagerImpl.ADD_OKAY) {
1269 return res;
1270 }
1271
1272 // From now on, no exceptions or errors allowed!
1273
1274 res = WindowManagerImpl.ADD_OKAY;
Romain Guy06882f82009-06-10 13:36:04 -07001275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 if (addToken) {
1279 mTokenMap.put(attrs.token, token);
1280 mTokenList.add(token);
1281 }
1282 win.attach();
1283 mWindowMap.put(client.asBinder(), win);
1284
1285 if (attrs.type == TYPE_APPLICATION_STARTING &&
1286 token.appWindowToken != null) {
1287 token.appWindowToken.startingWindow = win;
1288 }
1289
1290 boolean imMayMove = true;
Romain Guy06882f82009-06-10 13:36:04 -07001291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 if (attrs.type == TYPE_INPUT_METHOD) {
1293 mInputMethodWindow = win;
1294 addInputMethodWindowToListLocked(win);
1295 imMayMove = false;
1296 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
1297 mInputMethodDialogs.add(win);
1298 addWindowToListInOrderLocked(win, true);
1299 adjustInputMethodDialogsLocked();
1300 imMayMove = false;
1301 } else {
1302 addWindowToListInOrderLocked(win, true);
1303 }
Romain Guy06882f82009-06-10 13:36:04 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 win.mEnterAnimationPending = true;
Romain Guy06882f82009-06-10 13:36:04 -07001306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
Romain Guy06882f82009-06-10 13:36:04 -07001308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 if (mInTouchMode) {
1310 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
1311 }
1312 if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
1313 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
1314 }
Romain Guy06882f82009-06-10 13:36:04 -07001315
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001316 boolean focusChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 if (win.canReceiveKeys()) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001318 if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
1319 == true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 imMayMove = false;
1321 }
1322 }
Romain Guy06882f82009-06-10 13:36:04 -07001323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 if (imMayMove) {
Romain Guy06882f82009-06-10 13:36:04 -07001325 moveInputMethodWindowsIfNeededLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 }
Romain Guy06882f82009-06-10 13:36:04 -07001327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 assignLayersLocked();
1329 // Don't do layout here, the window must call
1330 // relayout to be displayed, so we'll do it there.
Romain Guy06882f82009-06-10 13:36:04 -07001331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 //dump();
1333
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001334 if (focusChanged) {
1335 if (mCurrentFocus != null) {
1336 mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
1337 }
1338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 if (localLOGV) Log.v(
1340 TAG, "New client " + client.asBinder()
1341 + ": window=" + win);
1342 }
1343
1344 // sendNewConfiguration() checks caller permissions so we must call it with
1345 // privilege. updateOrientationFromAppTokens() clears and resets the caller
1346 // identity anyway, so it's safe to just clear & restore around this whole
1347 // block.
1348 final long origId = Binder.clearCallingIdentity();
1349 if (reportNewConfig) {
1350 sendNewConfiguration();
1351 } else {
1352 // Update Orientation after adding a window, only if the window needs to be
1353 // displayed right away
1354 if (win.isVisibleOrAdding()) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001355 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 sendNewConfiguration();
1357 }
1358 }
1359 }
1360 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 return res;
1363 }
Romain Guy06882f82009-06-10 13:36:04 -07001364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 public void removeWindow(Session session, IWindow client) {
1366 synchronized(mWindowMap) {
1367 WindowState win = windowForClientLocked(session, client);
1368 if (win == null) {
1369 return;
1370 }
1371 removeWindowLocked(session, win);
1372 }
1373 }
Romain Guy06882f82009-06-10 13:36:04 -07001374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 public void removeWindowLocked(Session session, WindowState win) {
1376
1377 if (localLOGV || DEBUG_FOCUS) Log.v(
1378 TAG, "Remove " + win + " client="
1379 + Integer.toHexString(System.identityHashCode(
1380 win.mClient.asBinder()))
1381 + ", surface=" + win.mSurface);
1382
1383 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 if (DEBUG_APP_TRANSITIONS) Log.v(
1386 TAG, "Remove " + win + ": mSurface=" + win.mSurface
1387 + " mExiting=" + win.mExiting
1388 + " isAnimating=" + win.isAnimating()
1389 + " app-animation="
1390 + (win.mAppToken != null ? win.mAppToken.animation : null)
1391 + " inPendingTransaction="
1392 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
1393 + " mDisplayFrozen=" + mDisplayFrozen);
1394 // Visibility of the removed window. Will be used later to update orientation later on.
1395 boolean wasVisible = false;
1396 // First, see if we need to run an animation. If we do, we have
1397 // to hold off on removing the window until the animation is done.
1398 // If the display is frozen, just remove immediately, since the
1399 // animation wouldn't be seen.
1400 if (win.mSurface != null && !mDisplayFrozen) {
1401 // If we are not currently running the exit animation, we
1402 // need to see about starting one.
1403 if (wasVisible=win.isWinVisibleLw()) {
Romain Guy06882f82009-06-10 13:36:04 -07001404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1406 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1407 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1408 }
1409 // Try starting an animation.
1410 if (applyAnimationLocked(win, transit, false)) {
1411 win.mExiting = true;
1412 }
1413 }
1414 if (win.mExiting || win.isAnimating()) {
1415 // The exit animation is running... wait for it!
1416 //Log.i(TAG, "*** Running exit animation...");
1417 win.mExiting = true;
1418 win.mRemoveOnExit = true;
1419 mLayoutNeeded = true;
1420 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
1421 performLayoutAndPlaceSurfacesLocked();
1422 if (win.mAppToken != null) {
1423 win.mAppToken.updateReportedVisibilityLocked();
1424 }
1425 //dump();
1426 Binder.restoreCallingIdentity(origId);
1427 return;
1428 }
1429 }
1430
1431 removeWindowInnerLocked(session, win);
1432 // Removing a visible window will effect the computed orientation
1433 // So just update orientation if needed.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001434 if (wasVisible && computeForcedAppOrientationLocked()
1435 != mForcedAppOrientation) {
1436 mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
1438 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1439 Binder.restoreCallingIdentity(origId);
1440 }
Romain Guy06882f82009-06-10 13:36:04 -07001441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 private void removeWindowInnerLocked(Session session, WindowState win) {
1443 mKeyWaiter.releasePendingPointerLocked(win.mSession);
1444 mKeyWaiter.releasePendingTrackballLocked(win.mSession);
Romain Guy06882f82009-06-10 13:36:04 -07001445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 win.mRemoved = true;
Romain Guy06882f82009-06-10 13:36:04 -07001447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 if (mInputMethodTarget == win) {
1449 moveInputMethodWindowsIfNeededLocked(false);
1450 }
Romain Guy06882f82009-06-10 13:36:04 -07001451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 mPolicy.removeWindowLw(win);
1453 win.removeLocked();
1454
1455 mWindowMap.remove(win.mClient.asBinder());
1456 mWindows.remove(win);
1457
1458 if (mInputMethodWindow == win) {
1459 mInputMethodWindow = null;
1460 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
1461 mInputMethodDialogs.remove(win);
1462 }
Romain Guy06882f82009-06-10 13:36:04 -07001463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 final WindowToken token = win.mToken;
1465 final AppWindowToken atoken = win.mAppToken;
1466 token.windows.remove(win);
1467 if (atoken != null) {
1468 atoken.allAppWindows.remove(win);
1469 }
1470 if (localLOGV) Log.v(
1471 TAG, "**** Removing window " + win + ": count="
1472 + token.windows.size());
1473 if (token.windows.size() == 0) {
1474 if (!token.explicit) {
1475 mTokenMap.remove(token.token);
1476 mTokenList.remove(token);
1477 } else if (atoken != null) {
1478 atoken.firstWindowDrawn = false;
1479 }
1480 }
1481
1482 if (atoken != null) {
1483 if (atoken.startingWindow == win) {
1484 atoken.startingWindow = null;
1485 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
1486 // If this is the last window and we had requested a starting
1487 // transition window, well there is no point now.
1488 atoken.startingData = null;
1489 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
1490 // If this is the last window except for a starting transition
1491 // window, we need to get rid of the starting transition.
1492 if (DEBUG_STARTING_WINDOW) {
1493 Log.v(TAG, "Schedule remove starting " + token
1494 + ": no more real windows");
1495 }
1496 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
1497 mH.sendMessage(m);
1498 }
1499 }
Romain Guy06882f82009-06-10 13:36:04 -07001500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 if (!mInLayout) {
1502 assignLayersLocked();
1503 mLayoutNeeded = true;
1504 performLayoutAndPlaceSurfacesLocked();
1505 if (win.mAppToken != null) {
1506 win.mAppToken.updateReportedVisibilityLocked();
1507 }
1508 }
1509 }
1510
1511 private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
1512 long origId = Binder.clearCallingIdentity();
1513 try {
1514 synchronized (mWindowMap) {
1515 WindowState w = windowForClientLocked(session, client);
1516 if ((w != null) && (w.mSurface != null)) {
1517 Surface.openTransaction();
1518 try {
1519 w.mSurface.setTransparentRegionHint(region);
1520 } finally {
1521 Surface.closeTransaction();
1522 }
1523 }
1524 }
1525 } finally {
1526 Binder.restoreCallingIdentity(origId);
1527 }
1528 }
1529
1530 void setInsetsWindow(Session session, IWindow client,
Romain Guy06882f82009-06-10 13:36:04 -07001531 int touchableInsets, Rect contentInsets,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 Rect visibleInsets) {
1533 long origId = Binder.clearCallingIdentity();
1534 try {
1535 synchronized (mWindowMap) {
1536 WindowState w = windowForClientLocked(session, client);
1537 if (w != null) {
1538 w.mGivenInsetsPending = false;
1539 w.mGivenContentInsets.set(contentInsets);
1540 w.mGivenVisibleInsets.set(visibleInsets);
1541 w.mTouchableInsets = touchableInsets;
1542 mLayoutNeeded = true;
1543 performLayoutAndPlaceSurfacesLocked();
1544 }
1545 }
1546 } finally {
1547 Binder.restoreCallingIdentity(origId);
1548 }
1549 }
Romain Guy06882f82009-06-10 13:36:04 -07001550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 public void getWindowDisplayFrame(Session session, IWindow client,
1552 Rect outDisplayFrame) {
1553 synchronized(mWindowMap) {
1554 WindowState win = windowForClientLocked(session, client);
1555 if (win == null) {
1556 outDisplayFrame.setEmpty();
1557 return;
1558 }
1559 outDisplayFrame.set(win.mDisplayFrame);
1560 }
1561 }
1562
1563 public int relayoutWindow(Session session, IWindow client,
1564 WindowManager.LayoutParams attrs, int requestedWidth,
1565 int requestedHeight, int viewVisibility, boolean insetsPending,
1566 Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
1567 Surface outSurface) {
1568 boolean displayed = false;
1569 boolean inTouchMode;
1570 Configuration newConfig = null;
1571 long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 synchronized(mWindowMap) {
1574 WindowState win = windowForClientLocked(session, client);
1575 if (win == null) {
1576 return 0;
1577 }
1578 win.mRequestedWidth = requestedWidth;
1579 win.mRequestedHeight = requestedHeight;
1580
1581 if (attrs != null) {
1582 mPolicy.adjustWindowParamsLw(attrs);
1583 }
Romain Guy06882f82009-06-10 13:36:04 -07001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 int attrChanges = 0;
1586 int flagChanges = 0;
1587 if (attrs != null) {
1588 flagChanges = win.mAttrs.flags ^= attrs.flags;
1589 attrChanges = win.mAttrs.copyFrom(attrs);
1590 }
1591
1592 if (localLOGV) Log.v(
1593 TAG, "Relayout given client " + client.asBinder()
1594 + " (" + win.mAttrs.getTitle() + ")");
1595
1596
1597 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
1598 win.mAlpha = attrs.alpha;
1599 }
1600
1601 final boolean scaledWindow =
1602 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
1603
1604 if (scaledWindow) {
1605 // requested{Width|Height} Surface's physical size
1606 // attrs.{width|height} Size on screen
1607 win.mHScale = (attrs.width != requestedWidth) ?
1608 (attrs.width / (float)requestedWidth) : 1.0f;
1609 win.mVScale = (attrs.height != requestedHeight) ?
1610 (attrs.height / (float)requestedHeight) : 1.0f;
1611 }
1612
1613 boolean imMayMove = (flagChanges&(
1614 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
1615 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07001616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 boolean focusMayChange = win.mViewVisibility != viewVisibility
1618 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
1619 || (!win.mRelayoutCalled);
Romain Guy06882f82009-06-10 13:36:04 -07001620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 win.mRelayoutCalled = true;
1622 final int oldVisibility = win.mViewVisibility;
1623 win.mViewVisibility = viewVisibility;
1624 if (viewVisibility == View.VISIBLE &&
1625 (win.mAppToken == null || !win.mAppToken.clientHidden)) {
1626 displayed = !win.isVisibleLw();
1627 if (win.mExiting) {
1628 win.mExiting = false;
1629 win.mAnimation = null;
1630 }
1631 if (win.mDestroying) {
1632 win.mDestroying = false;
1633 mDestroySurface.remove(win);
1634 }
1635 if (oldVisibility == View.GONE) {
1636 win.mEnterAnimationPending = true;
1637 }
1638 if (displayed && win.mSurface != null && !win.mDrawPending
1639 && !win.mCommitDrawPending && !mDisplayFrozen) {
1640 applyEnterAnimationLocked(win);
1641 }
1642 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
1643 // To change the format, we need to re-build the surface.
1644 win.destroySurfaceLocked();
1645 displayed = true;
1646 }
1647 try {
1648 Surface surface = win.createSurfaceLocked();
1649 if (surface != null) {
1650 outSurface.copyFrom(surface);
1651 } else {
1652 outSurface.clear();
1653 }
1654 } catch (Exception e) {
1655 Log.w(TAG, "Exception thrown when creating surface for client "
1656 + client + " (" + win.mAttrs.getTitle() + ")",
1657 e);
1658 Binder.restoreCallingIdentity(origId);
1659 return 0;
1660 }
1661 if (displayed) {
1662 focusMayChange = true;
1663 }
1664 if (win.mAttrs.type == TYPE_INPUT_METHOD
1665 && mInputMethodWindow == null) {
1666 mInputMethodWindow = win;
1667 imMayMove = true;
1668 }
1669 } else {
1670 win.mEnterAnimationPending = false;
1671 if (win.mSurface != null) {
1672 // If we are not currently running the exit animation, we
1673 // need to see about starting one.
1674 if (!win.mExiting) {
1675 // Try starting an animation; if there isn't one, we
1676 // can destroy the surface right away.
1677 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1678 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1679 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1680 }
1681 if (win.isWinVisibleLw() &&
1682 applyAnimationLocked(win, transit, false)) {
1683 win.mExiting = true;
1684 mKeyWaiter.finishedKey(session, client, true,
1685 KeyWaiter.RETURN_NOTHING);
1686 } else if (win.isAnimating()) {
1687 // Currently in a hide animation... turn this into
1688 // an exit.
1689 win.mExiting = true;
1690 } else {
1691 if (mInputMethodWindow == win) {
1692 mInputMethodWindow = null;
1693 }
1694 win.destroySurfaceLocked();
1695 }
1696 }
1697 }
1698 outSurface.clear();
1699 }
1700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 if (focusMayChange) {
1702 //System.out.println("Focus may change: " + win.mAttrs.getTitle());
1703 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 imMayMove = false;
1705 }
1706 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
1707 }
Romain Guy06882f82009-06-10 13:36:04 -07001708
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001709 // updateFocusedWindowLocked() already assigned layers so we only need to
1710 // reassign them at this point if the IM window state gets shuffled
1711 boolean assignLayers = false;
Romain Guy06882f82009-06-10 13:36:04 -07001712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 if (imMayMove) {
1714 if (moveInputMethodWindowsIfNeededLocked(false)) {
1715 assignLayers = true;
1716 }
1717 }
Romain Guy06882f82009-06-10 13:36:04 -07001718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 mLayoutNeeded = true;
1720 win.mGivenInsetsPending = insetsPending;
1721 if (assignLayers) {
1722 assignLayersLocked();
1723 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001724 newConfig = updateOrientationFromAppTokensLocked(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 performLayoutAndPlaceSurfacesLocked();
1726 if (win.mAppToken != null) {
1727 win.mAppToken.updateReportedVisibilityLocked();
1728 }
1729 outFrame.set(win.mFrame);
1730 outContentInsets.set(win.mContentInsets);
1731 outVisibleInsets.set(win.mVisibleInsets);
1732 if (localLOGV) Log.v(
1733 TAG, "Relayout given client " + client.asBinder()
Romain Guy06882f82009-06-10 13:36:04 -07001734 + ", requestedWidth=" + requestedWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 + ", requestedHeight=" + requestedHeight
1736 + ", viewVisibility=" + viewVisibility
1737 + "\nRelayout returning frame=" + outFrame
1738 + ", surface=" + outSurface);
1739
1740 if (localLOGV || DEBUG_FOCUS) Log.v(
1741 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
1742
1743 inTouchMode = mInTouchMode;
1744 }
1745
1746 if (newConfig != null) {
1747 sendNewConfiguration();
1748 }
Romain Guy06882f82009-06-10 13:36:04 -07001749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
1753 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
1754 }
1755
1756 public void finishDrawingWindow(Session session, IWindow client) {
1757 final long origId = Binder.clearCallingIdentity();
1758 synchronized(mWindowMap) {
1759 WindowState win = windowForClientLocked(session, client);
1760 if (win != null && win.finishDrawingLocked()) {
1761 mLayoutNeeded = true;
1762 performLayoutAndPlaceSurfacesLocked();
1763 }
1764 }
1765 Binder.restoreCallingIdentity(origId);
1766 }
1767
1768 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
1769 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
1770 + (lp != null ? lp.packageName : null)
1771 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
1772 if (lp != null && lp.windowAnimations != 0) {
1773 // If this is a system resource, don't try to load it from the
1774 // application resources. It is nice to avoid loading application
1775 // resources if we can.
1776 String packageName = lp.packageName != null ? lp.packageName : "android";
1777 int resId = lp.windowAnimations;
1778 if ((resId&0xFF000000) == 0x01000000) {
1779 packageName = "android";
1780 }
1781 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
1782 + packageName);
1783 return AttributeCache.instance().get(packageName, resId,
1784 com.android.internal.R.styleable.WindowAnimation);
1785 }
1786 return null;
1787 }
Romain Guy06882f82009-06-10 13:36:04 -07001788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 private void applyEnterAnimationLocked(WindowState win) {
1790 int transit = WindowManagerPolicy.TRANSIT_SHOW;
1791 if (win.mEnterAnimationPending) {
1792 win.mEnterAnimationPending = false;
1793 transit = WindowManagerPolicy.TRANSIT_ENTER;
1794 }
1795
1796 applyAnimationLocked(win, transit, true);
1797 }
1798
1799 private boolean applyAnimationLocked(WindowState win,
1800 int transit, boolean isEntrance) {
1801 if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
1802 // If we are trying to apply an animation, but already running
1803 // an animation of the same type, then just leave that one alone.
1804 return true;
1805 }
Romain Guy06882f82009-06-10 13:36:04 -07001806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 // Only apply an animation if the display isn't frozen. If it is
1808 // frozen, there is no reason to animate and it can cause strange
1809 // artifacts when we unfreeze the display if some different animation
1810 // is running.
1811 if (!mDisplayFrozen) {
1812 int anim = mPolicy.selectAnimationLw(win, transit);
1813 int attr = -1;
1814 Animation a = null;
1815 if (anim != 0) {
1816 a = AnimationUtils.loadAnimation(mContext, anim);
1817 } else {
1818 switch (transit) {
1819 case WindowManagerPolicy.TRANSIT_ENTER:
1820 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
1821 break;
1822 case WindowManagerPolicy.TRANSIT_EXIT:
1823 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
1824 break;
1825 case WindowManagerPolicy.TRANSIT_SHOW:
1826 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
1827 break;
1828 case WindowManagerPolicy.TRANSIT_HIDE:
1829 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
1830 break;
1831 }
1832 if (attr >= 0) {
1833 a = loadAnimation(win.mAttrs, attr);
1834 }
1835 }
1836 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
1837 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
1838 + " mAnimation=" + win.mAnimation
1839 + " isEntrance=" + isEntrance);
1840 if (a != null) {
1841 if (DEBUG_ANIM) {
1842 RuntimeException e = new RuntimeException();
1843 e.fillInStackTrace();
1844 Log.v(TAG, "Loaded animation " + a + " for " + win, e);
1845 }
1846 win.setAnimation(a);
1847 win.mAnimationIsEntrance = isEntrance;
1848 }
1849 } else {
1850 win.clearAnimation();
1851 }
1852
1853 return win.mAnimation != null;
1854 }
1855
1856 private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
1857 int anim = 0;
1858 Context context = mContext;
1859 if (animAttr >= 0) {
1860 AttributeCache.Entry ent = getCachedAnimations(lp);
1861 if (ent != null) {
1862 context = ent.context;
1863 anim = ent.array.getResourceId(animAttr, 0);
1864 }
1865 }
1866 if (anim != 0) {
1867 return AnimationUtils.loadAnimation(context, anim);
1868 }
1869 return null;
1870 }
Romain Guy06882f82009-06-10 13:36:04 -07001871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 private boolean applyAnimationLocked(AppWindowToken wtoken,
1873 WindowManager.LayoutParams lp, int transit, boolean enter) {
1874 // Only apply an animation if the display isn't frozen. If it is
1875 // frozen, there is no reason to animate and it can cause strange
1876 // artifacts when we unfreeze the display if some different animation
1877 // is running.
1878 if (!mDisplayFrozen) {
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07001879 Animation a;
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07001880 if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07001881 a = new FadeInOutAnimation(enter);
1882 if (DEBUG_ANIM) Log.v(TAG,
1883 "applying FadeInOutAnimation for a window in compatibility mode");
1884 } else {
1885 int animAttr = 0;
1886 switch (transit) {
1887 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
1888 animAttr = enter
1889 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
1890 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
1891 break;
1892 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
1893 animAttr = enter
1894 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
1895 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
1896 break;
1897 case WindowManagerPolicy.TRANSIT_TASK_OPEN:
1898 animAttr = enter
1899 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
1900 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
1901 break;
1902 case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
1903 animAttr = enter
1904 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
1905 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
1906 break;
1907 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
1908 animAttr = enter
1909 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
1910 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
1911 break;
1912 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
1913 animAttr = enter
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07001914 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07001915 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
1916 break;
1917 }
1918 a = loadAnimation(lp, animAttr);
1919 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
1920 + " anim=" + a
1921 + " animAttr=0x" + Integer.toHexString(animAttr)
1922 + " transit=" + transit);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 if (a != null) {
1925 if (DEBUG_ANIM) {
1926 RuntimeException e = new RuntimeException();
1927 e.fillInStackTrace();
1928 Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
1929 }
1930 wtoken.setAnimation(a);
1931 }
1932 } else {
1933 wtoken.clearAnimation();
1934 }
1935
1936 return wtoken.animation != null;
1937 }
1938
1939 // -------------------------------------------------------------
1940 // Application Window Tokens
1941 // -------------------------------------------------------------
1942
1943 public void validateAppTokens(List tokens) {
1944 int v = tokens.size()-1;
1945 int m = mAppTokens.size()-1;
1946 while (v >= 0 && m >= 0) {
1947 AppWindowToken wtoken = mAppTokens.get(m);
1948 if (wtoken.removed) {
1949 m--;
1950 continue;
1951 }
1952 if (tokens.get(v) != wtoken.token) {
1953 Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
1954 + " @ " + v + ", internal is " + wtoken.token + " @ " + m);
1955 }
1956 v--;
1957 m--;
1958 }
1959 while (v >= 0) {
1960 Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
1961 v--;
1962 }
1963 while (m >= 0) {
1964 AppWindowToken wtoken = mAppTokens.get(m);
1965 if (!wtoken.removed) {
1966 Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
1967 }
1968 m--;
1969 }
1970 }
1971
1972 boolean checkCallingPermission(String permission, String func) {
1973 // Quick check: if the calling permission is me, it's all okay.
1974 if (Binder.getCallingPid() == Process.myPid()) {
1975 return true;
1976 }
Romain Guy06882f82009-06-10 13:36:04 -07001977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 if (mContext.checkCallingPermission(permission)
1979 == PackageManager.PERMISSION_GRANTED) {
1980 return true;
1981 }
1982 String msg = "Permission Denial: " + func + " from pid="
1983 + Binder.getCallingPid()
1984 + ", uid=" + Binder.getCallingUid()
1985 + " requires " + permission;
1986 Log.w(TAG, msg);
1987 return false;
1988 }
Romain Guy06882f82009-06-10 13:36:04 -07001989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 AppWindowToken findAppWindowToken(IBinder token) {
1991 WindowToken wtoken = mTokenMap.get(token);
1992 if (wtoken == null) {
1993 return null;
1994 }
1995 return wtoken.appWindowToken;
1996 }
Romain Guy06882f82009-06-10 13:36:04 -07001997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 public void addWindowToken(IBinder token, int type) {
1999 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2000 "addWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002001 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 }
Romain Guy06882f82009-06-10 13:36:04 -07002003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 synchronized(mWindowMap) {
2005 WindowToken wtoken = mTokenMap.get(token);
2006 if (wtoken != null) {
2007 Log.w(TAG, "Attempted to add existing input method token: " + token);
2008 return;
2009 }
2010 wtoken = new WindowToken(token, type, true);
2011 mTokenMap.put(token, wtoken);
2012 mTokenList.add(wtoken);
2013 }
2014 }
Romain Guy06882f82009-06-10 13:36:04 -07002015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 public void removeWindowToken(IBinder token) {
2017 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2018 "removeWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002019 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 }
2021
2022 final long origId = Binder.clearCallingIdentity();
2023 synchronized(mWindowMap) {
2024 WindowToken wtoken = mTokenMap.remove(token);
2025 mTokenList.remove(wtoken);
2026 if (wtoken != null) {
2027 boolean delayed = false;
2028 if (!wtoken.hidden) {
2029 wtoken.hidden = true;
Romain Guy06882f82009-06-10 13:36:04 -07002030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 final int N = wtoken.windows.size();
2032 boolean changed = false;
Romain Guy06882f82009-06-10 13:36:04 -07002033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 for (int i=0; i<N; i++) {
2035 WindowState win = wtoken.windows.get(i);
2036
2037 if (win.isAnimating()) {
2038 delayed = true;
2039 }
Romain Guy06882f82009-06-10 13:36:04 -07002040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 if (win.isVisibleNow()) {
2042 applyAnimationLocked(win,
2043 WindowManagerPolicy.TRANSIT_EXIT, false);
2044 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2045 KeyWaiter.RETURN_NOTHING);
2046 changed = true;
2047 }
2048 }
2049
2050 if (changed) {
2051 mLayoutNeeded = true;
2052 performLayoutAndPlaceSurfacesLocked();
2053 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2054 }
Romain Guy06882f82009-06-10 13:36:04 -07002055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 if (delayed) {
2057 mExitingTokens.add(wtoken);
2058 }
2059 }
Romain Guy06882f82009-06-10 13:36:04 -07002060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 } else {
2062 Log.w(TAG, "Attempted to remove non-existing token: " + token);
2063 }
2064 }
2065 Binder.restoreCallingIdentity(origId);
2066 }
2067
2068 public void addAppToken(int addPos, IApplicationToken token,
2069 int groupId, int requestedOrientation, boolean fullscreen) {
2070 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2071 "addAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002072 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
Romain Guy06882f82009-06-10 13:36:04 -07002074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 synchronized(mWindowMap) {
2076 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2077 if (wtoken != null) {
2078 Log.w(TAG, "Attempted to add existing app token: " + token);
2079 return;
2080 }
2081 wtoken = new AppWindowToken(token);
2082 wtoken.groupId = groupId;
2083 wtoken.appFullscreen = fullscreen;
2084 wtoken.requestedOrientation = requestedOrientation;
2085 mAppTokens.add(addPos, wtoken);
Dave Bortcfe65242009-04-09 14:51:04 -07002086 if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 mTokenMap.put(token.asBinder(), wtoken);
2088 mTokenList.add(wtoken);
Romain Guy06882f82009-06-10 13:36:04 -07002089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002090 // Application tokens start out hidden.
2091 wtoken.hidden = true;
2092 wtoken.hiddenRequested = true;
Romain Guy06882f82009-06-10 13:36:04 -07002093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002094 //dump();
2095 }
2096 }
Romain Guy06882f82009-06-10 13:36:04 -07002097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 public void setAppGroupId(IBinder token, int groupId) {
2099 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2100 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002101 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 }
2103
2104 synchronized(mWindowMap) {
2105 AppWindowToken wtoken = findAppWindowToken(token);
2106 if (wtoken == null) {
2107 Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
2108 return;
2109 }
2110 wtoken.groupId = groupId;
2111 }
2112 }
Romain Guy06882f82009-06-10 13:36:04 -07002113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 public int getOrientationFromWindowsLocked() {
2115 int pos = mWindows.size() - 1;
2116 while (pos >= 0) {
2117 WindowState wtoken = (WindowState) mWindows.get(pos);
2118 pos--;
2119 if (wtoken.mAppToken != null) {
2120 // We hit an application window. so the orientation will be determined by the
2121 // app window. No point in continuing further.
2122 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2123 }
2124 if (!wtoken.isVisibleLw()) {
2125 continue;
2126 }
2127 int req = wtoken.mAttrs.screenOrientation;
2128 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
2129 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
2130 continue;
2131 } else {
2132 return req;
2133 }
2134 }
2135 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2136 }
Romain Guy06882f82009-06-10 13:36:04 -07002137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 public int getOrientationFromAppTokensLocked() {
2139 int pos = mAppTokens.size() - 1;
2140 int curGroup = 0;
2141 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Owen Lin3413b892009-05-01 17:12:32 -07002142 boolean findingBehind = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 boolean haveGroup = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002144 boolean lastFullscreen = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 while (pos >= 0) {
2146 AppWindowToken wtoken = mAppTokens.get(pos);
2147 pos--;
Owen Lin3413b892009-05-01 17:12:32 -07002148 // if we're about to tear down this window and not seek for
2149 // the behind activity, don't use it for orientation
2150 if (!findingBehind
2151 && (!wtoken.hidden && wtoken.hiddenRequested)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002152 continue;
2153 }
2154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 if (!haveGroup) {
2156 // We ignore any hidden applications on the top.
2157 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
2158 continue;
2159 }
2160 haveGroup = true;
2161 curGroup = wtoken.groupId;
2162 lastOrientation = wtoken.requestedOrientation;
2163 } else if (curGroup != wtoken.groupId) {
2164 // If we have hit a new application group, and the bottom
2165 // of the previous group didn't explicitly say to use
The Android Open Source Project4df24232009-03-05 14:34:35 -08002166 // the orientation behind it, and the last app was
2167 // full screen, then we'll stick with the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168 // user's orientation.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002169 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
2170 && lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 return lastOrientation;
2172 }
2173 }
2174 int or = wtoken.requestedOrientation;
Owen Lin3413b892009-05-01 17:12:32 -07002175 // If this application is fullscreen, and didn't explicitly say
2176 // to use the orientation behind it, then just take whatever
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 // orientation it has and ignores whatever is under it.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002178 lastFullscreen = wtoken.appFullscreen;
Romain Guy06882f82009-06-10 13:36:04 -07002179 if (lastFullscreen
Owen Lin3413b892009-05-01 17:12:32 -07002180 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 return or;
2182 }
2183 // If this application has requested an explicit orientation,
2184 // then use it.
2185 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
2186 or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
2187 or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
2188 or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
2189 or == ActivityInfo.SCREEN_ORIENTATION_USER) {
2190 return or;
2191 }
Owen Lin3413b892009-05-01 17:12:32 -07002192 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 }
2194 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2195 }
Romain Guy06882f82009-06-10 13:36:04 -07002196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 public Configuration updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002198 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002199 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2200 "updateOrientationFromAppTokens()")) {
2201 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
2202 }
2203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 Configuration config;
2205 long ident = Binder.clearCallingIdentity();
Dianne Hackborncfaef692009-06-15 14:24:44 -07002206 config = updateOrientationFromAppTokensUnchecked(currentConfig,
2207 freezeThisOneIfNeeded);
2208 Binder.restoreCallingIdentity(ident);
2209 return config;
2210 }
2211
2212 Configuration updateOrientationFromAppTokensUnchecked(
2213 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
2214 Configuration config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 synchronized(mWindowMap) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002216 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 }
2218 if (config != null) {
2219 mLayoutNeeded = true;
2220 performLayoutAndPlaceSurfacesLocked();
2221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 return config;
2223 }
Romain Guy06882f82009-06-10 13:36:04 -07002224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 /*
2226 * The orientation is computed from non-application windows first. If none of
2227 * the non-application windows specify orientation, the orientation is computed from
Romain Guy06882f82009-06-10 13:36:04 -07002228 * application tokens.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 * @see android.view.IWindowManager#updateOrientationFromAppTokens(
2230 * android.os.IBinder)
2231 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002232 Configuration updateOrientationFromAppTokensLocked(
The Android Open Source Project10592532009-03-18 17:39:46 -07002233 Configuration appConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002234 boolean changed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235 long ident = Binder.clearCallingIdentity();
2236 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002237 int req = computeForcedAppOrientationLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 if (req != mForcedAppOrientation) {
2240 changed = true;
2241 mForcedAppOrientation = req;
2242 //send a message to Policy indicating orientation change to take
2243 //action like disabling/enabling sensors etc.,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002244 mPolicy.setCurrentOrientationLw(req);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002245 }
Romain Guy06882f82009-06-10 13:36:04 -07002246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 if (changed) {
2248 changed = setRotationUncheckedLocked(
Dianne Hackborn321ae682009-03-27 16:16:03 -07002249 WindowManagerPolicy.USE_LAST_ROTATION,
2250 mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 if (changed) {
2252 if (freezeThisOneIfNeeded != null) {
2253 AppWindowToken wtoken = findAppWindowToken(
2254 freezeThisOneIfNeeded);
2255 if (wtoken != null) {
2256 startAppFreezingScreenLocked(wtoken,
2257 ActivityInfo.CONFIG_ORIENTATION);
2258 }
2259 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07002260 return computeNewConfigurationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002261 }
2262 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002263
2264 // No obvious action we need to take, but if our current
2265 // state mismatches the activity maanager's, update it
2266 if (appConfig != null) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07002267 mTempConfiguration.setToDefaults();
2268 if (computeNewConfigurationLocked(mTempConfiguration)) {
2269 if (appConfig.diff(mTempConfiguration) != 0) {
2270 Log.i(TAG, "Config changed: " + mTempConfiguration);
2271 return new Configuration(mTempConfiguration);
2272 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002273 }
2274 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 } finally {
2276 Binder.restoreCallingIdentity(ident);
2277 }
Romain Guy06882f82009-06-10 13:36:04 -07002278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002279 return null;
2280 }
Romain Guy06882f82009-06-10 13:36:04 -07002281
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002282 int computeForcedAppOrientationLocked() {
2283 int req = getOrientationFromWindowsLocked();
2284 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
2285 req = getOrientationFromAppTokensLocked();
2286 }
2287 return req;
2288 }
Romain Guy06882f82009-06-10 13:36:04 -07002289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
2291 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2292 "setAppOrientation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002293 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 }
Romain Guy06882f82009-06-10 13:36:04 -07002295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002296 synchronized(mWindowMap) {
2297 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2298 if (wtoken == null) {
2299 Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
2300 return;
2301 }
Romain Guy06882f82009-06-10 13:36:04 -07002302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 wtoken.requestedOrientation = requestedOrientation;
2304 }
2305 }
Romain Guy06882f82009-06-10 13:36:04 -07002306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 public int getAppOrientation(IApplicationToken token) {
2308 synchronized(mWindowMap) {
2309 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2310 if (wtoken == null) {
2311 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2312 }
Romain Guy06882f82009-06-10 13:36:04 -07002313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002314 return wtoken.requestedOrientation;
2315 }
2316 }
Romain Guy06882f82009-06-10 13:36:04 -07002317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 public void setFocusedApp(IBinder token, boolean moveFocusNow) {
2319 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2320 "setFocusedApp()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002321 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 }
2323
2324 synchronized(mWindowMap) {
2325 boolean changed = false;
2326 if (token == null) {
2327 if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
2328 changed = mFocusedApp != null;
2329 mFocusedApp = null;
2330 mKeyWaiter.tickle();
2331 } else {
2332 AppWindowToken newFocus = findAppWindowToken(token);
2333 if (newFocus == null) {
2334 Log.w(TAG, "Attempted to set focus to non-existing app token: " + token);
2335 return;
2336 }
2337 changed = mFocusedApp != newFocus;
2338 mFocusedApp = newFocus;
2339 if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp);
2340 mKeyWaiter.tickle();
2341 }
2342
2343 if (moveFocusNow && changed) {
2344 final long origId = Binder.clearCallingIdentity();
2345 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2346 Binder.restoreCallingIdentity(origId);
2347 }
2348 }
2349 }
2350
2351 public void prepareAppTransition(int transit) {
2352 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2353 "prepareAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002354 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002355 }
Romain Guy06882f82009-06-10 13:36:04 -07002356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357 synchronized(mWindowMap) {
2358 if (DEBUG_APP_TRANSITIONS) Log.v(
2359 TAG, "Prepare app transition: transit=" + transit
2360 + " mNextAppTransition=" + mNextAppTransition);
2361 if (!mDisplayFrozen) {
2362 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
2363 mNextAppTransition = transit;
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002364 } else if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
2365 && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
2366 // Opening a new task always supersedes a close for the anim.
2367 mNextAppTransition = transit;
2368 } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2369 && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
2370 // Opening a new activity always supersedes a close for the anim.
2371 mNextAppTransition = transit;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002372 }
2373 mAppTransitionReady = false;
2374 mAppTransitionTimeout = false;
2375 mStartingIconInTransition = false;
2376 mSkipAppTransitionAnimation = false;
2377 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2378 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
2379 5000);
2380 }
2381 }
2382 }
2383
2384 public int getPendingAppTransition() {
2385 return mNextAppTransition;
2386 }
Romain Guy06882f82009-06-10 13:36:04 -07002387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002388 public void executeAppTransition() {
2389 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2390 "executeAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002391 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 }
Romain Guy06882f82009-06-10 13:36:04 -07002393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 synchronized(mWindowMap) {
2395 if (DEBUG_APP_TRANSITIONS) Log.v(
2396 TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
2397 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2398 mAppTransitionReady = true;
2399 final long origId = Binder.clearCallingIdentity();
2400 performLayoutAndPlaceSurfacesLocked();
2401 Binder.restoreCallingIdentity(origId);
2402 }
2403 }
2404 }
2405
2406 public void setAppStartingWindow(IBinder token, String pkg,
2407 int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
2408 IBinder transferFrom, boolean createIfNeeded) {
2409 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2410 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002411 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 }
2413
2414 synchronized(mWindowMap) {
2415 if (DEBUG_STARTING_WINDOW) Log.v(
2416 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
2417 + " transferFrom=" + transferFrom);
Romain Guy06882f82009-06-10 13:36:04 -07002418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002419 AppWindowToken wtoken = findAppWindowToken(token);
2420 if (wtoken == null) {
2421 Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
2422 return;
2423 }
2424
2425 // If the display is frozen, we won't do anything until the
2426 // actual window is displayed so there is no reason to put in
2427 // the starting window.
2428 if (mDisplayFrozen) {
2429 return;
2430 }
Romain Guy06882f82009-06-10 13:36:04 -07002431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002432 if (wtoken.startingData != null) {
2433 return;
2434 }
Romain Guy06882f82009-06-10 13:36:04 -07002435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002436 if (transferFrom != null) {
2437 AppWindowToken ttoken = findAppWindowToken(transferFrom);
2438 if (ttoken != null) {
2439 WindowState startingWindow = ttoken.startingWindow;
2440 if (startingWindow != null) {
2441 if (mStartingIconInTransition) {
2442 // In this case, the starting icon has already
2443 // been displayed, so start letting windows get
2444 // shown immediately without any more transitions.
2445 mSkipAppTransitionAnimation = true;
2446 }
2447 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2448 "Moving existing starting from " + ttoken
2449 + " to " + wtoken);
2450 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07002451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002452 // Transfer the starting window over to the new
2453 // token.
2454 wtoken.startingData = ttoken.startingData;
2455 wtoken.startingView = ttoken.startingView;
2456 wtoken.startingWindow = startingWindow;
2457 ttoken.startingData = null;
2458 ttoken.startingView = null;
2459 ttoken.startingWindow = null;
2460 ttoken.startingMoved = true;
2461 startingWindow.mToken = wtoken;
Dianne Hackbornef49c572009-03-24 19:27:32 -07002462 startingWindow.mRootToken = wtoken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 startingWindow.mAppToken = wtoken;
2464 mWindows.remove(startingWindow);
2465 ttoken.windows.remove(startingWindow);
2466 ttoken.allAppWindows.remove(startingWindow);
2467 addWindowToListInOrderLocked(startingWindow, true);
2468 wtoken.allAppWindows.add(startingWindow);
Romain Guy06882f82009-06-10 13:36:04 -07002469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002470 // Propagate other interesting state between the
2471 // tokens. If the old token is displayed, we should
2472 // immediately force the new one to be displayed. If
2473 // it is animating, we need to move that animation to
2474 // the new one.
2475 if (ttoken.allDrawn) {
2476 wtoken.allDrawn = true;
2477 }
2478 if (ttoken.firstWindowDrawn) {
2479 wtoken.firstWindowDrawn = true;
2480 }
2481 if (!ttoken.hidden) {
2482 wtoken.hidden = false;
2483 wtoken.hiddenRequested = false;
2484 wtoken.willBeHidden = false;
2485 }
2486 if (wtoken.clientHidden != ttoken.clientHidden) {
2487 wtoken.clientHidden = ttoken.clientHidden;
2488 wtoken.sendAppVisibilityToClients();
2489 }
2490 if (ttoken.animation != null) {
2491 wtoken.animation = ttoken.animation;
2492 wtoken.animating = ttoken.animating;
2493 wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
2494 ttoken.animation = null;
2495 ttoken.animLayerAdjustment = 0;
2496 wtoken.updateLayers();
2497 ttoken.updateLayers();
2498 }
Romain Guy06882f82009-06-10 13:36:04 -07002499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002500 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002501 mLayoutNeeded = true;
2502 performLayoutAndPlaceSurfacesLocked();
2503 Binder.restoreCallingIdentity(origId);
2504 return;
2505 } else if (ttoken.startingData != null) {
2506 // The previous app was getting ready to show a
2507 // starting window, but hasn't yet done so. Steal it!
2508 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2509 "Moving pending starting from " + ttoken
2510 + " to " + wtoken);
2511 wtoken.startingData = ttoken.startingData;
2512 ttoken.startingData = null;
2513 ttoken.startingMoved = true;
2514 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2515 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2516 // want to process the message ASAP, before any other queued
2517 // messages.
2518 mH.sendMessageAtFrontOfQueue(m);
2519 return;
2520 }
2521 }
2522 }
2523
2524 // There is no existing starting window, and the caller doesn't
2525 // want us to create one, so that's it!
2526 if (!createIfNeeded) {
2527 return;
2528 }
Romain Guy06882f82009-06-10 13:36:04 -07002529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 mStartingIconInTransition = true;
2531 wtoken.startingData = new StartingData(
2532 pkg, theme, nonLocalizedLabel,
2533 labelRes, icon);
2534 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2535 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2536 // want to process the message ASAP, before any other queued
2537 // messages.
2538 mH.sendMessageAtFrontOfQueue(m);
2539 }
2540 }
2541
2542 public void setAppWillBeHidden(IBinder token) {
2543 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2544 "setAppWillBeHidden()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002545 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 }
2547
2548 AppWindowToken wtoken;
2549
2550 synchronized(mWindowMap) {
2551 wtoken = findAppWindowToken(token);
2552 if (wtoken == null) {
2553 Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
2554 return;
2555 }
2556 wtoken.willBeHidden = true;
2557 }
2558 }
Romain Guy06882f82009-06-10 13:36:04 -07002559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
2561 boolean visible, int transit, boolean performLayout) {
2562 boolean delayed = false;
2563
2564 if (wtoken.clientHidden == visible) {
2565 wtoken.clientHidden = !visible;
2566 wtoken.sendAppVisibilityToClients();
2567 }
Romain Guy06882f82009-06-10 13:36:04 -07002568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002569 wtoken.willBeHidden = false;
2570 if (wtoken.hidden == visible) {
2571 final int N = wtoken.allAppWindows.size();
2572 boolean changed = false;
2573 if (DEBUG_APP_TRANSITIONS) Log.v(
2574 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
2575 + " performLayout=" + performLayout);
Romain Guy06882f82009-06-10 13:36:04 -07002576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002577 boolean runningAppAnimation = false;
Romain Guy06882f82009-06-10 13:36:04 -07002578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 if (transit != WindowManagerPolicy.TRANSIT_NONE) {
2580 if (wtoken.animation == sDummyAnimation) {
2581 wtoken.animation = null;
2582 }
2583 applyAnimationLocked(wtoken, lp, transit, visible);
2584 changed = true;
2585 if (wtoken.animation != null) {
2586 delayed = runningAppAnimation = true;
2587 }
2588 }
Romain Guy06882f82009-06-10 13:36:04 -07002589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 for (int i=0; i<N; i++) {
2591 WindowState win = wtoken.allAppWindows.get(i);
2592 if (win == wtoken.startingWindow) {
2593 continue;
2594 }
2595
2596 if (win.isAnimating()) {
2597 delayed = true;
2598 }
Romain Guy06882f82009-06-10 13:36:04 -07002599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
2601 //win.dump(" ");
2602 if (visible) {
2603 if (!win.isVisibleNow()) {
2604 if (!runningAppAnimation) {
2605 applyAnimationLocked(win,
2606 WindowManagerPolicy.TRANSIT_ENTER, true);
2607 }
2608 changed = true;
2609 }
2610 } else if (win.isVisibleNow()) {
2611 if (!runningAppAnimation) {
2612 applyAnimationLocked(win,
2613 WindowManagerPolicy.TRANSIT_EXIT, false);
2614 }
2615 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2616 KeyWaiter.RETURN_NOTHING);
2617 changed = true;
2618 }
2619 }
2620
2621 wtoken.hidden = wtoken.hiddenRequested = !visible;
2622 if (!visible) {
2623 unsetAppFreezingScreenLocked(wtoken, true, true);
2624 } else {
2625 // If we are being set visible, and the starting window is
2626 // not yet displayed, then make sure it doesn't get displayed.
2627 WindowState swin = wtoken.startingWindow;
2628 if (swin != null && (swin.mDrawPending
2629 || swin.mCommitDrawPending)) {
2630 swin.mPolicyVisibility = false;
2631 swin.mPolicyVisibilityAfterAnim = false;
2632 }
2633 }
Romain Guy06882f82009-06-10 13:36:04 -07002634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
2636 + ": hidden=" + wtoken.hidden + " hiddenRequested="
2637 + wtoken.hiddenRequested);
Romain Guy06882f82009-06-10 13:36:04 -07002638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 if (changed && performLayout) {
2640 mLayoutNeeded = true;
2641 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002642 performLayoutAndPlaceSurfacesLocked();
2643 }
2644 }
2645
2646 if (wtoken.animation != null) {
2647 delayed = true;
2648 }
Romain Guy06882f82009-06-10 13:36:04 -07002649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 return delayed;
2651 }
2652
2653 public void setAppVisibility(IBinder token, boolean visible) {
2654 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2655 "setAppVisibility()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002656 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 }
2658
2659 AppWindowToken wtoken;
2660
2661 synchronized(mWindowMap) {
2662 wtoken = findAppWindowToken(token);
2663 if (wtoken == null) {
2664 Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
2665 return;
2666 }
2667
2668 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
2669 RuntimeException e = new RuntimeException();
2670 e.fillInStackTrace();
2671 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
2672 + "): mNextAppTransition=" + mNextAppTransition
2673 + " hidden=" + wtoken.hidden
2674 + " hiddenRequested=" + wtoken.hiddenRequested, e);
2675 }
Romain Guy06882f82009-06-10 13:36:04 -07002676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677 // If we are preparing an app transition, then delay changing
2678 // the visibility of this token until we execute that transition.
2679 if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2680 // Already in requested state, don't do anything more.
2681 if (wtoken.hiddenRequested != visible) {
2682 return;
2683 }
2684 wtoken.hiddenRequested = !visible;
Romain Guy06882f82009-06-10 13:36:04 -07002685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 if (DEBUG_APP_TRANSITIONS) Log.v(
2687 TAG, "Setting dummy animation on: " + wtoken);
2688 wtoken.setDummyAnimation();
2689 mOpeningApps.remove(wtoken);
2690 mClosingApps.remove(wtoken);
2691 wtoken.inPendingTransaction = true;
2692 if (visible) {
2693 mOpeningApps.add(wtoken);
2694 wtoken.allDrawn = false;
2695 wtoken.startingDisplayed = false;
2696 wtoken.startingMoved = false;
Romain Guy06882f82009-06-10 13:36:04 -07002697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698 if (wtoken.clientHidden) {
2699 // In the case where we are making an app visible
2700 // but holding off for a transition, we still need
2701 // to tell the client to make its windows visible so
2702 // they get drawn. Otherwise, we will wait on
2703 // performing the transition until all windows have
2704 // been drawn, they never will be, and we are sad.
2705 wtoken.clientHidden = false;
2706 wtoken.sendAppVisibilityToClients();
2707 }
2708 } else {
2709 mClosingApps.add(wtoken);
2710 }
2711 return;
2712 }
Romain Guy06882f82009-06-10 13:36:04 -07002713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 final long origId = Binder.clearCallingIdentity();
2715 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
2716 wtoken.updateReportedVisibilityLocked();
2717 Binder.restoreCallingIdentity(origId);
2718 }
2719 }
2720
2721 void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
2722 boolean unfreezeSurfaceNow, boolean force) {
2723 if (wtoken.freezingScreen) {
2724 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
2725 + " force=" + force);
2726 final int N = wtoken.allAppWindows.size();
2727 boolean unfrozeWindows = false;
2728 for (int i=0; i<N; i++) {
2729 WindowState w = wtoken.allAppWindows.get(i);
2730 if (w.mAppFreezing) {
2731 w.mAppFreezing = false;
2732 if (w.mSurface != null && !w.mOrientationChanging) {
2733 w.mOrientationChanging = true;
2734 }
2735 unfrozeWindows = true;
2736 }
2737 }
2738 if (force || unfrozeWindows) {
2739 if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
2740 wtoken.freezingScreen = false;
2741 mAppsFreezingScreen--;
2742 }
2743 if (unfreezeSurfaceNow) {
2744 if (unfrozeWindows) {
2745 mLayoutNeeded = true;
2746 performLayoutAndPlaceSurfacesLocked();
2747 }
2748 if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
2749 stopFreezingDisplayLocked();
2750 }
2751 }
2752 }
2753 }
Romain Guy06882f82009-06-10 13:36:04 -07002754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755 public void startAppFreezingScreenLocked(AppWindowToken wtoken,
2756 int configChanges) {
2757 if (DEBUG_ORIENTATION) {
2758 RuntimeException e = new RuntimeException();
2759 e.fillInStackTrace();
2760 Log.i(TAG, "Set freezing of " + wtoken.appToken
2761 + ": hidden=" + wtoken.hidden + " freezing="
2762 + wtoken.freezingScreen, e);
2763 }
2764 if (!wtoken.hiddenRequested) {
2765 if (!wtoken.freezingScreen) {
2766 wtoken.freezingScreen = true;
2767 mAppsFreezingScreen++;
2768 if (mAppsFreezingScreen == 1) {
2769 startFreezingDisplayLocked();
2770 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
2771 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
2772 5000);
2773 }
2774 }
2775 final int N = wtoken.allAppWindows.size();
2776 for (int i=0; i<N; i++) {
2777 WindowState w = wtoken.allAppWindows.get(i);
2778 w.mAppFreezing = true;
2779 }
2780 }
2781 }
Romain Guy06882f82009-06-10 13:36:04 -07002782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 public void startAppFreezingScreen(IBinder token, int configChanges) {
2784 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2785 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002786 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002787 }
2788
2789 synchronized(mWindowMap) {
2790 if (configChanges == 0 && !mDisplayFrozen) {
2791 if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
2792 return;
2793 }
Romain Guy06882f82009-06-10 13:36:04 -07002794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 AppWindowToken wtoken = findAppWindowToken(token);
2796 if (wtoken == null || wtoken.appToken == null) {
2797 Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
2798 return;
2799 }
2800 final long origId = Binder.clearCallingIdentity();
2801 startAppFreezingScreenLocked(wtoken, configChanges);
2802 Binder.restoreCallingIdentity(origId);
2803 }
2804 }
Romain Guy06882f82009-06-10 13:36:04 -07002805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002806 public void stopAppFreezingScreen(IBinder token, boolean force) {
2807 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2808 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002809 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002810 }
2811
2812 synchronized(mWindowMap) {
2813 AppWindowToken wtoken = findAppWindowToken(token);
2814 if (wtoken == null || wtoken.appToken == null) {
2815 return;
2816 }
2817 final long origId = Binder.clearCallingIdentity();
2818 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
2819 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
2820 unsetAppFreezingScreenLocked(wtoken, true, force);
2821 Binder.restoreCallingIdentity(origId);
2822 }
2823 }
Romain Guy06882f82009-06-10 13:36:04 -07002824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002825 public void removeAppToken(IBinder token) {
2826 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2827 "removeAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002828 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829 }
2830
2831 AppWindowToken wtoken = null;
2832 AppWindowToken startingToken = null;
2833 boolean delayed = false;
2834
2835 final long origId = Binder.clearCallingIdentity();
2836 synchronized(mWindowMap) {
2837 WindowToken basewtoken = mTokenMap.remove(token);
2838 mTokenList.remove(basewtoken);
2839 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
2840 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
2841 delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
2842 wtoken.inPendingTransaction = false;
2843 mOpeningApps.remove(wtoken);
2844 if (mClosingApps.contains(wtoken)) {
2845 delayed = true;
2846 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2847 mClosingApps.add(wtoken);
2848 delayed = true;
2849 }
2850 if (DEBUG_APP_TRANSITIONS) Log.v(
2851 TAG, "Removing app " + wtoken + " delayed=" + delayed
2852 + " animation=" + wtoken.animation
2853 + " animating=" + wtoken.animating);
2854 if (delayed) {
2855 // set the token aside because it has an active animation to be finished
2856 mExitingAppTokens.add(wtoken);
2857 }
2858 mAppTokens.remove(wtoken);
2859 wtoken.removed = true;
2860 if (wtoken.startingData != null) {
2861 startingToken = wtoken;
2862 }
2863 unsetAppFreezingScreenLocked(wtoken, true, true);
2864 if (mFocusedApp == wtoken) {
2865 if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
2866 mFocusedApp = null;
2867 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2868 mKeyWaiter.tickle();
2869 }
2870 } else {
2871 Log.w(TAG, "Attempted to remove non-existing app token: " + token);
2872 }
Romain Guy06882f82009-06-10 13:36:04 -07002873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 if (!delayed && wtoken != null) {
2875 wtoken.updateReportedVisibilityLocked();
2876 }
2877 }
2878 Binder.restoreCallingIdentity(origId);
2879
2880 if (startingToken != null) {
2881 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
2882 + startingToken + ": app token removed");
2883 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
2884 mH.sendMessage(m);
2885 }
2886 }
2887
2888 private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
2889 final int NW = token.windows.size();
2890 for (int i=0; i<NW; i++) {
2891 WindowState win = token.windows.get(i);
2892 mWindows.remove(win);
2893 int j = win.mChildWindows.size();
2894 while (j > 0) {
2895 j--;
2896 mWindows.remove(win.mChildWindows.get(j));
2897 }
2898 }
2899 return NW > 0;
2900 }
2901
2902 void dumpAppTokensLocked() {
2903 for (int i=mAppTokens.size()-1; i>=0; i--) {
2904 Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
2905 }
2906 }
Romain Guy06882f82009-06-10 13:36:04 -07002907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 void dumpWindowsLocked() {
2909 for (int i=mWindows.size()-1; i>=0; i--) {
2910 Log.v(TAG, " #" + i + ": " + mWindows.get(i));
2911 }
2912 }
Romain Guy06882f82009-06-10 13:36:04 -07002913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002914 private int findWindowOffsetLocked(int tokenPos) {
2915 final int NW = mWindows.size();
2916
2917 if (tokenPos >= mAppTokens.size()) {
2918 int i = NW;
2919 while (i > 0) {
2920 i--;
2921 WindowState win = (WindowState)mWindows.get(i);
2922 if (win.getAppToken() != null) {
2923 return i+1;
2924 }
2925 }
2926 }
2927
2928 while (tokenPos > 0) {
2929 // Find the first app token below the new position that has
2930 // a window displayed.
2931 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
2932 if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
2933 + tokenPos + " -- " + wtoken.token);
2934 int i = wtoken.windows.size();
2935 while (i > 0) {
2936 i--;
2937 WindowState win = wtoken.windows.get(i);
2938 int j = win.mChildWindows.size();
2939 while (j > 0) {
2940 j--;
2941 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2942 if (cwin.mSubLayer >= 0 ) {
2943 for (int pos=NW-1; pos>=0; pos--) {
2944 if (mWindows.get(pos) == cwin) {
2945 if (DEBUG_REORDER) Log.v(TAG,
2946 "Found child win @" + (pos+1));
2947 return pos+1;
2948 }
2949 }
2950 }
2951 }
2952 for (int pos=NW-1; pos>=0; pos--) {
2953 if (mWindows.get(pos) == win) {
2954 if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
2955 return pos+1;
2956 }
2957 }
2958 }
2959 tokenPos--;
2960 }
2961
2962 return 0;
2963 }
2964
2965 private final int reAddWindowLocked(int index, WindowState win) {
2966 final int NCW = win.mChildWindows.size();
2967 boolean added = false;
2968 for (int j=0; j<NCW; j++) {
2969 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2970 if (!added && cwin.mSubLayer >= 0) {
2971 mWindows.add(index, win);
2972 index++;
2973 added = true;
2974 }
2975 mWindows.add(index, cwin);
2976 index++;
2977 }
2978 if (!added) {
2979 mWindows.add(index, win);
2980 index++;
2981 }
2982 return index;
2983 }
Romain Guy06882f82009-06-10 13:36:04 -07002984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 private final int reAddAppWindowsLocked(int index, WindowToken token) {
2986 final int NW = token.windows.size();
2987 for (int i=0; i<NW; i++) {
2988 index = reAddWindowLocked(index, token.windows.get(i));
2989 }
2990 return index;
2991 }
2992
2993 public void moveAppToken(int index, IBinder token) {
2994 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2995 "moveAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002996 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997 }
2998
2999 synchronized(mWindowMap) {
3000 if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
3001 if (DEBUG_REORDER) dumpAppTokensLocked();
3002 final AppWindowToken wtoken = findAppWindowToken(token);
3003 if (wtoken == null || !mAppTokens.remove(wtoken)) {
3004 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
3005 + token + " (" + wtoken + ")");
3006 return;
3007 }
3008 mAppTokens.add(index, wtoken);
3009 if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
3010 if (DEBUG_REORDER) dumpAppTokensLocked();
Romain Guy06882f82009-06-10 13:36:04 -07003011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003012 final long origId = Binder.clearCallingIdentity();
3013 if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
3014 if (DEBUG_REORDER) dumpWindowsLocked();
3015 if (tmpRemoveAppWindowsLocked(wtoken)) {
3016 if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:");
3017 if (DEBUG_REORDER) dumpWindowsLocked();
3018 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
3019 if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
3020 if (DEBUG_REORDER) dumpWindowsLocked();
3021 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003022 mLayoutNeeded = true;
3023 performLayoutAndPlaceSurfacesLocked();
3024 }
3025 Binder.restoreCallingIdentity(origId);
3026 }
3027 }
3028
3029 private void removeAppTokensLocked(List<IBinder> tokens) {
3030 // XXX This should be done more efficiently!
3031 // (take advantage of the fact that both lists should be
3032 // ordered in the same way.)
3033 int N = tokens.size();
3034 for (int i=0; i<N; i++) {
3035 IBinder token = tokens.get(i);
3036 final AppWindowToken wtoken = findAppWindowToken(token);
3037 if (!mAppTokens.remove(wtoken)) {
3038 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
3039 + token + " (" + wtoken + ")");
3040 i--;
3041 N--;
3042 }
3043 }
3044 }
3045
3046 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
3047 // First remove all of the windows from the list.
3048 final int N = tokens.size();
3049 int i;
3050 for (i=0; i<N; i++) {
3051 WindowToken token = mTokenMap.get(tokens.get(i));
3052 if (token != null) {
3053 tmpRemoveAppWindowsLocked(token);
3054 }
3055 }
3056
3057 // Where to start adding?
3058 int pos = findWindowOffsetLocked(tokenPos);
3059
3060 // And now add them back at the correct place.
3061 for (i=0; i<N; i++) {
3062 WindowToken token = mTokenMap.get(tokens.get(i));
3063 if (token != null) {
3064 pos = reAddAppWindowsLocked(pos, token);
3065 }
3066 }
3067
3068 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 mLayoutNeeded = true;
3070 performLayoutAndPlaceSurfacesLocked();
3071
3072 //dump();
3073 }
3074
3075 public void moveAppTokensToTop(List<IBinder> tokens) {
3076 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3077 "moveAppTokensToTop()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003078 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 }
3080
3081 final long origId = Binder.clearCallingIdentity();
3082 synchronized(mWindowMap) {
3083 removeAppTokensLocked(tokens);
3084 final int N = tokens.size();
3085 for (int i=0; i<N; i++) {
3086 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3087 if (wt != null) {
3088 mAppTokens.add(wt);
3089 }
3090 }
3091 moveAppWindowsLocked(tokens, mAppTokens.size());
3092 }
3093 Binder.restoreCallingIdentity(origId);
3094 }
3095
3096 public void moveAppTokensToBottom(List<IBinder> tokens) {
3097 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3098 "moveAppTokensToBottom()")) {
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 final long origId = Binder.clearCallingIdentity();
3103 synchronized(mWindowMap) {
3104 removeAppTokensLocked(tokens);
3105 final int N = tokens.size();
3106 int pos = 0;
3107 for (int i=0; i<N; i++) {
3108 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3109 if (wt != null) {
3110 mAppTokens.add(pos, wt);
3111 pos++;
3112 }
3113 }
3114 moveAppWindowsLocked(tokens, 0);
3115 }
3116 Binder.restoreCallingIdentity(origId);
3117 }
3118
3119 // -------------------------------------------------------------
3120 // Misc IWindowSession methods
3121 // -------------------------------------------------------------
Romain Guy06882f82009-06-10 13:36:04 -07003122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 public void disableKeyguard(IBinder token, String tag) {
3124 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3125 != PackageManager.PERMISSION_GRANTED) {
3126 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3127 }
3128 mKeyguardDisabled.acquire(token, tag);
3129 }
3130
3131 public void reenableKeyguard(IBinder token) {
3132 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3133 != PackageManager.PERMISSION_GRANTED) {
3134 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3135 }
3136 synchronized (mKeyguardDisabled) {
3137 mKeyguardDisabled.release(token);
3138
3139 if (!mKeyguardDisabled.isAcquired()) {
3140 // if we are the last one to reenable the keyguard wait until
3141 // we have actaully finished reenabling until returning
3142 mWaitingUntilKeyguardReenabled = true;
3143 while (mWaitingUntilKeyguardReenabled) {
3144 try {
3145 mKeyguardDisabled.wait();
3146 } catch (InterruptedException e) {
3147 Thread.currentThread().interrupt();
3148 }
3149 }
3150 }
3151 }
3152 }
3153
3154 /**
3155 * @see android.app.KeyguardManager#exitKeyguardSecurely
3156 */
3157 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
3158 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3159 != PackageManager.PERMISSION_GRANTED) {
3160 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3161 }
3162 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
3163 public void onKeyguardExitResult(boolean success) {
3164 try {
3165 callback.onKeyguardExitResult(success);
3166 } catch (RemoteException e) {
3167 // Client has died, we don't care.
3168 }
3169 }
3170 });
3171 }
3172
3173 public boolean inKeyguardRestrictedInputMode() {
3174 return mPolicy.inKeyguardRestrictedKeyInputMode();
3175 }
Romain Guy06882f82009-06-10 13:36:04 -07003176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 static float fixScale(float scale) {
3178 if (scale < 0) scale = 0;
3179 else if (scale > 20) scale = 20;
3180 return Math.abs(scale);
3181 }
Romain Guy06882f82009-06-10 13:36:04 -07003182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 public void setAnimationScale(int which, float scale) {
3184 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3185 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003186 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 }
3188
3189 if (scale < 0) scale = 0;
3190 else if (scale > 20) scale = 20;
3191 scale = Math.abs(scale);
3192 switch (which) {
3193 case 0: mWindowAnimationScale = fixScale(scale); break;
3194 case 1: mTransitionAnimationScale = fixScale(scale); break;
3195 }
Romain Guy06882f82009-06-10 13:36:04 -07003196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 // Persist setting
3198 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3199 }
Romain Guy06882f82009-06-10 13:36:04 -07003200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 public void setAnimationScales(float[] scales) {
3202 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3203 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003204 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205 }
3206
3207 if (scales != null) {
3208 if (scales.length >= 1) {
3209 mWindowAnimationScale = fixScale(scales[0]);
3210 }
3211 if (scales.length >= 2) {
3212 mTransitionAnimationScale = fixScale(scales[1]);
3213 }
3214 }
Romain Guy06882f82009-06-10 13:36:04 -07003215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 // Persist setting
3217 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3218 }
Romain Guy06882f82009-06-10 13:36:04 -07003219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 public float getAnimationScale(int which) {
3221 switch (which) {
3222 case 0: return mWindowAnimationScale;
3223 case 1: return mTransitionAnimationScale;
3224 }
3225 return 0;
3226 }
Romain Guy06882f82009-06-10 13:36:04 -07003227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 public float[] getAnimationScales() {
3229 return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
3230 }
Romain Guy06882f82009-06-10 13:36:04 -07003231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 public int getSwitchState(int sw) {
3233 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3234 "getSwitchState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003235 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 }
3237 return KeyInputQueue.getSwitchState(sw);
3238 }
Romain Guy06882f82009-06-10 13:36:04 -07003239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 public int getSwitchStateForDevice(int devid, int sw) {
3241 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3242 "getSwitchStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003243 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 }
3245 return KeyInputQueue.getSwitchState(devid, sw);
3246 }
Romain Guy06882f82009-06-10 13:36:04 -07003247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 public int getScancodeState(int sw) {
3249 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3250 "getScancodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003251 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 }
3253 return KeyInputQueue.getScancodeState(sw);
3254 }
Romain Guy06882f82009-06-10 13:36:04 -07003255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 public int getScancodeStateForDevice(int devid, int sw) {
3257 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3258 "getScancodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003259 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 }
3261 return KeyInputQueue.getScancodeState(devid, sw);
3262 }
Romain Guy06882f82009-06-10 13:36:04 -07003263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 public int getKeycodeState(int sw) {
3265 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3266 "getKeycodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003267 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003268 }
3269 return KeyInputQueue.getKeycodeState(sw);
3270 }
Romain Guy06882f82009-06-10 13:36:04 -07003271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 public int getKeycodeStateForDevice(int devid, int sw) {
3273 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3274 "getKeycodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003275 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003276 }
3277 return KeyInputQueue.getKeycodeState(devid, sw);
3278 }
Romain Guy06882f82009-06-10 13:36:04 -07003279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
3281 return KeyInputQueue.hasKeys(keycodes, keyExists);
3282 }
Romain Guy06882f82009-06-10 13:36:04 -07003283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 public void enableScreenAfterBoot() {
3285 synchronized(mWindowMap) {
3286 if (mSystemBooted) {
3287 return;
3288 }
3289 mSystemBooted = true;
3290 }
Romain Guy06882f82009-06-10 13:36:04 -07003291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292 performEnableScreen();
3293 }
Romain Guy06882f82009-06-10 13:36:04 -07003294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 public void enableScreenIfNeededLocked() {
3296 if (mDisplayEnabled) {
3297 return;
3298 }
3299 if (!mSystemBooted) {
3300 return;
3301 }
3302 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
3303 }
Romain Guy06882f82009-06-10 13:36:04 -07003304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305 public void performEnableScreen() {
3306 synchronized(mWindowMap) {
3307 if (mDisplayEnabled) {
3308 return;
3309 }
3310 if (!mSystemBooted) {
3311 return;
3312 }
Romain Guy06882f82009-06-10 13:36:04 -07003313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003314 // Don't enable the screen until all existing windows
3315 // have been drawn.
3316 final int N = mWindows.size();
3317 for (int i=0; i<N; i++) {
3318 WindowState w = (WindowState)mWindows.get(i);
3319 if (w.isVisibleLw() && !w.isDisplayedLw()) {
3320 return;
3321 }
3322 }
Romain Guy06882f82009-06-10 13:36:04 -07003323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 mDisplayEnabled = true;
3325 if (false) {
3326 Log.i(TAG, "ENABLING SCREEN!");
3327 StringWriter sw = new StringWriter();
3328 PrintWriter pw = new PrintWriter(sw);
3329 this.dump(null, pw, null);
3330 Log.i(TAG, sw.toString());
3331 }
3332 try {
3333 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
3334 if (surfaceFlinger != null) {
3335 //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
3336 Parcel data = Parcel.obtain();
3337 data.writeInterfaceToken("android.ui.ISurfaceComposer");
3338 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
3339 data, null, 0);
3340 data.recycle();
3341 }
3342 } catch (RemoteException ex) {
3343 Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
3344 }
3345 }
Romain Guy06882f82009-06-10 13:36:04 -07003346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 mPolicy.enableScreenAfterBoot();
Romain Guy06882f82009-06-10 13:36:04 -07003348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349 // Make sure the last requested orientation has been applied.
Dianne Hackborn321ae682009-03-27 16:16:03 -07003350 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
3351 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 }
Romain Guy06882f82009-06-10 13:36:04 -07003353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003354 public void setInTouchMode(boolean mode) {
3355 synchronized(mWindowMap) {
3356 mInTouchMode = mode;
3357 }
3358 }
3359
Romain Guy06882f82009-06-10 13:36:04 -07003360 public void setRotation(int rotation,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003361 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003363 "setRotation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003364 throw new SecurityException("Requires SET_ORIENTATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 }
3366
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003367 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 }
Romain Guy06882f82009-06-10 13:36:04 -07003369
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003370 public void setRotationUnchecked(int rotation,
3371 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 if(DEBUG_ORIENTATION) Log.v(TAG,
3373 "alwaysSendConfiguration set to "+alwaysSendConfiguration);
Romain Guy06882f82009-06-10 13:36:04 -07003374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 long origId = Binder.clearCallingIdentity();
3376 boolean changed;
3377 synchronized(mWindowMap) {
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003378 changed = setRotationUncheckedLocked(rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003379 }
Romain Guy06882f82009-06-10 13:36:04 -07003380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 if (changed) {
3382 sendNewConfiguration();
3383 synchronized(mWindowMap) {
3384 mLayoutNeeded = true;
3385 performLayoutAndPlaceSurfacesLocked();
3386 }
3387 } else if (alwaysSendConfiguration) {
3388 //update configuration ignoring orientation change
3389 sendNewConfiguration();
3390 }
Romain Guy06882f82009-06-10 13:36:04 -07003391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 Binder.restoreCallingIdentity(origId);
3393 }
Romain Guy06882f82009-06-10 13:36:04 -07003394
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003395 public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 boolean changed;
3397 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
3398 rotation = mRequestedRotation;
3399 } else {
3400 mRequestedRotation = rotation;
Dianne Hackborn321ae682009-03-27 16:16:03 -07003401 mLastRotationFlags = animFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 }
3403 if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07003404 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 mRotation, mDisplayEnabled);
3406 if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
3407 changed = mDisplayEnabled && mRotation != rotation;
Romain Guy06882f82009-06-10 13:36:04 -07003408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003409 if (changed) {
Romain Guy06882f82009-06-10 13:36:04 -07003410 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 "Rotation changed to " + rotation
3412 + " from " + mRotation
3413 + " (forceApp=" + mForcedAppOrientation
3414 + ", req=" + mRequestedRotation + ")");
3415 mRotation = rotation;
3416 mWindowsFreezingScreen = true;
3417 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
3418 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
3419 2000);
3420 startFreezingDisplayLocked();
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003421 Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003422 mQueue.setOrientation(rotation);
3423 if (mDisplayEnabled) {
Dianne Hackborn321ae682009-03-27 16:16:03 -07003424 Surface.setOrientation(0, rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003425 }
3426 for (int i=mWindows.size()-1; i>=0; i--) {
3427 WindowState w = (WindowState)mWindows.get(i);
3428 if (w.mSurface != null) {
3429 w.mOrientationChanging = true;
3430 }
3431 }
3432 for (int i=mRotationWatchers.size()-1; i>=0; i--) {
3433 try {
3434 mRotationWatchers.get(i).onRotationChanged(rotation);
3435 } catch (RemoteException e) {
3436 }
3437 }
3438 } //end if changed
Romain Guy06882f82009-06-10 13:36:04 -07003439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 return changed;
3441 }
Romain Guy06882f82009-06-10 13:36:04 -07003442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 public int getRotation() {
3444 return mRotation;
3445 }
3446
3447 public int watchRotation(IRotationWatcher watcher) {
3448 final IBinder watcherBinder = watcher.asBinder();
3449 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
3450 public void binderDied() {
3451 synchronized (mWindowMap) {
3452 for (int i=0; i<mRotationWatchers.size(); i++) {
3453 if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07003454 IRotationWatcher removed = mRotationWatchers.remove(i);
3455 if (removed != null) {
3456 removed.asBinder().unlinkToDeath(this, 0);
3457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 i--;
3459 }
3460 }
3461 }
3462 }
3463 };
Romain Guy06882f82009-06-10 13:36:04 -07003464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003465 synchronized (mWindowMap) {
3466 try {
3467 watcher.asBinder().linkToDeath(dr, 0);
3468 mRotationWatchers.add(watcher);
3469 } catch (RemoteException e) {
3470 // Client died, no cleanup needed.
3471 }
Romain Guy06882f82009-06-10 13:36:04 -07003472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 return mRotation;
3474 }
3475 }
3476
3477 /**
3478 * Starts the view server on the specified port.
3479 *
3480 * @param port The port to listener to.
3481 *
3482 * @return True if the server was successfully started, false otherwise.
3483 *
3484 * @see com.android.server.ViewServer
3485 * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
3486 */
3487 public boolean startViewServer(int port) {
Romain Guy06882f82009-06-10 13:36:04 -07003488 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 return false;
3490 }
3491
3492 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
3493 return false;
3494 }
3495
3496 if (port < 1024) {
3497 return false;
3498 }
3499
3500 if (mViewServer != null) {
3501 if (!mViewServer.isRunning()) {
3502 try {
3503 return mViewServer.start();
3504 } catch (IOException e) {
Romain Guy06882f82009-06-10 13:36:04 -07003505 Log.w(TAG, "View server did not start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 }
3507 }
3508 return false;
3509 }
3510
3511 try {
3512 mViewServer = new ViewServer(this, port);
3513 return mViewServer.start();
3514 } catch (IOException e) {
3515 Log.w(TAG, "View server did not start");
3516 }
3517 return false;
3518 }
3519
Romain Guy06882f82009-06-10 13:36:04 -07003520 private boolean isSystemSecure() {
3521 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
3522 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
3523 }
3524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 /**
3526 * Stops the view server if it exists.
3527 *
3528 * @return True if the server stopped, false if it wasn't started or
3529 * couldn't be stopped.
3530 *
3531 * @see com.android.server.ViewServer
3532 */
3533 public boolean stopViewServer() {
Romain Guy06882f82009-06-10 13:36:04 -07003534 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 return false;
3536 }
3537
3538 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
3539 return false;
3540 }
3541
3542 if (mViewServer != null) {
3543 return mViewServer.stop();
3544 }
3545 return false;
3546 }
3547
3548 /**
3549 * Indicates whether the view server is running.
3550 *
3551 * @return True if the server is running, false otherwise.
3552 *
3553 * @see com.android.server.ViewServer
3554 */
3555 public boolean isViewServerRunning() {
Romain Guy06882f82009-06-10 13:36:04 -07003556 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003557 return false;
3558 }
3559
3560 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
3561 return false;
3562 }
3563
3564 return mViewServer != null && mViewServer.isRunning();
3565 }
3566
3567 /**
3568 * Lists all availble windows in the system. The listing is written in the
3569 * specified Socket's output stream with the following syntax:
3570 * windowHashCodeInHexadecimal windowName
3571 * Each line of the ouput represents a different window.
3572 *
3573 * @param client The remote client to send the listing to.
3574 * @return False if an error occured, true otherwise.
3575 */
3576 boolean viewServerListWindows(Socket client) {
Romain Guy06882f82009-06-10 13:36:04 -07003577 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 return false;
3579 }
3580
3581 boolean result = true;
3582
3583 Object[] windows;
3584 synchronized (mWindowMap) {
3585 windows = new Object[mWindows.size()];
3586 //noinspection unchecked
3587 windows = mWindows.toArray(windows);
3588 }
3589
3590 BufferedWriter out = null;
3591
3592 // Any uncaught exception will crash the system process
3593 try {
3594 OutputStream clientStream = client.getOutputStream();
3595 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
3596
3597 final int count = windows.length;
3598 for (int i = 0; i < count; i++) {
3599 final WindowState w = (WindowState) windows[i];
3600 out.write(Integer.toHexString(System.identityHashCode(w)));
3601 out.write(' ');
3602 out.append(w.mAttrs.getTitle());
3603 out.write('\n');
3604 }
3605
3606 out.write("DONE.\n");
3607 out.flush();
3608 } catch (Exception e) {
3609 result = false;
3610 } finally {
3611 if (out != null) {
3612 try {
3613 out.close();
3614 } catch (IOException e) {
3615 result = false;
3616 }
3617 }
3618 }
3619
3620 return result;
3621 }
3622
3623 /**
3624 * Sends a command to a target window. The result of the command, if any, will be
3625 * written in the output stream of the specified socket.
3626 *
3627 * The parameters must follow this syntax:
3628 * windowHashcode extra
3629 *
3630 * Where XX is the length in characeters of the windowTitle.
3631 *
3632 * The first parameter is the target window. The window with the specified hashcode
3633 * will be the target. If no target can be found, nothing happens. The extra parameters
3634 * will be delivered to the target window and as parameters to the command itself.
3635 *
3636 * @param client The remote client to sent the result, if any, to.
3637 * @param command The command to execute.
3638 * @param parameters The command parameters.
3639 *
3640 * @return True if the command was successfully delivered, false otherwise. This does
3641 * not indicate whether the command itself was successful.
3642 */
3643 boolean viewServerWindowCommand(Socket client, String command, String parameters) {
Romain Guy06882f82009-06-10 13:36:04 -07003644 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003645 return false;
3646 }
3647
3648 boolean success = true;
3649 Parcel data = null;
3650 Parcel reply = null;
3651
3652 // Any uncaught exception will crash the system process
3653 try {
3654 // Find the hashcode of the window
3655 int index = parameters.indexOf(' ');
3656 if (index == -1) {
3657 index = parameters.length();
3658 }
3659 final String code = parameters.substring(0, index);
3660 int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
3661
3662 // Extract the command's parameter after the window description
3663 if (index < parameters.length()) {
3664 parameters = parameters.substring(index + 1);
3665 } else {
3666 parameters = "";
3667 }
3668
3669 final WindowManagerService.WindowState window = findWindow(hashCode);
3670 if (window == null) {
3671 return false;
3672 }
3673
3674 data = Parcel.obtain();
3675 data.writeInterfaceToken("android.view.IWindow");
3676 data.writeString(command);
3677 data.writeString(parameters);
3678 data.writeInt(1);
3679 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
3680
3681 reply = Parcel.obtain();
3682
3683 final IBinder binder = window.mClient.asBinder();
3684 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
3685 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
3686
3687 reply.readException();
3688
3689 } catch (Exception e) {
3690 Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
3691 success = false;
3692 } finally {
3693 if (data != null) {
3694 data.recycle();
3695 }
3696 if (reply != null) {
3697 reply.recycle();
3698 }
3699 }
3700
3701 return success;
3702 }
3703
3704 private WindowState findWindow(int hashCode) {
3705 if (hashCode == -1) {
3706 return getFocusedWindow();
3707 }
3708
3709 synchronized (mWindowMap) {
3710 final ArrayList windows = mWindows;
3711 final int count = windows.size();
3712
3713 for (int i = 0; i < count; i++) {
3714 WindowState w = (WindowState) windows.get(i);
3715 if (System.identityHashCode(w) == hashCode) {
3716 return w;
3717 }
3718 }
3719 }
3720
3721 return null;
3722 }
3723
3724 /*
3725 * Instruct the Activity Manager to fetch the current configuration and broadcast
3726 * that to config-changed listeners if appropriate.
3727 */
3728 void sendNewConfiguration() {
3729 try {
3730 mActivityManager.updateConfiguration(null);
3731 } catch (RemoteException e) {
3732 }
3733 }
Romain Guy06882f82009-06-10 13:36:04 -07003734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003735 public Configuration computeNewConfiguration() {
3736 synchronized (mWindowMap) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07003737 return computeNewConfigurationLocked();
3738 }
3739 }
Romain Guy06882f82009-06-10 13:36:04 -07003740
Dianne Hackbornc485a602009-03-24 22:39:49 -07003741 Configuration computeNewConfigurationLocked() {
3742 Configuration config = new Configuration();
3743 if (!computeNewConfigurationLocked(config)) {
3744 return null;
3745 }
3746 Log.i(TAG, "Config changed: " + config);
3747 long now = SystemClock.uptimeMillis();
3748 //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
3749 if (mFreezeGcPending != 0) {
3750 if (now > (mFreezeGcPending+1000)) {
3751 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
3752 mH.removeMessages(H.FORCE_GC);
3753 Runtime.getRuntime().gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 mFreezeGcPending = now;
3755 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003756 } else {
3757 mFreezeGcPending = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003758 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003759 return config;
3760 }
Romain Guy06882f82009-06-10 13:36:04 -07003761
Dianne Hackbornc485a602009-03-24 22:39:49 -07003762 boolean computeNewConfigurationLocked(Configuration config) {
3763 if (mDisplay == null) {
3764 return false;
3765 }
3766 mQueue.getInputConfiguration(config);
3767 final int dw = mDisplay.getWidth();
3768 final int dh = mDisplay.getHeight();
3769 int orientation = Configuration.ORIENTATION_SQUARE;
3770 if (dw < dh) {
3771 orientation = Configuration.ORIENTATION_PORTRAIT;
3772 } else if (dw > dh) {
3773 orientation = Configuration.ORIENTATION_LANDSCAPE;
3774 }
3775 config.orientation = orientation;
Dianne Hackborn723738c2009-06-25 19:48:04 -07003776
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07003777 DisplayMetrics dm = new DisplayMetrics();
3778 mDisplay.getMetrics(dm);
3779 CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
3780
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07003781 if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
Dianne Hackborn723738c2009-06-25 19:48:04 -07003782 // Note we only do this once because at this point we don't
3783 // expect the screen to change in this way at runtime, and want
3784 // to avoid all of this computation for every config change.
Dianne Hackborn723738c2009-06-25 19:48:04 -07003785 int longSize = dw;
3786 int shortSize = dh;
3787 if (longSize < shortSize) {
3788 int tmp = longSize;
3789 longSize = shortSize;
3790 shortSize = tmp;
3791 }
3792 longSize = (int)(longSize/dm.density);
3793 shortSize = (int)(shortSize/dm.density);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07003794
Dianne Hackborn723738c2009-06-25 19:48:04 -07003795 // These semi-magic numbers define our compatibility modes for
3796 // applications with different screens. Don't change unless you
3797 // make sure to test lots and lots of apps!
3798 if (longSize < 470) {
3799 // This is shorter than an HVGA normal density screen (which
3800 // is 480 pixels on its long side).
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07003801 mScreenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
3802 | Configuration.SCREENLAYOUT_LONG_NO;
Dianne Hackborn723738c2009-06-25 19:48:04 -07003803 } else {
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07003804 // Is this a large screen?
3805 if (longSize > 640 && shortSize >= 480) {
3806 // VGA or larger screens at medium density are the point
3807 // at which we consider it to be a large screen.
3808 mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
3809 } else {
3810 mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
3811
3812 // If this screen is wider than normal HVGA, or taller
3813 // than FWVGA, then for old apps we want to run in size
3814 // compatibility mode.
3815 if (shortSize > 321 || longSize > 570) {
3816 mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
3817 }
3818 }
3819
3820 // Is this a long screen?
3821 if (((longSize*3)/5) >= (shortSize-1)) {
3822 // Anything wider than WVGA (5:3) is considering to be long.
3823 mScreenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
3824 } else {
3825 mScreenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
3826 }
Dianne Hackborn723738c2009-06-25 19:48:04 -07003827 }
3828 }
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07003829 config.screenLayout = mScreenLayout;
Dianne Hackborn723738c2009-06-25 19:48:04 -07003830
Dianne Hackbornc485a602009-03-24 22:39:49 -07003831 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
3832 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
3833 mPolicy.adjustConfigurationLw(config);
3834 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003835 }
Romain Guy06882f82009-06-10 13:36:04 -07003836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 // -------------------------------------------------------------
3838 // Input Events and Focus Management
3839 // -------------------------------------------------------------
3840
3841 private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
Michael Chane96440f2009-05-06 10:27:36 -07003842 long curTime = SystemClock.uptimeMillis();
3843
Michael Chane10de972009-05-18 11:24:50 -07003844 if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
Michael Chane96440f2009-05-06 10:27:36 -07003845 if (mLastTouchEventType == eventType &&
3846 (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
3847 return;
3848 }
3849 mLastUserActivityCallTime = curTime;
3850 mLastTouchEventType = eventType;
3851 }
3852
3853 if (targetWin == null
3854 || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
3855 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003856 }
3857 }
3858
3859 // tells if it's a cheek event or not -- this function is stateful
3860 private static final int EVENT_NONE = 0;
3861 private static final int EVENT_UNKNOWN = 0;
3862 private static final int EVENT_CHEEK = 0;
3863 private static final int EVENT_IGNORE_DURATION = 300; // ms
3864 private static final float CHEEK_THRESHOLD = 0.6f;
3865 private int mEventState = EVENT_NONE;
3866 private float mEventSize;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003868 private int eventType(MotionEvent ev) {
3869 float size = ev.getSize();
3870 switch (ev.getAction()) {
3871 case MotionEvent.ACTION_DOWN:
3872 mEventSize = size;
3873 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
3874 case MotionEvent.ACTION_UP:
3875 if (size > mEventSize) mEventSize = size;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003876 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003877 case MotionEvent.ACTION_MOVE:
3878 final int N = ev.getHistorySize();
3879 if (size > mEventSize) mEventSize = size;
3880 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3881 for (int i=0; i<N; i++) {
3882 size = ev.getHistoricalSize(i);
3883 if (size > mEventSize) mEventSize = size;
3884 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3885 }
3886 if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
3887 return TOUCH_EVENT;
3888 } else {
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003889 return LONG_TOUCH_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 }
3891 default:
3892 // not good
3893 return OTHER_EVENT;
3894 }
3895 }
3896
3897 /**
3898 * @return Returns true if event was dispatched, false if it was dropped for any reason
3899 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07003900 private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901 if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
3902 "dispatchPointer " + ev);
3903
Michael Chan53071d62009-05-13 17:29:48 -07003904 if (MEASURE_LATENCY) {
3905 lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
3906 }
3907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003908 Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07003909 ev, true, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003910
Michael Chan53071d62009-05-13 17:29:48 -07003911 if (MEASURE_LATENCY) {
3912 lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
3913 }
3914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003915 int action = ev.getAction();
Romain Guy06882f82009-06-10 13:36:04 -07003916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003917 if (action == MotionEvent.ACTION_UP) {
3918 // let go of our target
3919 mKeyWaiter.mMotionTarget = null;
3920 mPowerManager.logPointerUpEvent();
3921 } else if (action == MotionEvent.ACTION_DOWN) {
3922 mPowerManager.logPointerDownEvent();
3923 }
3924
3925 if (targetObj == null) {
3926 // In this case we are either dropping the event, or have received
3927 // a move or up without a down. It is common to receive move
3928 // events in such a way, since this means the user is moving the
3929 // pointer without actually pressing down. All other cases should
3930 // be atypical, so let's log them.
Michael Chane96440f2009-05-06 10:27:36 -07003931 if (action != MotionEvent.ACTION_MOVE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003932 Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
3933 }
3934 if (qev != null) {
3935 mQueue.recycleEvent(qev);
3936 }
3937 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003938 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003939 }
3940 if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3941 if (qev != null) {
3942 mQueue.recycleEvent(qev);
3943 }
3944 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003945 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003946 }
Romain Guy06882f82009-06-10 13:36:04 -07003947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003948 WindowState target = (WindowState)targetObj;
Romain Guy06882f82009-06-10 13:36:04 -07003949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003950 final long eventTime = ev.getEventTime();
Michael Chan53071d62009-05-13 17:29:48 -07003951 final long eventTimeNano = ev.getEventTimeNano();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003952
3953 //Log.i(TAG, "Sending " + ev + " to " + target);
3954
3955 if (uid != 0 && uid != target.mSession.mUid) {
3956 if (mContext.checkPermission(
3957 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3958 != PackageManager.PERMISSION_GRANTED) {
3959 Log.w(TAG, "Permission denied: injecting pointer event from pid "
3960 + pid + " uid " + uid + " to window " + target
3961 + " owned by uid " + target.mSession.mUid);
3962 if (qev != null) {
3963 mQueue.recycleEvent(qev);
3964 }
3965 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003966 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003967 }
3968 }
3969
Michael Chan53071d62009-05-13 17:29:48 -07003970 if (MEASURE_LATENCY) {
3971 lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
3972 }
3973
Romain Guy06882f82009-06-10 13:36:04 -07003974 if ((target.mAttrs.flags &
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003975 WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
3976 //target wants to ignore fat touch events
3977 boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
3978 //explicit flag to return without processing event further
3979 boolean returnFlag = false;
3980 if((action == MotionEvent.ACTION_DOWN)) {
3981 mFatTouch = false;
3982 if(cheekPress) {
3983 mFatTouch = true;
3984 returnFlag = true;
3985 }
3986 } else {
3987 if(action == MotionEvent.ACTION_UP) {
3988 if(mFatTouch) {
3989 //earlier even was invalid doesnt matter if current up is cheekpress or not
3990 mFatTouch = false;
3991 returnFlag = true;
3992 } else if(cheekPress) {
3993 //cancel the earlier event
3994 ev.setAction(MotionEvent.ACTION_CANCEL);
3995 action = MotionEvent.ACTION_CANCEL;
3996 }
3997 } else if(action == MotionEvent.ACTION_MOVE) {
3998 if(mFatTouch) {
3999 //two cases here
4000 //an invalid down followed by 0 or moves(valid or invalid)
Romain Guy06882f82009-06-10 13:36:04 -07004001 //a valid down, invalid move, more moves. want to ignore till up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002 returnFlag = true;
4003 } else if(cheekPress) {
4004 //valid down followed by invalid moves
4005 //an invalid move have to cancel earlier action
4006 ev.setAction(MotionEvent.ACTION_CANCEL);
4007 action = MotionEvent.ACTION_CANCEL;
4008 if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE");
4009 //note that the subsequent invalid moves will not get here
4010 mFatTouch = true;
4011 }
4012 }
4013 } //else if action
4014 if(returnFlag) {
4015 //recycle que, ev
4016 if (qev != null) {
4017 mQueue.recycleEvent(qev);
4018 }
4019 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004020 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004021 }
4022 } //end if target
Michael Chane96440f2009-05-06 10:27:36 -07004023
Michael Chan9f028e62009-08-04 17:37:46 -07004024 // Enable this for testing the "right" value
4025 if (false && action == MotionEvent.ACTION_DOWN) {
Michael Chane96440f2009-05-06 10:27:36 -07004026 int max_events_per_sec = 35;
4027 try {
4028 max_events_per_sec = Integer.parseInt(SystemProperties
4029 .get("windowsmgr.max_events_per_sec"));
4030 if (max_events_per_sec < 1) {
4031 max_events_per_sec = 35;
4032 }
4033 } catch (NumberFormatException e) {
4034 }
4035 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
4036 }
4037
4038 /*
4039 * Throttle events to minimize CPU usage when there's a flood of events
4040 * e.g. constant contact with the screen
4041 */
4042 if (action == MotionEvent.ACTION_MOVE) {
4043 long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
4044 long now = SystemClock.uptimeMillis();
4045 if (now < nextEventTime) {
4046 try {
4047 Thread.sleep(nextEventTime - now);
4048 } catch (InterruptedException e) {
4049 }
4050 mLastTouchEventTime = nextEventTime;
4051 } else {
4052 mLastTouchEventTime = now;
4053 }
4054 }
4055
Michael Chan53071d62009-05-13 17:29:48 -07004056 if (MEASURE_LATENCY) {
4057 lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano);
4058 }
4059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004060 synchronized(mWindowMap) {
4061 if (qev != null && action == MotionEvent.ACTION_MOVE) {
4062 mKeyWaiter.bindTargetWindowLocked(target,
4063 KeyWaiter.RETURN_PENDING_POINTER, qev);
4064 ev = null;
4065 } else {
4066 if (action == MotionEvent.ACTION_DOWN) {
4067 WindowState out = mKeyWaiter.mOutsideTouchTargets;
4068 if (out != null) {
4069 MotionEvent oev = MotionEvent.obtain(ev);
4070 oev.setAction(MotionEvent.ACTION_OUTSIDE);
4071 do {
4072 final Rect frame = out.mFrame;
4073 oev.offsetLocation(-(float)frame.left, -(float)frame.top);
4074 try {
4075 out.mClient.dispatchPointer(oev, eventTime);
4076 } catch (android.os.RemoteException e) {
4077 Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
4078 }
4079 oev.offsetLocation((float)frame.left, (float)frame.top);
4080 out = out.mNextOutsideTouch;
4081 } while (out != null);
4082 mKeyWaiter.mOutsideTouchTargets = null;
4083 }
4084 }
4085 final Rect frame = target.mFrame;
4086 ev.offsetLocation(-(float)frame.left, -(float)frame.top);
4087 mKeyWaiter.bindTargetWindowLocked(target);
4088 }
4089 }
Romain Guy06882f82009-06-10 13:36:04 -07004090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 // finally offset the event to the target's coordinate system and
4092 // dispatch the event.
4093 try {
4094 if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
4095 Log.v(TAG, "Delivering pointer " + qev + " to " + target);
4096 }
Michael Chan53071d62009-05-13 17:29:48 -07004097
4098 if (MEASURE_LATENCY) {
4099 lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
4100 }
4101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004102 target.mClient.dispatchPointer(ev, eventTime);
Michael Chan53071d62009-05-13 17:29:48 -07004103
4104 if (MEASURE_LATENCY) {
4105 lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
4106 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004107 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 } catch (android.os.RemoteException e) {
4109 Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
4110 mKeyWaiter.mMotionTarget = null;
4111 try {
4112 removeWindow(target.mSession, target.mClient);
4113 } catch (java.util.NoSuchElementException ex) {
4114 // This will happen if the window has already been
4115 // removed.
4116 }
4117 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004118 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004119 }
Romain Guy06882f82009-06-10 13:36:04 -07004120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004121 /**
4122 * @return Returns true if event was dispatched, false if it was dropped for any reason
4123 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004124 private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 if (DEBUG_INPUT) Log.v(
4126 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
Romain Guy06882f82009-06-10 13:36:04 -07004127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128 Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004129 ev, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004130 if (focusObj == null) {
4131 Log.w(TAG, "No focus window, dropping trackball: " + ev);
4132 if (qev != null) {
4133 mQueue.recycleEvent(qev);
4134 }
4135 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004136 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004137 }
4138 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
4139 if (qev != null) {
4140 mQueue.recycleEvent(qev);
4141 }
4142 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004143 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004144 }
Romain Guy06882f82009-06-10 13:36:04 -07004145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004146 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004148 if (uid != 0 && uid != focus.mSession.mUid) {
4149 if (mContext.checkPermission(
4150 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4151 != PackageManager.PERMISSION_GRANTED) {
4152 Log.w(TAG, "Permission denied: injecting key event from pid "
4153 + pid + " uid " + uid + " to window " + focus
4154 + " owned by uid " + focus.mSession.mUid);
4155 if (qev != null) {
4156 mQueue.recycleEvent(qev);
4157 }
4158 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004159 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 }
4161 }
Romain Guy06882f82009-06-10 13:36:04 -07004162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004163 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004165 synchronized(mWindowMap) {
4166 if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
4167 mKeyWaiter.bindTargetWindowLocked(focus,
4168 KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
4169 // We don't deliver movement events to the client, we hold
4170 // them and wait for them to call back.
4171 ev = null;
4172 } else {
4173 mKeyWaiter.bindTargetWindowLocked(focus);
4174 }
4175 }
Romain Guy06882f82009-06-10 13:36:04 -07004176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004177 try {
4178 focus.mClient.dispatchTrackball(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004179 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004180 } catch (android.os.RemoteException e) {
4181 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4182 try {
4183 removeWindow(focus.mSession, focus.mClient);
4184 } catch (java.util.NoSuchElementException ex) {
4185 // This will happen if the window has already been
4186 // removed.
4187 }
4188 }
Romain Guy06882f82009-06-10 13:36:04 -07004189
Dianne Hackborncfaef692009-06-15 14:24:44 -07004190 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004191 }
Romain Guy06882f82009-06-10 13:36:04 -07004192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 /**
4194 * @return Returns true if event was dispatched, false if it was dropped for any reason
4195 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004196 private int dispatchKey(KeyEvent event, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197 if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
4198
4199 Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004200 null, false, false, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004201 if (focusObj == null) {
4202 Log.w(TAG, "No focus window, dropping: " + event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004203 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004204 }
4205 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004206 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004207 }
Romain Guy06882f82009-06-10 13:36:04 -07004208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004209 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004211 if (DEBUG_INPUT) Log.v(
4212 TAG, "Dispatching to " + focus + ": " + event);
4213
4214 if (uid != 0 && uid != focus.mSession.mUid) {
4215 if (mContext.checkPermission(
4216 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4217 != PackageManager.PERMISSION_GRANTED) {
4218 Log.w(TAG, "Permission denied: injecting key event from pid "
4219 + pid + " uid " + uid + " to window " + focus
4220 + " owned by uid " + focus.mSession.mUid);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004221 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004222 }
4223 }
Romain Guy06882f82009-06-10 13:36:04 -07004224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004225 synchronized(mWindowMap) {
4226 mKeyWaiter.bindTargetWindowLocked(focus);
4227 }
4228
4229 // NOSHIP extra state logging
4230 mKeyWaiter.recordDispatchState(event, focus);
4231 // END NOSHIP
Romain Guy06882f82009-06-10 13:36:04 -07004232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004233 try {
4234 if (DEBUG_INPUT || DEBUG_FOCUS) {
4235 Log.v(TAG, "Delivering key " + event.getKeyCode()
4236 + " to " + focus);
4237 }
4238 focus.mClient.dispatchKey(event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004239 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004240 } catch (android.os.RemoteException e) {
4241 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4242 try {
4243 removeWindow(focus.mSession, focus.mClient);
4244 } catch (java.util.NoSuchElementException ex) {
4245 // This will happen if the window has already been
4246 // removed.
4247 }
4248 }
Romain Guy06882f82009-06-10 13:36:04 -07004249
Dianne Hackborncfaef692009-06-15 14:24:44 -07004250 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004251 }
Romain Guy06882f82009-06-10 13:36:04 -07004252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004253 public void pauseKeyDispatching(IBinder _token) {
4254 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4255 "pauseKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004256 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004257 }
4258
4259 synchronized (mWindowMap) {
4260 WindowToken token = mTokenMap.get(_token);
4261 if (token != null) {
4262 mKeyWaiter.pauseDispatchingLocked(token);
4263 }
4264 }
4265 }
4266
4267 public void resumeKeyDispatching(IBinder _token) {
4268 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4269 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004270 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004271 }
4272
4273 synchronized (mWindowMap) {
4274 WindowToken token = mTokenMap.get(_token);
4275 if (token != null) {
4276 mKeyWaiter.resumeDispatchingLocked(token);
4277 }
4278 }
4279 }
4280
4281 public void setEventDispatching(boolean enabled) {
4282 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4283 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004284 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004285 }
4286
4287 synchronized (mWindowMap) {
4288 mKeyWaiter.setEventDispatchingLocked(enabled);
4289 }
4290 }
Romain Guy06882f82009-06-10 13:36:04 -07004291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004292 /**
4293 * Injects a keystroke event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004294 *
4295 * @param ev A motion event describing the keystroke action. (Be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004296 * {@link SystemClock#uptimeMillis()} as the timebase.)
4297 * @param sync If true, wait for the event to be completed before returning to the caller.
4298 * @return Returns true if event was dispatched, false if it was dropped for any reason
4299 */
4300 public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
4301 long downTime = ev.getDownTime();
4302 long eventTime = ev.getEventTime();
4303
4304 int action = ev.getAction();
4305 int code = ev.getKeyCode();
4306 int repeatCount = ev.getRepeatCount();
4307 int metaState = ev.getMetaState();
4308 int deviceId = ev.getDeviceId();
4309 int scancode = ev.getScanCode();
4310
4311 if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
4312 if (downTime == 0) downTime = eventTime;
4313
4314 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
The Android Open Source Project10592532009-03-18 17:39:46 -07004315 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004316
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004317 final int pid = Binder.getCallingPid();
4318 final int uid = Binder.getCallingUid();
4319 final long ident = Binder.clearCallingIdentity();
4320 final int result = dispatchKey(newEvent, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004321 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004322 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004323 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004324 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004325 switch (result) {
4326 case INJECT_NO_PERMISSION:
4327 throw new SecurityException(
4328 "Injecting to another application requires INJECT_EVENT permission");
4329 case INJECT_SUCCEEDED:
4330 return true;
4331 }
4332 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004333 }
4334
4335 /**
4336 * Inject a pointer (touch) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004337 *
4338 * @param ev A motion event describing the pointer (touch) action. (As noted in
4339 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004340 * {@link SystemClock#uptimeMillis()} as the timebase.)
4341 * @param sync If true, wait for the event to be completed before returning to the caller.
4342 * @return Returns true if event was dispatched, false if it was dropped for any reason
4343 */
4344 public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004345 final int pid = Binder.getCallingPid();
4346 final int uid = Binder.getCallingUid();
4347 final long ident = Binder.clearCallingIdentity();
4348 final int result = dispatchPointer(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004349 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004350 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004351 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004352 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004353 switch (result) {
4354 case INJECT_NO_PERMISSION:
4355 throw new SecurityException(
4356 "Injecting to another application requires INJECT_EVENT permission");
4357 case INJECT_SUCCEEDED:
4358 return true;
4359 }
4360 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004361 }
Romain Guy06882f82009-06-10 13:36:04 -07004362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004363 /**
4364 * Inject a trackball (navigation device) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004365 *
4366 * @param ev A motion event describing the trackball action. (As noted in
4367 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004368 * {@link SystemClock#uptimeMillis()} as the timebase.)
4369 * @param sync If true, wait for the event to be completed before returning to the caller.
4370 * @return Returns true if event was dispatched, false if it was dropped for any reason
4371 */
4372 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004373 final int pid = Binder.getCallingPid();
4374 final int uid = Binder.getCallingUid();
4375 final long ident = Binder.clearCallingIdentity();
4376 final int result = dispatchTrackball(null, ev, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004377 if (sync) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004378 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004379 }
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004380 Binder.restoreCallingIdentity(ident);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004381 switch (result) {
4382 case INJECT_NO_PERMISSION:
4383 throw new SecurityException(
4384 "Injecting to another application requires INJECT_EVENT permission");
4385 case INJECT_SUCCEEDED:
4386 return true;
4387 }
4388 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004389 }
Romain Guy06882f82009-06-10 13:36:04 -07004390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004391 private WindowState getFocusedWindow() {
4392 synchronized (mWindowMap) {
4393 return getFocusedWindowLocked();
4394 }
4395 }
4396
4397 private WindowState getFocusedWindowLocked() {
4398 return mCurrentFocus;
4399 }
Romain Guy06882f82009-06-10 13:36:04 -07004400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004401 /**
4402 * This class holds the state for dispatching key events. This state
4403 * is protected by the KeyWaiter instance, NOT by the window lock. You
4404 * can be holding the main window lock while acquire the KeyWaiter lock,
4405 * but not the other way around.
4406 */
4407 final class KeyWaiter {
4408 // NOSHIP debugging
4409 public class DispatchState {
4410 private KeyEvent event;
4411 private WindowState focus;
4412 private long time;
4413 private WindowState lastWin;
4414 private IBinder lastBinder;
4415 private boolean finished;
4416 private boolean gotFirstWindow;
4417 private boolean eventDispatching;
4418 private long timeToSwitch;
4419 private boolean wasFrozen;
4420 private boolean focusPaused;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004421 private WindowState curFocus;
Romain Guy06882f82009-06-10 13:36:04 -07004422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004423 DispatchState(KeyEvent theEvent, WindowState theFocus) {
4424 focus = theFocus;
4425 event = theEvent;
4426 time = System.currentTimeMillis();
4427 // snapshot KeyWaiter state
4428 lastWin = mLastWin;
4429 lastBinder = mLastBinder;
4430 finished = mFinished;
4431 gotFirstWindow = mGotFirstWindow;
4432 eventDispatching = mEventDispatching;
4433 timeToSwitch = mTimeToSwitch;
4434 wasFrozen = mWasFrozen;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004435 curFocus = mCurrentFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004436 // cache the paused state at ctor time as well
4437 if (theFocus == null || theFocus.mToken == null) {
4438 Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
4439 focusPaused = false;
4440 } else {
4441 focusPaused = theFocus.mToken.paused;
4442 }
4443 }
Romain Guy06882f82009-06-10 13:36:04 -07004444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004445 public String toString() {
4446 return "{{" + event + " to " + focus + " @ " + time
4447 + " lw=" + lastWin + " lb=" + lastBinder
4448 + " fin=" + finished + " gfw=" + gotFirstWindow
4449 + " ed=" + eventDispatching + " tts=" + timeToSwitch
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004450 + " wf=" + wasFrozen + " fp=" + focusPaused
4451 + " mcf=" + mCurrentFocus + "}}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004452 }
4453 };
4454 private DispatchState mDispatchState = null;
4455 public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
4456 mDispatchState = new DispatchState(theEvent, theFocus);
4457 }
4458 // END NOSHIP
4459
4460 public static final int RETURN_NOTHING = 0;
4461 public static final int RETURN_PENDING_POINTER = 1;
4462 public static final int RETURN_PENDING_TRACKBALL = 2;
Romain Guy06882f82009-06-10 13:36:04 -07004463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 final Object SKIP_TARGET_TOKEN = new Object();
4465 final Object CONSUMED_EVENT_TOKEN = new Object();
Romain Guy06882f82009-06-10 13:36:04 -07004466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004467 private WindowState mLastWin = null;
4468 private IBinder mLastBinder = null;
4469 private boolean mFinished = true;
4470 private boolean mGotFirstWindow = false;
4471 private boolean mEventDispatching = true;
4472 private long mTimeToSwitch = 0;
4473 /* package */ boolean mWasFrozen = false;
Romain Guy06882f82009-06-10 13:36:04 -07004474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004475 // Target of Motion events
4476 WindowState mMotionTarget;
Romain Guy06882f82009-06-10 13:36:04 -07004477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004478 // Windows above the target who would like to receive an "outside"
4479 // touch event for any down events outside of them.
4480 WindowState mOutsideTouchTargets;
4481
4482 /**
4483 * Wait for the last event dispatch to complete, then find the next
4484 * target that should receive the given event and wait for that one
4485 * to be ready to receive it.
4486 */
4487 Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
4488 MotionEvent nextMotion, boolean isPointerEvent,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004489 boolean failIfTimeout, int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004490 long startTime = SystemClock.uptimeMillis();
4491 long keyDispatchingTimeout = 5 * 1000;
4492 long waitedFor = 0;
4493
4494 while (true) {
4495 // Figure out which window we care about. It is either the
4496 // last window we are waiting to have process the event or,
4497 // if none, then the next window we think the event should go
4498 // to. Note: we retrieve mLastWin outside of the lock, so
4499 // it may change before we lock. Thus we must check it again.
4500 WindowState targetWin = mLastWin;
4501 boolean targetIsNew = targetWin == null;
4502 if (DEBUG_INPUT) Log.v(
4503 TAG, "waitForLastKey: mFinished=" + mFinished +
4504 ", mLastWin=" + mLastWin);
4505 if (targetIsNew) {
4506 Object target = findTargetWindow(nextKey, qev, nextMotion,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004507 isPointerEvent, callingPid, callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 if (target == SKIP_TARGET_TOKEN) {
4509 // The user has pressed a special key, and we are
4510 // dropping all pending events before it.
4511 if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey
4512 + " " + nextMotion);
4513 return null;
4514 }
4515 if (target == CONSUMED_EVENT_TOKEN) {
4516 if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
4517 + " " + nextMotion);
4518 return target;
4519 }
4520 targetWin = (WindowState)target;
4521 }
Romain Guy06882f82009-06-10 13:36:04 -07004522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004523 AppWindowToken targetApp = null;
Romain Guy06882f82009-06-10 13:36:04 -07004524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004525 // Now: is it okay to send the next event to this window?
4526 synchronized (this) {
4527 // First: did we come here based on the last window not
4528 // being null, but it changed by the time we got here?
4529 // If so, try again.
4530 if (!targetIsNew && mLastWin == null) {
4531 continue;
4532 }
Romain Guy06882f82009-06-10 13:36:04 -07004533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004534 // We never dispatch events if not finished with the
4535 // last one, or the display is frozen.
4536 if (mFinished && !mDisplayFrozen) {
4537 // If event dispatching is disabled, then we
4538 // just consume the events.
4539 if (!mEventDispatching) {
4540 if (DEBUG_INPUT) Log.v(TAG,
4541 "Skipping event; dispatching disabled: "
4542 + nextKey + " " + nextMotion);
4543 return null;
4544 }
4545 if (targetWin != null) {
4546 // If this is a new target, and that target is not
4547 // paused or unresponsive, then all looks good to
4548 // handle the event.
4549 if (targetIsNew && !targetWin.mToken.paused) {
4550 return targetWin;
4551 }
Romain Guy06882f82009-06-10 13:36:04 -07004552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 // If we didn't find a target window, and there is no
4554 // focused app window, then just eat the events.
4555 } else if (mFocusedApp == null) {
4556 if (DEBUG_INPUT) Log.v(TAG,
4557 "Skipping event; no focused app: "
4558 + nextKey + " " + nextMotion);
4559 return null;
4560 }
4561 }
Romain Guy06882f82009-06-10 13:36:04 -07004562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004563 if (DEBUG_INPUT) Log.v(
4564 TAG, "Waiting for last key in " + mLastBinder
4565 + " target=" + targetWin
4566 + " mFinished=" + mFinished
4567 + " mDisplayFrozen=" + mDisplayFrozen
4568 + " targetIsNew=" + targetIsNew
4569 + " paused="
4570 + (targetWin != null ? targetWin.mToken.paused : false)
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004571 + " mFocusedApp=" + mFocusedApp
4572 + " mCurrentFocus=" + mCurrentFocus);
Romain Guy06882f82009-06-10 13:36:04 -07004573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004574 targetApp = targetWin != null
4575 ? targetWin.mAppToken : mFocusedApp;
Romain Guy06882f82009-06-10 13:36:04 -07004576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004577 long curTimeout = keyDispatchingTimeout;
4578 if (mTimeToSwitch != 0) {
4579 long now = SystemClock.uptimeMillis();
4580 if (mTimeToSwitch <= now) {
4581 // If an app switch key has been pressed, and we have
4582 // waited too long for the current app to finish
4583 // processing keys, then wait no more!
4584 doFinishedKeyLocked(true);
4585 continue;
4586 }
4587 long switchTimeout = mTimeToSwitch - now;
4588 if (curTimeout > switchTimeout) {
4589 curTimeout = switchTimeout;
4590 }
4591 }
Romain Guy06882f82009-06-10 13:36:04 -07004592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004593 try {
4594 // after that continue
4595 // processing keys, so we don't get stuck.
4596 if (DEBUG_INPUT) Log.v(
4597 TAG, "Waiting for key dispatch: " + curTimeout);
4598 wait(curTimeout);
4599 if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
4600 + SystemClock.uptimeMillis() + " startTime="
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004601 + startTime + " switchTime=" + mTimeToSwitch
4602 + " target=" + targetWin + " mLW=" + mLastWin
4603 + " mLB=" + mLastBinder + " fin=" + mFinished
4604 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 } catch (InterruptedException e) {
4606 }
4607 }
4608
4609 // If we were frozen during configuration change, restart the
4610 // timeout checks from now; otherwise look at whether we timed
4611 // out before awakening.
4612 if (mWasFrozen) {
4613 waitedFor = 0;
4614 mWasFrozen = false;
4615 } else {
4616 waitedFor = SystemClock.uptimeMillis() - startTime;
4617 }
4618
4619 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
4620 IApplicationToken at = null;
4621 synchronized (this) {
4622 Log.w(TAG, "Key dispatching timed out sending to " +
4623 (targetWin != null ? targetWin.mAttrs.getTitle()
4624 : "<null>"));
4625 // NOSHIP debugging
4626 Log.w(TAG, "Dispatch state: " + mDispatchState);
4627 Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
4628 // END NOSHIP
4629 //dump();
4630 if (targetWin != null) {
4631 at = targetWin.getAppToken();
4632 } else if (targetApp != null) {
4633 at = targetApp.appToken;
4634 }
4635 }
4636
4637 boolean abort = true;
4638 if (at != null) {
4639 try {
4640 long timeout = at.getKeyDispatchingTimeout();
4641 if (timeout > waitedFor) {
4642 // we did not wait the proper amount of time for this application.
4643 // set the timeout to be the real timeout and wait again.
4644 keyDispatchingTimeout = timeout - waitedFor;
4645 continue;
4646 } else {
4647 abort = at.keyDispatchingTimedOut();
4648 }
4649 } catch (RemoteException ex) {
4650 }
4651 }
4652
4653 synchronized (this) {
4654 if (abort && (mLastWin == targetWin || targetWin == null)) {
4655 mFinished = true;
Romain Guy06882f82009-06-10 13:36:04 -07004656 if (mLastWin != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004657 if (DEBUG_INPUT) Log.v(TAG,
4658 "Window " + mLastWin +
4659 " timed out on key input");
4660 if (mLastWin.mToken.paused) {
4661 Log.w(TAG, "Un-pausing dispatching to this window");
4662 mLastWin.mToken.paused = false;
4663 }
4664 }
4665 if (mMotionTarget == targetWin) {
4666 mMotionTarget = null;
4667 }
4668 mLastWin = null;
4669 mLastBinder = null;
4670 if (failIfTimeout || targetWin == null) {
4671 return null;
4672 }
4673 } else {
4674 Log.w(TAG, "Continuing to wait for key to be dispatched");
4675 startTime = SystemClock.uptimeMillis();
4676 }
4677 }
4678 }
4679 }
4680 }
Romain Guy06882f82009-06-10 13:36:04 -07004681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004683 MotionEvent nextMotion, boolean isPointerEvent,
4684 int callingPid, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 mOutsideTouchTargets = null;
Romain Guy06882f82009-06-10 13:36:04 -07004686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 if (nextKey != null) {
4688 // Find the target window for a normal key event.
4689 final int keycode = nextKey.getKeyCode();
4690 final int repeatCount = nextKey.getRepeatCount();
4691 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
4692 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 if (!dispatch) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004695 if (callingUid == 0 ||
4696 mContext.checkPermission(
4697 android.Manifest.permission.INJECT_EVENTS,
4698 callingPid, callingUid)
4699 == PackageManager.PERMISSION_GRANTED) {
4700 mPolicy.interceptKeyTi(null, keycode,
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07004701 nextKey.getMetaState(), down, repeatCount,
4702 nextKey.getFlags());
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004704 Log.w(TAG, "Event timeout during app switch: dropping "
4705 + nextKey);
4706 return SKIP_TARGET_TOKEN;
4707 }
Romain Guy06882f82009-06-10 13:36:04 -07004708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
Romain Guy06882f82009-06-10 13:36:04 -07004710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004711 WindowState focus = null;
4712 synchronized(mWindowMap) {
4713 focus = getFocusedWindowLocked();
4714 }
Romain Guy06882f82009-06-10 13:36:04 -07004715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004716 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
Romain Guy06882f82009-06-10 13:36:04 -07004717
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004718 if (callingUid == 0 ||
4719 (focus != null && callingUid == focus.mSession.mUid) ||
4720 mContext.checkPermission(
4721 android.Manifest.permission.INJECT_EVENTS,
4722 callingPid, callingUid)
4723 == PackageManager.PERMISSION_GRANTED) {
4724 if (mPolicy.interceptKeyTi(focus,
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07004725 keycode, nextKey.getMetaState(), down, repeatCount,
4726 nextKey.getFlags())) {
Dianne Hackborn2bd33d72009-06-26 18:59:01 -07004727 return CONSUMED_EVENT_TOKEN;
4728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004729 }
Romain Guy06882f82009-06-10 13:36:04 -07004730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004731 return focus;
Romain Guy06882f82009-06-10 13:36:04 -07004732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004733 } else if (!isPointerEvent) {
4734 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
4735 if (!dispatch) {
4736 Log.w(TAG, "Event timeout during app switch: dropping trackball "
4737 + nextMotion);
4738 return SKIP_TARGET_TOKEN;
4739 }
Romain Guy06882f82009-06-10 13:36:04 -07004740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004741 WindowState focus = null;
4742 synchronized(mWindowMap) {
4743 focus = getFocusedWindowLocked();
4744 }
Romain Guy06882f82009-06-10 13:36:04 -07004745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
4747 return focus;
4748 }
Romain Guy06882f82009-06-10 13:36:04 -07004749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004750 if (nextMotion == null) {
4751 return SKIP_TARGET_TOKEN;
4752 }
Romain Guy06882f82009-06-10 13:36:04 -07004753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004754 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
4755 KeyEvent.KEYCODE_UNKNOWN);
4756 if (!dispatch) {
4757 Log.w(TAG, "Event timeout during app switch: dropping pointer "
4758 + nextMotion);
4759 return SKIP_TARGET_TOKEN;
4760 }
Romain Guy06882f82009-06-10 13:36:04 -07004761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004762 // Find the target window for a pointer event.
4763 int action = nextMotion.getAction();
4764 final float xf = nextMotion.getX();
4765 final float yf = nextMotion.getY();
4766 final long eventTime = nextMotion.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004768 final boolean screenWasOff = qev != null
4769 && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07004770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004771 WindowState target = null;
Romain Guy06882f82009-06-10 13:36:04 -07004772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004773 synchronized(mWindowMap) {
4774 synchronized (this) {
4775 if (action == MotionEvent.ACTION_DOWN) {
4776 if (mMotionTarget != null) {
4777 // this is weird, we got a pen down, but we thought it was
4778 // already down!
4779 // XXX: We should probably send an ACTION_UP to the current
4780 // target.
4781 Log.w(TAG, "Pointer down received while already down in: "
4782 + mMotionTarget);
4783 mMotionTarget = null;
4784 }
Romain Guy06882f82009-06-10 13:36:04 -07004785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 // ACTION_DOWN is special, because we need to lock next events to
4787 // the window we'll land onto.
4788 final int x = (int)xf;
4789 final int y = (int)yf;
Romain Guy06882f82009-06-10 13:36:04 -07004790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004791 final ArrayList windows = mWindows;
4792 final int N = windows.size();
4793 WindowState topErrWindow = null;
4794 final Rect tmpRect = mTempRect;
4795 for (int i=N-1; i>=0; i--) {
4796 WindowState child = (WindowState)windows.get(i);
4797 //Log.i(TAG, "Checking dispatch to: " + child);
4798 final int flags = child.mAttrs.flags;
4799 if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
4800 if (topErrWindow == null) {
4801 topErrWindow = child;
4802 }
4803 }
4804 if (!child.isVisibleLw()) {
4805 //Log.i(TAG, "Not visible!");
4806 continue;
4807 }
4808 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
4809 //Log.i(TAG, "Not touchable!");
4810 if ((flags & WindowManager.LayoutParams
4811 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4812 child.mNextOutsideTouch = mOutsideTouchTargets;
4813 mOutsideTouchTargets = child;
4814 }
4815 continue;
4816 }
4817 tmpRect.set(child.mFrame);
4818 if (child.mTouchableInsets == ViewTreeObserver
4819 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
4820 // The touch is inside of the window if it is
4821 // inside the frame, AND the content part of that
4822 // frame that was given by the application.
4823 tmpRect.left += child.mGivenContentInsets.left;
4824 tmpRect.top += child.mGivenContentInsets.top;
4825 tmpRect.right -= child.mGivenContentInsets.right;
4826 tmpRect.bottom -= child.mGivenContentInsets.bottom;
4827 } else if (child.mTouchableInsets == ViewTreeObserver
4828 .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
4829 // The touch is inside of the window if it is
4830 // inside the frame, AND the visible part of that
4831 // frame that was given by the application.
4832 tmpRect.left += child.mGivenVisibleInsets.left;
4833 tmpRect.top += child.mGivenVisibleInsets.top;
4834 tmpRect.right -= child.mGivenVisibleInsets.right;
4835 tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
4836 }
4837 final int touchFlags = flags &
4838 (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
4839 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
4840 if (tmpRect.contains(x, y) || touchFlags == 0) {
4841 //Log.i(TAG, "Using this target!");
4842 if (!screenWasOff || (flags &
4843 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
4844 mMotionTarget = child;
4845 } else {
4846 //Log.i(TAG, "Waking, skip!");
4847 mMotionTarget = null;
4848 }
4849 break;
4850 }
Romain Guy06882f82009-06-10 13:36:04 -07004851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004852 if ((flags & WindowManager.LayoutParams
4853 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4854 child.mNextOutsideTouch = mOutsideTouchTargets;
4855 mOutsideTouchTargets = child;
4856 //Log.i(TAG, "Adding to outside target list: " + child);
4857 }
4858 }
4859
4860 // if there's an error window but it's not accepting
4861 // focus (typically because it is not yet visible) just
4862 // wait for it -- any other focused window may in fact
4863 // be in ANR state.
4864 if (topErrWindow != null && mMotionTarget != topErrWindow) {
4865 mMotionTarget = null;
4866 }
4867 }
Romain Guy06882f82009-06-10 13:36:04 -07004868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004869 target = mMotionTarget;
4870 }
4871 }
Romain Guy06882f82009-06-10 13:36:04 -07004872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873 wakeupIfNeeded(target, eventType(nextMotion));
Romain Guy06882f82009-06-10 13:36:04 -07004874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004875 // Pointer events are a little different -- if there isn't a
4876 // target found for any event, then just drop it.
4877 return target != null ? target : SKIP_TARGET_TOKEN;
4878 }
Romain Guy06882f82009-06-10 13:36:04 -07004879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004880 boolean checkShouldDispatchKey(int keycode) {
4881 synchronized (this) {
4882 if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
4883 mTimeToSwitch = 0;
4884 return true;
4885 }
4886 if (mTimeToSwitch != 0
4887 && mTimeToSwitch < SystemClock.uptimeMillis()) {
4888 return false;
4889 }
4890 return true;
4891 }
4892 }
Romain Guy06882f82009-06-10 13:36:04 -07004893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004894 void bindTargetWindowLocked(WindowState win,
4895 int pendingWhat, QueuedEvent pendingMotion) {
4896 synchronized (this) {
4897 bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
4898 }
4899 }
Romain Guy06882f82009-06-10 13:36:04 -07004900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004901 void bindTargetWindowLocked(WindowState win) {
4902 synchronized (this) {
4903 bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
4904 }
4905 }
4906
4907 void bindTargetWindowLockedLocked(WindowState win,
4908 int pendingWhat, QueuedEvent pendingMotion) {
4909 mLastWin = win;
4910 mLastBinder = win.mClient.asBinder();
4911 mFinished = false;
4912 if (pendingMotion != null) {
4913 final Session s = win.mSession;
4914 if (pendingWhat == RETURN_PENDING_POINTER) {
4915 releasePendingPointerLocked(s);
4916 s.mPendingPointerMove = pendingMotion;
4917 s.mPendingPointerWindow = win;
Romain Guy06882f82009-06-10 13:36:04 -07004918 if (DEBUG_INPUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004919 "bindTargetToWindow " + s.mPendingPointerMove);
4920 } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
4921 releasePendingTrackballLocked(s);
4922 s.mPendingTrackballMove = pendingMotion;
4923 s.mPendingTrackballWindow = win;
4924 }
4925 }
4926 }
Romain Guy06882f82009-06-10 13:36:04 -07004927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004928 void releasePendingPointerLocked(Session s) {
4929 if (DEBUG_INPUT) Log.v(TAG,
4930 "releasePendingPointer " + s.mPendingPointerMove);
4931 if (s.mPendingPointerMove != null) {
4932 mQueue.recycleEvent(s.mPendingPointerMove);
4933 s.mPendingPointerMove = null;
4934 }
4935 }
Romain Guy06882f82009-06-10 13:36:04 -07004936
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004937 void releasePendingTrackballLocked(Session s) {
4938 if (s.mPendingTrackballMove != null) {
4939 mQueue.recycleEvent(s.mPendingTrackballMove);
4940 s.mPendingTrackballMove = null;
4941 }
4942 }
Romain Guy06882f82009-06-10 13:36:04 -07004943
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004944 MotionEvent finishedKey(Session session, IWindow client, boolean force,
4945 int returnWhat) {
4946 if (DEBUG_INPUT) Log.v(
4947 TAG, "finishedKey: client=" + client + ", force=" + force);
4948
4949 if (client == null) {
4950 return null;
4951 }
4952
4953 synchronized (this) {
4954 if (DEBUG_INPUT) Log.v(
4955 TAG, "finishedKey: client=" + client.asBinder()
4956 + ", force=" + force + ", last=" + mLastBinder
4957 + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
4958
4959 QueuedEvent qev = null;
4960 WindowState win = null;
4961 if (returnWhat == RETURN_PENDING_POINTER) {
4962 qev = session.mPendingPointerMove;
4963 win = session.mPendingPointerWindow;
4964 session.mPendingPointerMove = null;
4965 session.mPendingPointerWindow = null;
4966 } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
4967 qev = session.mPendingTrackballMove;
4968 win = session.mPendingTrackballWindow;
4969 session.mPendingTrackballMove = null;
4970 session.mPendingTrackballWindow = null;
4971 }
Romain Guy06882f82009-06-10 13:36:04 -07004972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004973 if (mLastBinder == client.asBinder()) {
4974 if (DEBUG_INPUT) Log.v(
4975 TAG, "finishedKey: last paused="
4976 + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
4977 if (mLastWin != null && (!mLastWin.mToken.paused || force
4978 || !mEventDispatching)) {
4979 doFinishedKeyLocked(false);
4980 } else {
4981 // Make sure to wake up anyone currently waiting to
4982 // dispatch a key, so they can re-evaluate their
4983 // current situation.
4984 mFinished = true;
4985 notifyAll();
4986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004987 }
Romain Guy06882f82009-06-10 13:36:04 -07004988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004989 if (qev != null) {
4990 MotionEvent res = (MotionEvent)qev.event;
4991 if (DEBUG_INPUT) Log.v(TAG,
4992 "Returning pending motion: " + res);
4993 mQueue.recycleEvent(qev);
4994 if (win != null && returnWhat == RETURN_PENDING_POINTER) {
4995 res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
4996 }
4997 return res;
4998 }
4999 return null;
5000 }
5001 }
5002
5003 void tickle() {
5004 synchronized (this) {
5005 notifyAll();
5006 }
5007 }
Romain Guy06882f82009-06-10 13:36:04 -07005008
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005009 void handleNewWindowLocked(WindowState newWindow) {
5010 if (!newWindow.canReceiveKeys()) {
5011 return;
5012 }
5013 synchronized (this) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005014 if (DEBUG_INPUT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005015 TAG, "New key dispatch window: win="
5016 + newWindow.mClient.asBinder()
5017 + ", last=" + mLastBinder
5018 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
5019 + "), finished=" + mFinished + ", paused="
5020 + newWindow.mToken.paused);
5021
5022 // Displaying a window implicitly causes dispatching to
5023 // be unpaused. (This is to protect against bugs if someone
5024 // pauses dispatching but forgets to resume.)
5025 newWindow.mToken.paused = false;
5026
5027 mGotFirstWindow = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005028
5029 if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
5030 if (DEBUG_INPUT) Log.v(TAG,
5031 "New SYSTEM_ERROR window; resetting state");
5032 mLastWin = null;
5033 mLastBinder = null;
5034 mMotionTarget = null;
5035 mFinished = true;
5036 } else if (mLastWin != null) {
5037 // If the new window is above the window we are
5038 // waiting on, then stop waiting and let key dispatching
5039 // start on the new guy.
5040 if (DEBUG_INPUT) Log.v(
5041 TAG, "Last win layer=" + mLastWin.mLayer
5042 + ", new win layer=" + newWindow.mLayer);
5043 if (newWindow.mLayer >= mLastWin.mLayer) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005044 // The new window is above the old; finish pending input to the last
5045 // window and start directing it to the new one.
5046 mLastWin.mToken.paused = false;
5047 doFinishedKeyLocked(true); // does a notifyAll()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005048 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005049 // Either the new window is lower, so there is no need to wake key waiters,
5050 // or we just finished key input to the previous window, which implicitly
5051 // notified the key waiters. In both cases, we don't need to issue the
5052 // notification here.
5053 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005054 }
5055
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08005056 // Now that we've put a new window state in place, make the event waiter
5057 // take notice and retarget its attentions.
5058 notifyAll();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005059 }
5060 }
5061
5062 void pauseDispatchingLocked(WindowToken token) {
5063 synchronized (this)
5064 {
5065 if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
5066 token.paused = true;
5067
5068 /*
5069 if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
5070 mPaused = true;
5071 } else {
5072 if (mLastWin == null) {
Dave Bortcfe65242009-04-09 14:51:04 -07005073 Log.i(TAG, "Key dispatching not paused: no last window.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005074 } else if (mFinished) {
Dave Bortcfe65242009-04-09 14:51:04 -07005075 Log.i(TAG, "Key dispatching not paused: finished last key.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005076 } else {
Dave Bortcfe65242009-04-09 14:51:04 -07005077 Log.i(TAG, "Key dispatching not paused: window in higher layer.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 }
5079 }
5080 */
5081 }
5082 }
5083
5084 void resumeDispatchingLocked(WindowToken token) {
5085 synchronized (this) {
5086 if (token.paused) {
5087 if (DEBUG_INPUT) Log.v(
5088 TAG, "Resuming WindowToken " + token
5089 + ", last=" + mLastBinder
5090 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
5091 + "), finished=" + mFinished + ", paused="
5092 + token.paused);
5093 token.paused = false;
5094 if (mLastWin != null && mLastWin.mToken == token && mFinished) {
5095 doFinishedKeyLocked(true);
5096 } else {
5097 notifyAll();
5098 }
5099 }
5100 }
5101 }
5102
5103 void setEventDispatchingLocked(boolean enabled) {
5104 synchronized (this) {
5105 mEventDispatching = enabled;
5106 notifyAll();
5107 }
5108 }
Romain Guy06882f82009-06-10 13:36:04 -07005109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005110 void appSwitchComing() {
5111 synchronized (this) {
5112 // Don't wait for more than .5 seconds for app to finish
5113 // processing the pending events.
5114 long now = SystemClock.uptimeMillis() + 500;
5115 if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now);
5116 if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
5117 mTimeToSwitch = now;
5118 }
5119 notifyAll();
5120 }
5121 }
Romain Guy06882f82009-06-10 13:36:04 -07005122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005123 private final void doFinishedKeyLocked(boolean doRecycle) {
5124 if (mLastWin != null) {
5125 releasePendingPointerLocked(mLastWin.mSession);
5126 releasePendingTrackballLocked(mLastWin.mSession);
5127 }
Romain Guy06882f82009-06-10 13:36:04 -07005128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005129 if (mLastWin == null || !mLastWin.mToken.paused
5130 || !mLastWin.isVisibleLw()) {
5131 // If the current window has been paused, we aren't -really-
5132 // finished... so let the waiters still wait.
5133 mLastWin = null;
5134 mLastBinder = null;
5135 }
5136 mFinished = true;
5137 notifyAll();
5138 }
5139 }
5140
5141 private class KeyQ extends KeyInputQueue
5142 implements KeyInputQueue.FilterCallback {
5143 PowerManager.WakeLock mHoldingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07005144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005145 KeyQ() {
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07005146 super(mContext, WindowManagerService.this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005147 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
5148 mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
5149 "KEEP_SCREEN_ON_FLAG");
5150 mHoldingScreen.setReferenceCounted(false);
5151 }
5152
5153 @Override
5154 boolean preprocessEvent(InputDevice device, RawInputEvent event) {
5155 if (mPolicy.preprocessInputEventTq(event)) {
5156 return true;
5157 }
Romain Guy06882f82009-06-10 13:36:04 -07005158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005159 switch (event.type) {
5160 case RawInputEvent.EV_KEY: {
5161 // XXX begin hack
5162 if (DEBUG) {
5163 if (event.keycode == KeyEvent.KEYCODE_G) {
5164 if (event.value != 0) {
5165 // G down
5166 mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
5167 }
5168 return false;
5169 }
5170 if (event.keycode == KeyEvent.KEYCODE_D) {
5171 if (event.value != 0) {
5172 //dump();
5173 }
5174 return false;
5175 }
5176 }
5177 // XXX end hack
Romain Guy06882f82009-06-10 13:36:04 -07005178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005179 boolean screenIsOff = !mPowerManager.screenIsOn();
5180 boolean screenIsDim = !mPowerManager.screenIsBright();
5181 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
Romain Guy06882f82009-06-10 13:36:04 -07005182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183 if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
5184 mPowerManager.goToSleep(event.when);
5185 }
5186
5187 if (screenIsOff) {
5188 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5189 }
5190 if (screenIsDim) {
5191 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5192 }
5193 if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
5194 mPowerManager.userActivity(event.when, false,
Michael Chane96440f2009-05-06 10:27:36 -07005195 LocalPowerManager.BUTTON_EVENT, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005196 }
Romain Guy06882f82009-06-10 13:36:04 -07005197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005198 if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
5199 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
5200 filterQueue(this);
5201 mKeyWaiter.appSwitchComing();
5202 }
5203 return true;
5204 } else {
5205 return false;
5206 }
5207 }
Romain Guy06882f82009-06-10 13:36:04 -07005208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 case RawInputEvent.EV_REL: {
5210 boolean screenIsOff = !mPowerManager.screenIsOn();
5211 boolean screenIsDim = !mPowerManager.screenIsBright();
5212 if (screenIsOff) {
5213 if (!mPolicy.isWakeRelMovementTq(event.deviceId,
5214 device.classes, event)) {
5215 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5216 return false;
5217 }
5218 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5219 }
5220 if (screenIsDim) {
5221 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5222 }
5223 return true;
5224 }
Romain Guy06882f82009-06-10 13:36:04 -07005225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005226 case RawInputEvent.EV_ABS: {
5227 boolean screenIsOff = !mPowerManager.screenIsOn();
5228 boolean screenIsDim = !mPowerManager.screenIsBright();
5229 if (screenIsOff) {
5230 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
5231 device.classes, event)) {
5232 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5233 return false;
5234 }
5235 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5236 }
5237 if (screenIsDim) {
5238 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5239 }
5240 return true;
5241 }
Romain Guy06882f82009-06-10 13:36:04 -07005242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005243 default:
5244 return true;
5245 }
5246 }
5247
5248 public int filterEvent(QueuedEvent ev) {
5249 switch (ev.classType) {
5250 case RawInputEvent.CLASS_KEYBOARD:
5251 KeyEvent ke = (KeyEvent)ev.event;
5252 if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
5253 Log.w(TAG, "Dropping movement key during app switch: "
5254 + ke.getKeyCode() + ", action=" + ke.getAction());
5255 return FILTER_REMOVE;
5256 }
5257 return FILTER_ABORT;
5258 default:
5259 return FILTER_KEEP;
5260 }
5261 }
Romain Guy06882f82009-06-10 13:36:04 -07005262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005263 /**
5264 * Must be called with the main window manager lock held.
5265 */
5266 void setHoldScreenLocked(boolean holding) {
5267 boolean state = mHoldingScreen.isHeld();
5268 if (holding != state) {
5269 if (holding) {
5270 mHoldingScreen.acquire();
5271 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005272 mPolicy.screenOnStoppedLw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005273 mHoldingScreen.release();
5274 }
5275 }
5276 }
Michael Chan53071d62009-05-13 17:29:48 -07005277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005278
5279 public boolean detectSafeMode() {
5280 mSafeMode = mPolicy.detectSafeMode();
5281 return mSafeMode;
5282 }
Romain Guy06882f82009-06-10 13:36:04 -07005283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005284 public void systemReady() {
5285 mPolicy.systemReady();
5286 }
Romain Guy06882f82009-06-10 13:36:04 -07005287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005288 private final class InputDispatcherThread extends Thread {
5289 // Time to wait when there is nothing to do: 9999 seconds.
5290 static final int LONG_WAIT=9999*1000;
5291
5292 public InputDispatcherThread() {
5293 super("InputDispatcher");
5294 }
Romain Guy06882f82009-06-10 13:36:04 -07005295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005296 @Override
5297 public void run() {
5298 while (true) {
5299 try {
5300 process();
5301 } catch (Exception e) {
5302 Log.e(TAG, "Exception in input dispatcher", e);
5303 }
5304 }
5305 }
Romain Guy06882f82009-06-10 13:36:04 -07005306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005307 private void process() {
5308 android.os.Process.setThreadPriority(
5309 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -07005310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005311 // The last key event we saw
5312 KeyEvent lastKey = null;
5313
5314 // Last keydown time for auto-repeating keys
5315 long lastKeyTime = SystemClock.uptimeMillis();
5316 long nextKeyTime = lastKeyTime+LONG_WAIT;
5317
Romain Guy06882f82009-06-10 13:36:04 -07005318 // How many successive repeats we generated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005319 int keyRepeatCount = 0;
5320
5321 // Need to report that configuration has changed?
5322 boolean configChanged = false;
Romain Guy06882f82009-06-10 13:36:04 -07005323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005324 while (true) {
5325 long curTime = SystemClock.uptimeMillis();
5326
5327 if (DEBUG_INPUT) Log.v(
5328 TAG, "Waiting for next key: now=" + curTime
5329 + ", repeat @ " + nextKeyTime);
5330
5331 // Retrieve next event, waiting only as long as the next
5332 // repeat timeout. If the configuration has changed, then
5333 // don't wait at all -- we'll report the change as soon as
5334 // we have processed all events.
5335 QueuedEvent ev = mQueue.getEvent(
5336 (int)((!configChanged && curTime < nextKeyTime)
5337 ? (nextKeyTime-curTime) : 0));
5338
5339 if (DEBUG_INPUT && ev != null) Log.v(
5340 TAG, "Event: type=" + ev.classType + " data=" + ev.event);
5341
Michael Chan53071d62009-05-13 17:29:48 -07005342 if (MEASURE_LATENCY) {
5343 lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
5344 }
5345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005346 try {
5347 if (ev != null) {
Michael Chan53071d62009-05-13 17:29:48 -07005348 curTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005349 int eventType;
5350 if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
5351 eventType = eventType((MotionEvent)ev.event);
5352 } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
5353 ev.classType == RawInputEvent.CLASS_TRACKBALL) {
5354 eventType = LocalPowerManager.BUTTON_EVENT;
5355 } else {
5356 eventType = LocalPowerManager.OTHER_EVENT;
5357 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005358 try {
Michael Chan53071d62009-05-13 17:29:48 -07005359 if ((curTime - mLastBatteryStatsCallTime)
Michael Chane96440f2009-05-06 10:27:36 -07005360 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
Michael Chan53071d62009-05-13 17:29:48 -07005361 mLastBatteryStatsCallTime = curTime;
Michael Chane96440f2009-05-06 10:27:36 -07005362 mBatteryStats.noteInputEvent();
5363 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005364 } catch (RemoteException e) {
5365 // Ignore
5366 }
Michael Chane10de972009-05-18 11:24:50 -07005367
5368 if (eventType != TOUCH_EVENT
5369 && eventType != LONG_TOUCH_EVENT
5370 && eventType != CHEEK_EVENT) {
5371 mPowerManager.userActivity(curTime, false,
5372 eventType, false);
5373 } else if (mLastTouchEventType != eventType
5374 || (curTime - mLastUserActivityCallTime)
5375 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
5376 mLastUserActivityCallTime = curTime;
5377 mLastTouchEventType = eventType;
5378 mPowerManager.userActivity(curTime, false,
5379 eventType, false);
5380 }
5381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005382 switch (ev.classType) {
5383 case RawInputEvent.CLASS_KEYBOARD:
5384 KeyEvent ke = (KeyEvent)ev.event;
5385 if (ke.isDown()) {
5386 lastKey = ke;
5387 keyRepeatCount = 0;
5388 lastKeyTime = curTime;
5389 nextKeyTime = lastKeyTime
5390 + KEY_REPEAT_FIRST_DELAY;
5391 if (DEBUG_INPUT) Log.v(
5392 TAG, "Received key down: first repeat @ "
5393 + nextKeyTime);
5394 } else {
5395 lastKey = null;
5396 // Arbitrary long timeout.
5397 lastKeyTime = curTime;
5398 nextKeyTime = curTime + LONG_WAIT;
5399 if (DEBUG_INPUT) Log.v(
5400 TAG, "Received key up: ignore repeat @ "
5401 + nextKeyTime);
5402 }
5403 dispatchKey((KeyEvent)ev.event, 0, 0);
5404 mQueue.recycleEvent(ev);
5405 break;
5406 case RawInputEvent.CLASS_TOUCHSCREEN:
5407 //Log.i(TAG, "Read next event " + ev);
5408 dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
5409 break;
5410 case RawInputEvent.CLASS_TRACKBALL:
5411 dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
5412 break;
5413 case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
5414 configChanged = true;
5415 break;
5416 default:
5417 mQueue.recycleEvent(ev);
5418 break;
5419 }
Romain Guy06882f82009-06-10 13:36:04 -07005420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005421 } else if (configChanged) {
5422 configChanged = false;
5423 sendNewConfiguration();
Romain Guy06882f82009-06-10 13:36:04 -07005424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005425 } else if (lastKey != null) {
5426 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005428 // Timeout occurred while key was down. If it is at or
5429 // past the key repeat time, dispatch the repeat.
5430 if (DEBUG_INPUT) Log.v(
5431 TAG, "Key timeout: repeat=" + nextKeyTime
5432 + ", now=" + curTime);
5433 if (curTime < nextKeyTime) {
5434 continue;
5435 }
Romain Guy06882f82009-06-10 13:36:04 -07005436
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005437 lastKeyTime = nextKeyTime;
5438 nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
5439 keyRepeatCount++;
5440 if (DEBUG_INPUT) Log.v(
5441 TAG, "Key repeat: count=" + keyRepeatCount
5442 + ", next @ " + nextKeyTime);
The Android Open Source Project10592532009-03-18 17:39:46 -07005443 dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
Romain Guy06882f82009-06-10 13:36:04 -07005444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005445 } else {
5446 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005448 lastKeyTime = curTime;
5449 nextKeyTime = curTime + LONG_WAIT;
5450 }
Romain Guy06882f82009-06-10 13:36:04 -07005451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 } catch (Exception e) {
5453 Log.e(TAG,
5454 "Input thread received uncaught exception: " + e, e);
5455 }
5456 }
5457 }
5458 }
5459
5460 // -------------------------------------------------------------
5461 // Client Session State
5462 // -------------------------------------------------------------
5463
5464 private final class Session extends IWindowSession.Stub
5465 implements IBinder.DeathRecipient {
5466 final IInputMethodClient mClient;
5467 final IInputContext mInputContext;
5468 final int mUid;
5469 final int mPid;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005470 final String mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005471 SurfaceSession mSurfaceSession;
5472 int mNumWindow = 0;
5473 boolean mClientDead = false;
Romain Guy06882f82009-06-10 13:36:04 -07005474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005475 /**
5476 * Current pointer move event being dispatched to client window... must
5477 * hold key lock to access.
5478 */
5479 QueuedEvent mPendingPointerMove;
5480 WindowState mPendingPointerWindow;
Romain Guy06882f82009-06-10 13:36:04 -07005481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005482 /**
5483 * Current trackball move event being dispatched to client window... must
5484 * hold key lock to access.
5485 */
5486 QueuedEvent mPendingTrackballMove;
5487 WindowState mPendingTrackballWindow;
5488
5489 public Session(IInputMethodClient client, IInputContext inputContext) {
5490 mClient = client;
5491 mInputContext = inputContext;
5492 mUid = Binder.getCallingUid();
5493 mPid = Binder.getCallingPid();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005494 StringBuilder sb = new StringBuilder();
5495 sb.append("Session{");
5496 sb.append(Integer.toHexString(System.identityHashCode(this)));
5497 sb.append(" uid ");
5498 sb.append(mUid);
5499 sb.append("}");
5500 mStringName = sb.toString();
Romain Guy06882f82009-06-10 13:36:04 -07005501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005502 synchronized (mWindowMap) {
5503 if (mInputMethodManager == null && mHaveInputMethods) {
5504 IBinder b = ServiceManager.getService(
5505 Context.INPUT_METHOD_SERVICE);
5506 mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
5507 }
5508 }
5509 long ident = Binder.clearCallingIdentity();
5510 try {
5511 // Note: it is safe to call in to the input method manager
5512 // here because we are not holding our lock.
5513 if (mInputMethodManager != null) {
5514 mInputMethodManager.addClient(client, inputContext,
5515 mUid, mPid);
5516 } else {
5517 client.setUsingInputMethod(false);
5518 }
5519 client.asBinder().linkToDeath(this, 0);
5520 } catch (RemoteException e) {
5521 // The caller has died, so we can just forget about this.
5522 try {
5523 if (mInputMethodManager != null) {
5524 mInputMethodManager.removeClient(client);
5525 }
5526 } catch (RemoteException ee) {
5527 }
5528 } finally {
5529 Binder.restoreCallingIdentity(ident);
5530 }
5531 }
Romain Guy06882f82009-06-10 13:36:04 -07005532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533 @Override
5534 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5535 throws RemoteException {
5536 try {
5537 return super.onTransact(code, data, reply, flags);
5538 } catch (RuntimeException e) {
5539 // Log all 'real' exceptions thrown to the caller
5540 if (!(e instanceof SecurityException)) {
5541 Log.e(TAG, "Window Session Crash", e);
5542 }
5543 throw e;
5544 }
5545 }
5546
5547 public void binderDied() {
5548 // Note: it is safe to call in to the input method manager
5549 // here because we are not holding our lock.
5550 try {
5551 if (mInputMethodManager != null) {
5552 mInputMethodManager.removeClient(mClient);
5553 }
5554 } catch (RemoteException e) {
5555 }
5556 synchronized(mWindowMap) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07005557 mClient.asBinder().unlinkToDeath(this, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005558 mClientDead = true;
5559 killSessionLocked();
5560 }
5561 }
5562
5563 public int add(IWindow window, WindowManager.LayoutParams attrs,
5564 int viewVisibility, Rect outContentInsets) {
5565 return addWindow(this, window, attrs, viewVisibility, outContentInsets);
5566 }
Romain Guy06882f82009-06-10 13:36:04 -07005567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005568 public void remove(IWindow window) {
5569 removeWindow(this, window);
5570 }
Romain Guy06882f82009-06-10 13:36:04 -07005571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005572 public int relayout(IWindow window, WindowManager.LayoutParams attrs,
5573 int requestedWidth, int requestedHeight, int viewFlags,
5574 boolean insetsPending, Rect outFrame, Rect outContentInsets,
5575 Rect outVisibleInsets, Surface outSurface) {
5576 return relayoutWindow(this, window, attrs,
5577 requestedWidth, requestedHeight, viewFlags, insetsPending,
5578 outFrame, outContentInsets, outVisibleInsets, outSurface);
5579 }
Romain Guy06882f82009-06-10 13:36:04 -07005580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005581 public void setTransparentRegion(IWindow window, Region region) {
5582 setTransparentRegionWindow(this, window, region);
5583 }
Romain Guy06882f82009-06-10 13:36:04 -07005584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 public void setInsets(IWindow window, int touchableInsets,
5586 Rect contentInsets, Rect visibleInsets) {
5587 setInsetsWindow(this, window, touchableInsets, contentInsets,
5588 visibleInsets);
5589 }
Romain Guy06882f82009-06-10 13:36:04 -07005590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005591 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
5592 getWindowDisplayFrame(this, window, outDisplayFrame);
5593 }
Romain Guy06882f82009-06-10 13:36:04 -07005594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005595 public void finishDrawing(IWindow window) {
5596 if (localLOGV) Log.v(
5597 TAG, "IWindow finishDrawing called for " + window);
5598 finishDrawingWindow(this, window);
5599 }
5600
5601 public void finishKey(IWindow window) {
5602 if (localLOGV) Log.v(
5603 TAG, "IWindow finishKey called for " + window);
5604 mKeyWaiter.finishedKey(this, window, false,
5605 KeyWaiter.RETURN_NOTHING);
5606 }
5607
5608 public MotionEvent getPendingPointerMove(IWindow window) {
5609 if (localLOGV) Log.v(
5610 TAG, "IWindow getPendingMotionEvent called for " + window);
5611 return mKeyWaiter.finishedKey(this, window, false,
5612 KeyWaiter.RETURN_PENDING_POINTER);
5613 }
Romain Guy06882f82009-06-10 13:36:04 -07005614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005615 public MotionEvent getPendingTrackballMove(IWindow window) {
5616 if (localLOGV) Log.v(
5617 TAG, "IWindow getPendingMotionEvent called for " + window);
5618 return mKeyWaiter.finishedKey(this, window, false,
5619 KeyWaiter.RETURN_PENDING_TRACKBALL);
5620 }
5621
5622 public void setInTouchMode(boolean mode) {
5623 synchronized(mWindowMap) {
5624 mInTouchMode = mode;
5625 }
5626 }
5627
5628 public boolean getInTouchMode() {
5629 synchronized(mWindowMap) {
5630 return mInTouchMode;
5631 }
5632 }
5633
5634 public boolean performHapticFeedback(IWindow window, int effectId,
5635 boolean always) {
5636 synchronized(mWindowMap) {
5637 long ident = Binder.clearCallingIdentity();
5638 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005639 return mPolicy.performHapticFeedbackLw(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005640 windowForClientLocked(this, window), effectId, always);
5641 } finally {
5642 Binder.restoreCallingIdentity(ident);
5643 }
5644 }
5645 }
Romain Guy06882f82009-06-10 13:36:04 -07005646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005647 void windowAddedLocked() {
5648 if (mSurfaceSession == null) {
5649 if (localLOGV) Log.v(
5650 TAG, "First window added to " + this + ", creating SurfaceSession");
5651 mSurfaceSession = new SurfaceSession();
5652 mSessions.add(this);
5653 }
5654 mNumWindow++;
5655 }
5656
5657 void windowRemovedLocked() {
5658 mNumWindow--;
5659 killSessionLocked();
5660 }
Romain Guy06882f82009-06-10 13:36:04 -07005661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005662 void killSessionLocked() {
5663 if (mNumWindow <= 0 && mClientDead) {
5664 mSessions.remove(this);
5665 if (mSurfaceSession != null) {
5666 if (localLOGV) Log.v(
5667 TAG, "Last window removed from " + this
5668 + ", destroying " + mSurfaceSession);
5669 try {
5670 mSurfaceSession.kill();
5671 } catch (Exception e) {
5672 Log.w(TAG, "Exception thrown when killing surface session "
5673 + mSurfaceSession + " in session " + this
5674 + ": " + e.toString());
5675 }
5676 mSurfaceSession = null;
5677 }
5678 }
5679 }
Romain Guy06882f82009-06-10 13:36:04 -07005680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005681 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005682 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
5683 pw.print(" mClientDead="); pw.print(mClientDead);
5684 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
5685 if (mPendingPointerWindow != null || mPendingPointerMove != null) {
5686 pw.print(prefix);
5687 pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
5688 pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
5689 }
5690 if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
5691 pw.print(prefix);
5692 pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
5693 pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
5694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005695 }
5696
5697 @Override
5698 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005699 return mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005700 }
5701 }
5702
5703 // -------------------------------------------------------------
5704 // Client Window State
5705 // -------------------------------------------------------------
5706
5707 private final class WindowState implements WindowManagerPolicy.WindowState {
5708 final Session mSession;
5709 final IWindow mClient;
5710 WindowToken mToken;
The Android Open Source Project10592532009-03-18 17:39:46 -07005711 WindowToken mRootToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005712 AppWindowToken mAppToken;
5713 AppWindowToken mTargetAppToken;
5714 final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
5715 final DeathRecipient mDeathRecipient;
5716 final WindowState mAttachedWindow;
5717 final ArrayList mChildWindows = new ArrayList();
5718 final int mBaseLayer;
5719 final int mSubLayer;
5720 final boolean mLayoutAttached;
5721 final boolean mIsImWindow;
5722 int mViewVisibility;
5723 boolean mPolicyVisibility = true;
5724 boolean mPolicyVisibilityAfterAnim = true;
5725 boolean mAppFreezing;
5726 Surface mSurface;
5727 boolean mAttachedHidden; // is our parent window hidden?
5728 boolean mLastHidden; // was this window last hidden?
5729 int mRequestedWidth;
5730 int mRequestedHeight;
5731 int mLastRequestedWidth;
5732 int mLastRequestedHeight;
5733 int mReqXPos;
5734 int mReqYPos;
5735 int mLayer;
5736 int mAnimLayer;
5737 int mLastLayer;
5738 boolean mHaveFrame;
5739
5740 WindowState mNextOutsideTouch;
Romain Guy06882f82009-06-10 13:36:04 -07005741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 // Actual frame shown on-screen (may be modified by animation)
5743 final Rect mShownFrame = new Rect();
5744 final Rect mLastShownFrame = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005746 /**
5747 * Insets that determine the actually visible area
5748 */
5749 final Rect mVisibleInsets = new Rect();
5750 final Rect mLastVisibleInsets = new Rect();
5751 boolean mVisibleInsetsChanged;
5752
5753 /**
5754 * Insets that are covered by system windows
5755 */
5756 final Rect mContentInsets = new Rect();
5757 final Rect mLastContentInsets = new Rect();
5758 boolean mContentInsetsChanged;
5759
5760 /**
5761 * Set to true if we are waiting for this window to receive its
5762 * given internal insets before laying out other windows based on it.
5763 */
5764 boolean mGivenInsetsPending;
Romain Guy06882f82009-06-10 13:36:04 -07005765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005766 /**
5767 * These are the content insets that were given during layout for
5768 * this window, to be applied to windows behind it.
5769 */
5770 final Rect mGivenContentInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 /**
5773 * These are the visible insets that were given during layout for
5774 * this window, to be applied to windows behind it.
5775 */
5776 final Rect mGivenVisibleInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005778 /**
5779 * Flag indicating whether the touchable region should be adjusted by
5780 * the visible insets; if false the area outside the visible insets is
5781 * NOT touchable, so we must use those to adjust the frame during hit
5782 * tests.
5783 */
5784 int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
Romain Guy06882f82009-06-10 13:36:04 -07005785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005786 // Current transformation being applied.
5787 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
5788 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
5789 float mHScale=1, mVScale=1;
5790 float mLastHScale=1, mLastVScale=1;
5791 final Matrix mTmpMatrix = new Matrix();
5792
5793 // "Real" frame that the application sees.
5794 final Rect mFrame = new Rect();
5795 final Rect mLastFrame = new Rect();
5796
5797 final Rect mContainingFrame = new Rect();
5798 final Rect mDisplayFrame = new Rect();
5799 final Rect mContentFrame = new Rect();
5800 final Rect mVisibleFrame = new Rect();
5801
5802 float mShownAlpha = 1;
5803 float mAlpha = 1;
5804 float mLastAlpha = 1;
5805
5806 // Set to true if, when the window gets displayed, it should perform
5807 // an enter animation.
5808 boolean mEnterAnimationPending;
5809
5810 // Currently running animation.
5811 boolean mAnimating;
5812 boolean mLocalAnimating;
5813 Animation mAnimation;
5814 boolean mAnimationIsEntrance;
5815 boolean mHasTransformation;
5816 boolean mHasLocalTransformation;
5817 final Transformation mTransformation = new Transformation();
5818
5819 // This is set after IWindowSession.relayout() has been called at
5820 // least once for the window. It allows us to detect the situation
5821 // where we don't yet have a surface, but should have one soon, so
5822 // we can give the window focus before waiting for the relayout.
5823 boolean mRelayoutCalled;
Romain Guy06882f82009-06-10 13:36:04 -07005824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005825 // This is set after the Surface has been created but before the
5826 // window has been drawn. During this time the surface is hidden.
5827 boolean mDrawPending;
5828
5829 // This is set after the window has finished drawing for the first
5830 // time but before its surface is shown. The surface will be
5831 // displayed when the next layout is run.
5832 boolean mCommitDrawPending;
5833
5834 // This is set during the time after the window's drawing has been
5835 // committed, and before its surface is actually shown. It is used
5836 // to delay showing the surface until all windows in a token are ready
5837 // to be shown.
5838 boolean mReadyToShow;
Romain Guy06882f82009-06-10 13:36:04 -07005839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005840 // Set when the window has been shown in the screen the first time.
5841 boolean mHasDrawn;
5842
5843 // Currently running an exit animation?
5844 boolean mExiting;
5845
5846 // Currently on the mDestroySurface list?
5847 boolean mDestroying;
Romain Guy06882f82009-06-10 13:36:04 -07005848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005849 // Completely remove from window manager after exit animation?
5850 boolean mRemoveOnExit;
5851
5852 // Set when the orientation is changing and this window has not yet
5853 // been updated for the new orientation.
5854 boolean mOrientationChanging;
Romain Guy06882f82009-06-10 13:36:04 -07005855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005856 // Is this window now (or just being) removed?
5857 boolean mRemoved;
Romain Guy06882f82009-06-10 13:36:04 -07005858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005859 WindowState(Session s, IWindow c, WindowToken token,
5860 WindowState attachedWindow, WindowManager.LayoutParams a,
5861 int viewVisibility) {
5862 mSession = s;
5863 mClient = c;
5864 mToken = token;
5865 mAttrs.copyFrom(a);
5866 mViewVisibility = viewVisibility;
5867 DeathRecipient deathRecipient = new DeathRecipient();
5868 mAlpha = a.alpha;
5869 if (localLOGV) Log.v(
5870 TAG, "Window " + this + " client=" + c.asBinder()
5871 + " token=" + token + " (" + mAttrs.token + ")");
5872 try {
5873 c.asBinder().linkToDeath(deathRecipient, 0);
5874 } catch (RemoteException e) {
5875 mDeathRecipient = null;
5876 mAttachedWindow = null;
5877 mLayoutAttached = false;
5878 mIsImWindow = false;
5879 mBaseLayer = 0;
5880 mSubLayer = 0;
5881 return;
5882 }
5883 mDeathRecipient = deathRecipient;
Romain Guy06882f82009-06-10 13:36:04 -07005884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005885 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
5886 mAttrs.type <= LAST_SUB_WINDOW)) {
5887 // The multiplier here is to reserve space for multiple
5888 // windows in the same type layer.
5889 mBaseLayer = mPolicy.windowTypeToLayerLw(
5890 attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
5891 + TYPE_LAYER_OFFSET;
5892 mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
5893 mAttachedWindow = attachedWindow;
5894 mAttachedWindow.mChildWindows.add(this);
5895 mLayoutAttached = mAttrs.type !=
5896 WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
5897 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
5898 || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5899 } else {
5900 // The multiplier here is to reserve space for multiple
5901 // windows in the same type layer.
5902 mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
5903 * TYPE_LAYER_MULTIPLIER
5904 + TYPE_LAYER_OFFSET;
5905 mSubLayer = 0;
5906 mAttachedWindow = null;
5907 mLayoutAttached = false;
5908 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
5909 || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5910 }
5911
5912 WindowState appWin = this;
5913 while (appWin.mAttachedWindow != null) {
5914 appWin = mAttachedWindow;
5915 }
5916 WindowToken appToken = appWin.mToken;
5917 while (appToken.appWindowToken == null) {
5918 WindowToken parent = mTokenMap.get(appToken.token);
5919 if (parent == null || appToken == parent) {
5920 break;
5921 }
5922 appToken = parent;
5923 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005924 mRootToken = appToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005925 mAppToken = appToken.appWindowToken;
5926
5927 mSurface = null;
5928 mRequestedWidth = 0;
5929 mRequestedHeight = 0;
5930 mLastRequestedWidth = 0;
5931 mLastRequestedHeight = 0;
5932 mReqXPos = 0;
5933 mReqYPos = 0;
5934 mLayer = 0;
5935 mAnimLayer = 0;
5936 mLastLayer = 0;
5937 }
5938
5939 void attach() {
5940 if (localLOGV) Log.v(
5941 TAG, "Attaching " + this + " token=" + mToken
5942 + ", list=" + mToken.windows);
5943 mSession.windowAddedLocked();
5944 }
5945
5946 public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
5947 mHaveFrame = true;
5948
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005949 final Rect container = mContainingFrame;
5950 container.set(pf);
5951
5952 final Rect display = mDisplayFrame;
5953 display.set(df);
5954
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07005955 if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005956 container.intersect(mCompatibleScreenFrame);
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07005957 if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
5958 display.intersect(mCompatibleScreenFrame);
5959 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005960 }
5961
5962 final int pw = container.right - container.left;
5963 final int ph = container.bottom - container.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005964
5965 int w,h;
5966 if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
5967 w = mAttrs.width < 0 ? pw : mAttrs.width;
5968 h = mAttrs.height< 0 ? ph : mAttrs.height;
5969 } else {
5970 w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
5971 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
5972 }
Romain Guy06882f82009-06-10 13:36:04 -07005973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005974 final Rect content = mContentFrame;
5975 content.set(cf);
Romain Guy06882f82009-06-10 13:36:04 -07005976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005977 final Rect visible = mVisibleFrame;
5978 visible.set(vf);
Romain Guy06882f82009-06-10 13:36:04 -07005979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005980 final Rect frame = mFrame;
Romain Guy06882f82009-06-10 13:36:04 -07005981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005982 //System.out.println("In: w=" + w + " h=" + h + " container=" +
5983 // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
5984
5985 Gravity.apply(mAttrs.gravity, w, h, container,
5986 (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
5987 (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
5988
5989 //System.out.println("Out: " + mFrame);
5990
5991 // Now make sure the window fits in the overall display.
5992 Gravity.applyDisplay(mAttrs.gravity, df, frame);
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07005993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005994 // Make sure the content and visible frames are inside of the
5995 // final window frame.
5996 if (content.left < frame.left) content.left = frame.left;
5997 if (content.top < frame.top) content.top = frame.top;
5998 if (content.right > frame.right) content.right = frame.right;
5999 if (content.bottom > frame.bottom) content.bottom = frame.bottom;
6000 if (visible.left < frame.left) visible.left = frame.left;
6001 if (visible.top < frame.top) visible.top = frame.top;
6002 if (visible.right > frame.right) visible.right = frame.right;
6003 if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07006004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006005 final Rect contentInsets = mContentInsets;
6006 contentInsets.left = content.left-frame.left;
6007 contentInsets.top = content.top-frame.top;
6008 contentInsets.right = frame.right-content.right;
6009 contentInsets.bottom = frame.bottom-content.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07006010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006011 final Rect visibleInsets = mVisibleInsets;
6012 visibleInsets.left = visible.left-frame.left;
6013 visibleInsets.top = visible.top-frame.top;
6014 visibleInsets.right = frame.right-visible.right;
6015 visibleInsets.bottom = frame.bottom-visible.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07006016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006017 if (localLOGV) {
6018 //if ("com.google.android.youtube".equals(mAttrs.packageName)
6019 // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
6020 Log.v(TAG, "Resolving (mRequestedWidth="
6021 + mRequestedWidth + ", mRequestedheight="
6022 + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
6023 + "): frame=" + mFrame.toShortString()
6024 + " ci=" + contentInsets.toShortString()
6025 + " vi=" + visibleInsets.toShortString());
6026 //}
6027 }
6028 }
Romain Guy06882f82009-06-10 13:36:04 -07006029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006030 public Rect getFrameLw() {
6031 return mFrame;
6032 }
6033
6034 public Rect getShownFrameLw() {
6035 return mShownFrame;
6036 }
6037
6038 public Rect getDisplayFrameLw() {
6039 return mDisplayFrame;
6040 }
6041
6042 public Rect getContentFrameLw() {
6043 return mContentFrame;
6044 }
6045
6046 public Rect getVisibleFrameLw() {
6047 return mVisibleFrame;
6048 }
6049
6050 public boolean getGivenInsetsPendingLw() {
6051 return mGivenInsetsPending;
6052 }
6053
6054 public Rect getGivenContentInsetsLw() {
6055 return mGivenContentInsets;
6056 }
Romain Guy06882f82009-06-10 13:36:04 -07006057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006058 public Rect getGivenVisibleInsetsLw() {
6059 return mGivenVisibleInsets;
6060 }
Romain Guy06882f82009-06-10 13:36:04 -07006061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006062 public WindowManager.LayoutParams getAttrs() {
6063 return mAttrs;
6064 }
6065
6066 public int getSurfaceLayer() {
6067 return mLayer;
6068 }
Romain Guy06882f82009-06-10 13:36:04 -07006069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006070 public IApplicationToken getAppToken() {
6071 return mAppToken != null ? mAppToken.appToken : null;
6072 }
6073
6074 public boolean hasAppShownWindows() {
6075 return mAppToken != null ? mAppToken.firstWindowDrawn : false;
6076 }
6077
6078 public boolean hasAppStartingIcon() {
6079 return mAppToken != null ? (mAppToken.startingData != null) : false;
6080 }
6081
6082 public WindowManagerPolicy.WindowState getAppStartingWindow() {
6083 return mAppToken != null ? mAppToken.startingWindow : null;
6084 }
6085
6086 public void setAnimation(Animation anim) {
6087 if (localLOGV) Log.v(
6088 TAG, "Setting animation in " + this + ": " + anim);
6089 mAnimating = false;
6090 mLocalAnimating = false;
6091 mAnimation = anim;
6092 mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
6093 mAnimation.scaleCurrentDuration(mWindowAnimationScale);
6094 }
6095
6096 public void clearAnimation() {
6097 if (mAnimation != null) {
6098 mAnimating = true;
6099 mLocalAnimating = false;
6100 mAnimation = null;
6101 }
6102 }
Romain Guy06882f82009-06-10 13:36:04 -07006103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006104 Surface createSurfaceLocked() {
6105 if (mSurface == null) {
6106 mDrawPending = true;
6107 mCommitDrawPending = false;
6108 mReadyToShow = false;
6109 if (mAppToken != null) {
6110 mAppToken.allDrawn = false;
6111 }
6112
6113 int flags = 0;
6114 if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
6115 flags |= Surface.HARDWARE;
6116 } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
6117 flags |= Surface.GPU;
6118 } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
6119 flags |= Surface.PUSH_BUFFERS;
6120 }
6121
6122 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
6123 flags |= Surface.SECURE;
6124 }
6125 if (DEBUG_VISIBILITY) Log.v(
6126 TAG, "Creating surface in session "
6127 + mSession.mSurfaceSession + " window " + this
6128 + " w=" + mFrame.width()
6129 + " h=" + mFrame.height() + " format="
6130 + mAttrs.format + " flags=" + flags);
6131
6132 int w = mFrame.width();
6133 int h = mFrame.height();
6134 if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
6135 // for a scaled surface, we always want the requested
6136 // size.
6137 w = mRequestedWidth;
6138 h = mRequestedHeight;
6139 }
6140
6141 try {
6142 mSurface = new Surface(
Romain Guy06882f82009-06-10 13:36:04 -07006143 mSession.mSurfaceSession, mSession.mPid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006144 0, w, h, mAttrs.format, flags);
6145 } catch (Surface.OutOfResourcesException e) {
6146 Log.w(TAG, "OutOfResourcesException creating surface");
6147 reclaimSomeSurfaceMemoryLocked(this, "create");
6148 return null;
6149 } catch (Exception e) {
6150 Log.e(TAG, "Exception creating surface", e);
6151 return null;
6152 }
Romain Guy06882f82009-06-10 13:36:04 -07006153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006154 if (localLOGV) Log.v(
6155 TAG, "Got surface: " + mSurface
6156 + ", set left=" + mFrame.left + " top=" + mFrame.top
6157 + ", animLayer=" + mAnimLayer);
6158 if (SHOW_TRANSACTIONS) {
6159 Log.i(TAG, ">>> OPEN TRANSACTION");
6160 Log.i(TAG, " SURFACE " + mSurface + ": CREATE ("
6161 + mAttrs.getTitle() + ") pos=(" +
6162 mFrame.left + "," + mFrame.top + ") (" +
6163 mFrame.width() + "x" + mFrame.height() + "), layer=" +
6164 mAnimLayer + " HIDE");
6165 }
6166 Surface.openTransaction();
6167 try {
6168 try {
6169 mSurface.setPosition(mFrame.left, mFrame.top);
6170 mSurface.setLayer(mAnimLayer);
6171 mSurface.hide();
6172 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
6173 mSurface.setFlags(Surface.SURFACE_DITHER,
6174 Surface.SURFACE_DITHER);
6175 }
6176 } catch (RuntimeException e) {
6177 Log.w(TAG, "Error creating surface in " + w, e);
6178 reclaimSomeSurfaceMemoryLocked(this, "create-init");
6179 }
6180 mLastHidden = true;
6181 } finally {
6182 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
6183 Surface.closeTransaction();
6184 }
6185 if (localLOGV) Log.v(
6186 TAG, "Created surface " + this);
6187 }
6188 return mSurface;
6189 }
Romain Guy06882f82009-06-10 13:36:04 -07006190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006191 void destroySurfaceLocked() {
6192 // Window is no longer on-screen, so can no longer receive
6193 // key events... if we were waiting for it to finish
6194 // handling a key event, the wait is over!
6195 mKeyWaiter.finishedKey(mSession, mClient, true,
6196 KeyWaiter.RETURN_NOTHING);
6197 mKeyWaiter.releasePendingPointerLocked(mSession);
6198 mKeyWaiter.releasePendingTrackballLocked(mSession);
6199
6200 if (mAppToken != null && this == mAppToken.startingWindow) {
6201 mAppToken.startingDisplayed = false;
6202 }
Romain Guy06882f82009-06-10 13:36:04 -07006203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006204 if (localLOGV) Log.v(
6205 TAG, "Window " + this
6206 + " destroying surface " + mSurface + ", session " + mSession);
6207 if (mSurface != null) {
6208 try {
6209 if (SHOW_TRANSACTIONS) {
6210 RuntimeException ex = new RuntimeException();
6211 ex.fillInStackTrace();
6212 Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
6213 + mAttrs.getTitle() + ")", ex);
6214 }
6215 mSurface.clear();
6216 } catch (RuntimeException e) {
6217 Log.w(TAG, "Exception thrown when destroying Window " + this
6218 + " surface " + mSurface + " session " + mSession
6219 + ": " + e.toString());
6220 }
6221 mSurface = null;
6222 mDrawPending = false;
6223 mCommitDrawPending = false;
6224 mReadyToShow = false;
6225
6226 int i = mChildWindows.size();
6227 while (i > 0) {
6228 i--;
6229 WindowState c = (WindowState)mChildWindows.get(i);
6230 c.mAttachedHidden = true;
6231 }
6232 }
6233 }
6234
6235 boolean finishDrawingLocked() {
6236 if (mDrawPending) {
6237 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
6238 TAG, "finishDrawingLocked: " + mSurface);
6239 mCommitDrawPending = true;
6240 mDrawPending = false;
6241 return true;
6242 }
6243 return false;
6244 }
6245
6246 // This must be called while inside a transaction.
6247 void commitFinishDrawingLocked(long currentTime) {
6248 //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
6249 if (!mCommitDrawPending) {
6250 return;
6251 }
6252 mCommitDrawPending = false;
6253 mReadyToShow = true;
6254 final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING;
6255 final AppWindowToken atoken = mAppToken;
6256 if (atoken == null || atoken.allDrawn || starting) {
6257 performShowLocked();
6258 }
6259 }
6260
6261 // This must be called while inside a transaction.
6262 boolean performShowLocked() {
6263 if (DEBUG_VISIBILITY) {
6264 RuntimeException e = new RuntimeException();
6265 e.fillInStackTrace();
6266 Log.v(TAG, "performShow on " + this
6267 + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
6268 + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
6269 }
6270 if (mReadyToShow && isReadyForDisplay()) {
6271 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i(
6272 TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)");
6273 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this
6274 + " during animation: policyVis=" + mPolicyVisibility
6275 + " attHidden=" + mAttachedHidden
6276 + " tok.hiddenRequested="
6277 + (mAppToken != null ? mAppToken.hiddenRequested : false)
6278 + " tok.idden="
6279 + (mAppToken != null ? mAppToken.hidden : false)
6280 + " animating=" + mAnimating
6281 + " tok animating="
6282 + (mAppToken != null ? mAppToken.animating : false));
6283 if (!showSurfaceRobustlyLocked(this)) {
6284 return false;
6285 }
6286 mLastAlpha = -1;
6287 mHasDrawn = true;
6288 mLastHidden = false;
6289 mReadyToShow = false;
6290 enableScreenIfNeededLocked();
6291
6292 applyEnterAnimationLocked(this);
Romain Guy06882f82009-06-10 13:36:04 -07006293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006294 int i = mChildWindows.size();
6295 while (i > 0) {
6296 i--;
6297 WindowState c = (WindowState)mChildWindows.get(i);
6298 if (c.mSurface != null && c.mAttachedHidden) {
6299 c.mAttachedHidden = false;
6300 c.performShowLocked();
6301 }
6302 }
Romain Guy06882f82009-06-10 13:36:04 -07006303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006304 if (mAttrs.type != TYPE_APPLICATION_STARTING
6305 && mAppToken != null) {
6306 mAppToken.firstWindowDrawn = true;
6307 if (mAnimation == null && mAppToken.startingData != null) {
6308 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6309 + mToken
6310 + ": first real window is shown, no animation");
6311 mFinishedStarting.add(mAppToken);
6312 mH.sendEmptyMessage(H.FINISHED_STARTING);
6313 }
6314 mAppToken.updateReportedVisibilityLocked();
6315 }
6316 }
6317 return true;
6318 }
Romain Guy06882f82009-06-10 13:36:04 -07006319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006320 // This must be called while inside a transaction. Returns true if
6321 // there is more animation to run.
6322 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6323 if (!mDisplayFrozen) {
6324 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07006325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006326 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
6327 mHasTransformation = true;
6328 mHasLocalTransformation = true;
6329 if (!mLocalAnimating) {
6330 if (DEBUG_ANIM) Log.v(
6331 TAG, "Starting animation in " + this +
6332 " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
6333 " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
6334 mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
6335 mAnimation.setStartTime(currentTime);
6336 mLocalAnimating = true;
6337 mAnimating = true;
6338 }
6339 mTransformation.clear();
6340 final boolean more = mAnimation.getTransformation(
6341 currentTime, mTransformation);
6342 if (DEBUG_ANIM) Log.v(
6343 TAG, "Stepped animation in " + this +
6344 ": more=" + more + ", xform=" + mTransformation);
6345 if (more) {
6346 // we're not done!
6347 return true;
6348 }
6349 if (DEBUG_ANIM) Log.v(
6350 TAG, "Finished animation in " + this +
6351 " @ " + currentTime);
6352 mAnimation = null;
6353 //WindowManagerService.this.dump();
6354 }
6355 mHasLocalTransformation = false;
6356 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
6357 && mAppToken.hasTransformation) {
6358 // When our app token is animating, we kind-of pretend like
6359 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
6360 // part of this check means that we will only do this if
6361 // our window is not currently exiting, or it is not
6362 // locally animating itself. The idea being that one that
6363 // is exiting and doing a local animation should be removed
6364 // once that animation is done.
6365 mAnimating = true;
6366 mHasTransformation = true;
6367 mTransformation.clear();
6368 return false;
6369 } else if (mHasTransformation) {
6370 // Little trick to get through the path below to act like
6371 // we have finished an animation.
6372 mAnimating = true;
6373 } else if (isAnimating()) {
6374 mAnimating = true;
6375 }
6376 } else if (mAnimation != null) {
6377 // If the display is frozen, and there is a pending animation,
6378 // clear it and make sure we run the cleanup code.
6379 mAnimating = true;
6380 mLocalAnimating = true;
6381 mAnimation = null;
6382 }
Romain Guy06882f82009-06-10 13:36:04 -07006383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006384 if (!mAnimating && !mLocalAnimating) {
6385 return false;
6386 }
6387
6388 if (DEBUG_ANIM) Log.v(
6389 TAG, "Animation done in " + this + ": exiting=" + mExiting
6390 + ", reportedVisible="
6391 + (mAppToken != null ? mAppToken.reportedVisible : false));
Romain Guy06882f82009-06-10 13:36:04 -07006392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006393 mAnimating = false;
6394 mLocalAnimating = false;
6395 mAnimation = null;
6396 mAnimLayer = mLayer;
6397 if (mIsImWindow) {
6398 mAnimLayer += mInputMethodAnimLayerAdjustment;
6399 }
6400 if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
6401 + " anim layer: " + mAnimLayer);
6402 mHasTransformation = false;
6403 mHasLocalTransformation = false;
6404 mPolicyVisibility = mPolicyVisibilityAfterAnim;
6405 mTransformation.clear();
6406 if (mHasDrawn
6407 && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
6408 && mAppToken != null
6409 && mAppToken.firstWindowDrawn
6410 && mAppToken.startingData != null) {
6411 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6412 + mToken + ": first real window done animating");
6413 mFinishedStarting.add(mAppToken);
6414 mH.sendEmptyMessage(H.FINISHED_STARTING);
6415 }
Romain Guy06882f82009-06-10 13:36:04 -07006416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006417 finishExit();
6418
6419 if (mAppToken != null) {
6420 mAppToken.updateReportedVisibilityLocked();
6421 }
6422
6423 return false;
6424 }
6425
6426 void finishExit() {
6427 if (DEBUG_ANIM) Log.v(
6428 TAG, "finishExit in " + this
6429 + ": exiting=" + mExiting
6430 + " remove=" + mRemoveOnExit
6431 + " windowAnimating=" + isWindowAnimating());
Romain Guy06882f82009-06-10 13:36:04 -07006432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006433 final int N = mChildWindows.size();
6434 for (int i=0; i<N; i++) {
6435 ((WindowState)mChildWindows.get(i)).finishExit();
6436 }
Romain Guy06882f82009-06-10 13:36:04 -07006437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006438 if (!mExiting) {
6439 return;
6440 }
Romain Guy06882f82009-06-10 13:36:04 -07006441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006442 if (isWindowAnimating()) {
6443 return;
6444 }
6445
6446 if (localLOGV) Log.v(
6447 TAG, "Exit animation finished in " + this
6448 + ": remove=" + mRemoveOnExit);
6449 if (mSurface != null) {
6450 mDestroySurface.add(this);
6451 mDestroying = true;
6452 if (SHOW_TRANSACTIONS) Log.i(
6453 TAG, " SURFACE " + mSurface + ": HIDE (finishExit)");
6454 try {
6455 mSurface.hide();
6456 } catch (RuntimeException e) {
6457 Log.w(TAG, "Error hiding surface in " + this, e);
6458 }
6459 mLastHidden = true;
6460 mKeyWaiter.releasePendingPointerLocked(mSession);
6461 }
6462 mExiting = false;
6463 if (mRemoveOnExit) {
6464 mPendingRemove.add(this);
6465 mRemoveOnExit = false;
6466 }
6467 }
Romain Guy06882f82009-06-10 13:36:04 -07006468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006469 boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
6470 if (dsdx < .99999f || dsdx > 1.00001f) return false;
6471 if (dtdy < .99999f || dtdy > 1.00001f) return false;
6472 if (dtdx < -.000001f || dtdx > .000001f) return false;
6473 if (dsdy < -.000001f || dsdy > .000001f) return false;
6474 return true;
6475 }
Romain Guy06882f82009-06-10 13:36:04 -07006476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 void computeShownFrameLocked() {
6478 final boolean selfTransformation = mHasLocalTransformation;
6479 Transformation attachedTransformation =
6480 (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
6481 ? mAttachedWindow.mTransformation : null;
6482 Transformation appTransformation =
6483 (mAppToken != null && mAppToken.hasTransformation)
6484 ? mAppToken.transformation : null;
6485 if (selfTransformation || attachedTransformation != null
6486 || appTransformation != null) {
Romain Guy06882f82009-06-10 13:36:04 -07006487 // cache often used attributes locally
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006488 final Rect frame = mFrame;
6489 final float tmpFloats[] = mTmpFloats;
6490 final Matrix tmpMatrix = mTmpMatrix;
6491
6492 // Compute the desired transformation.
6493 tmpMatrix.setTranslate(frame.left, frame.top);
6494 if (selfTransformation) {
6495 tmpMatrix.preConcat(mTransformation.getMatrix());
6496 }
6497 if (attachedTransformation != null) {
6498 tmpMatrix.preConcat(attachedTransformation.getMatrix());
6499 }
6500 if (appTransformation != null) {
6501 tmpMatrix.preConcat(appTransformation.getMatrix());
6502 }
6503
6504 // "convert" it into SurfaceFlinger's format
6505 // (a 2x2 matrix + an offset)
6506 // Here we must not transform the position of the surface
6507 // since it is already included in the transformation.
6508 //Log.i(TAG, "Transform: " + matrix);
Romain Guy06882f82009-06-10 13:36:04 -07006509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006510 tmpMatrix.getValues(tmpFloats);
6511 mDsDx = tmpFloats[Matrix.MSCALE_X];
6512 mDtDx = tmpFloats[Matrix.MSKEW_X];
6513 mDsDy = tmpFloats[Matrix.MSKEW_Y];
6514 mDtDy = tmpFloats[Matrix.MSCALE_Y];
6515 int x = (int)tmpFloats[Matrix.MTRANS_X];
6516 int y = (int)tmpFloats[Matrix.MTRANS_Y];
6517 int w = frame.width();
6518 int h = frame.height();
6519 mShownFrame.set(x, y, x+w, y+h);
6520
6521 // Now set the alpha... but because our current hardware
6522 // can't do alpha transformation on a non-opaque surface,
6523 // turn it off if we are running an animation that is also
6524 // transforming since it is more important to have that
6525 // animation be smooth.
6526 mShownAlpha = mAlpha;
6527 if (!mLimitedAlphaCompositing
6528 || (!PixelFormat.formatHasAlpha(mAttrs.format)
6529 || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
6530 && x == frame.left && y == frame.top))) {
6531 //Log.i(TAG, "Applying alpha transform");
6532 if (selfTransformation) {
6533 mShownAlpha *= mTransformation.getAlpha();
6534 }
6535 if (attachedTransformation != null) {
6536 mShownAlpha *= attachedTransformation.getAlpha();
6537 }
6538 if (appTransformation != null) {
6539 mShownAlpha *= appTransformation.getAlpha();
6540 }
6541 } else {
6542 //Log.i(TAG, "Not applying alpha transform");
6543 }
Romain Guy06882f82009-06-10 13:36:04 -07006544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006545 if (localLOGV) Log.v(
6546 TAG, "Continuing animation in " + this +
6547 ": " + mShownFrame +
6548 ", alpha=" + mTransformation.getAlpha());
6549 return;
6550 }
Romain Guy06882f82009-06-10 13:36:04 -07006551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006552 mShownFrame.set(mFrame);
6553 mShownAlpha = mAlpha;
6554 mDsDx = 1;
6555 mDtDx = 0;
6556 mDsDy = 0;
6557 mDtDy = 1;
6558 }
Romain Guy06882f82009-06-10 13:36:04 -07006559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006560 /**
6561 * Is this window visible? It is not visible if there is no
6562 * surface, or we are in the process of running an exit animation
6563 * that will remove the surface, or its app token has been hidden.
6564 */
6565 public boolean isVisibleLw() {
6566 final AppWindowToken atoken = mAppToken;
6567 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6568 && (atoken == null || !atoken.hiddenRequested)
6569 && !mExiting && !mDestroying;
6570 }
6571
6572 /**
6573 * Is this window visible, ignoring its app token? It is not visible
6574 * if there is no surface, or we are in the process of running an exit animation
6575 * that will remove the surface.
6576 */
6577 public boolean isWinVisibleLw() {
6578 final AppWindowToken atoken = mAppToken;
6579 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6580 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
6581 && !mExiting && !mDestroying;
6582 }
6583
6584 /**
6585 * The same as isVisible(), but follows the current hidden state of
6586 * the associated app token, not the pending requested hidden state.
6587 */
6588 boolean isVisibleNow() {
6589 return mSurface != null && mPolicyVisibility && !mAttachedHidden
The Android Open Source Project10592532009-03-18 17:39:46 -07006590 && !mRootToken.hidden && !mExiting && !mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006591 }
6592
6593 /**
6594 * Same as isVisible(), but we also count it as visible between the
6595 * call to IWindowSession.add() and the first relayout().
6596 */
6597 boolean isVisibleOrAdding() {
6598 final AppWindowToken atoken = mAppToken;
6599 return (mSurface != null
6600 || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
6601 && mPolicyVisibility && !mAttachedHidden
6602 && (atoken == null || !atoken.hiddenRequested)
6603 && !mExiting && !mDestroying;
6604 }
6605
6606 /**
6607 * Is this window currently on-screen? It is on-screen either if it
6608 * is visible or it is currently running an animation before no longer
6609 * being visible.
6610 */
6611 boolean isOnScreen() {
6612 final AppWindowToken atoken = mAppToken;
6613 if (atoken != null) {
6614 return mSurface != null && mPolicyVisibility && !mDestroying
6615 && ((!mAttachedHidden && !atoken.hiddenRequested)
6616 || mAnimating || atoken.animating);
6617 } else {
6618 return mSurface != null && mPolicyVisibility && !mDestroying
6619 && (!mAttachedHidden || mAnimating);
6620 }
6621 }
Romain Guy06882f82009-06-10 13:36:04 -07006622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006623 /**
6624 * Like isOnScreen(), but we don't return true if the window is part
6625 * of a transition that has not yet been started.
6626 */
6627 boolean isReadyForDisplay() {
6628 final AppWindowToken atoken = mAppToken;
6629 final boolean animating = atoken != null ? atoken.animating : false;
6630 return mSurface != null && mPolicyVisibility && !mDestroying
The Android Open Source Project10592532009-03-18 17:39:46 -07006631 && ((!mAttachedHidden && !mRootToken.hidden)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006632 || mAnimating || animating);
6633 }
6634
6635 /** Is the window or its container currently animating? */
6636 boolean isAnimating() {
6637 final WindowState attached = mAttachedWindow;
6638 final AppWindowToken atoken = mAppToken;
6639 return mAnimation != null
6640 || (attached != null && attached.mAnimation != null)
Romain Guy06882f82009-06-10 13:36:04 -07006641 || (atoken != null &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006642 (atoken.animation != null
6643 || atoken.inPendingTransaction));
6644 }
6645
6646 /** Is this window currently animating? */
6647 boolean isWindowAnimating() {
6648 return mAnimation != null;
6649 }
6650
6651 /**
6652 * Like isOnScreen, but returns false if the surface hasn't yet
6653 * been drawn.
6654 */
6655 public boolean isDisplayedLw() {
6656 final AppWindowToken atoken = mAppToken;
6657 return mSurface != null && mPolicyVisibility && !mDestroying
6658 && !mDrawPending && !mCommitDrawPending
6659 && ((!mAttachedHidden &&
6660 (atoken == null || !atoken.hiddenRequested))
6661 || mAnimating);
6662 }
6663
6664 public boolean fillsScreenLw(int screenWidth, int screenHeight,
6665 boolean shownFrame, boolean onlyOpaque) {
6666 if (mSurface == null) {
6667 return false;
6668 }
6669 if (mAppToken != null && !mAppToken.appFullscreen) {
6670 return false;
6671 }
6672 if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
6673 return false;
6674 }
6675 final Rect frame = shownFrame ? mShownFrame : mFrame;
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07006676
6677 if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
6678 return frame.left <= mCompatibleScreenFrame.left &&
6679 frame.top <= mCompatibleScreenFrame.top &&
6680 frame.right >= mCompatibleScreenFrame.right &&
6681 frame.bottom >= mCompatibleScreenFrame.bottom;
6682 } else {
6683 return frame.left <= 0 && frame.top <= 0
6684 && frame.right >= screenWidth
6685 && frame.bottom >= screenHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006687 }
Romain Guy06882f82009-06-10 13:36:04 -07006688
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006689 /**
6690 * Return true if the window is opaque and fully drawn.
6691 */
6692 boolean isOpaqueDrawn() {
6693 return mAttrs.format == PixelFormat.OPAQUE && mSurface != null
6694 && mAnimation == null && !mDrawPending && !mCommitDrawPending;
6695 }
6696
6697 boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
6698 return
6699 // only if the application is requesting compatible window
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07006700 (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
6701 // only if it's visible
6702 mHasDrawn && mViewVisibility == View.VISIBLE &&
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07006703 // and only if the application fills the compatible screen
6704 mFrame.left <= mCompatibleScreenFrame.left &&
6705 mFrame.top <= mCompatibleScreenFrame.top &&
6706 mFrame.right >= mCompatibleScreenFrame.right &&
6707 mFrame.bottom >= mCompatibleScreenFrame.bottom &&
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07006708 // and starting window do not need background filler
Mitsuru Oshimad2967e22009-07-20 14:01:43 -07006709 mAttrs.type != mAttrs.TYPE_APPLICATION_STARTING;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07006710 }
6711
6712 boolean isFullscreen(int screenWidth, int screenHeight) {
6713 return mFrame.left <= 0 && mFrame.top <= 0 &&
6714 mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006715 }
6716
6717 void removeLocked() {
6718 if (mAttachedWindow != null) {
6719 mAttachedWindow.mChildWindows.remove(this);
6720 }
6721 destroySurfaceLocked();
6722 mSession.windowRemovedLocked();
6723 try {
6724 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
6725 } catch (RuntimeException e) {
6726 // Ignore if it has already been removed (usually because
6727 // we are doing this as part of processing a death note.)
6728 }
6729 }
6730
6731 private class DeathRecipient implements IBinder.DeathRecipient {
6732 public void binderDied() {
6733 try {
6734 synchronized(mWindowMap) {
6735 WindowState win = windowForClientLocked(mSession, mClient);
6736 Log.i(TAG, "WIN DEATH: " + win);
6737 if (win != null) {
6738 removeWindowLocked(mSession, win);
6739 }
6740 }
6741 } catch (IllegalArgumentException ex) {
6742 // This will happen if the window has already been
6743 // removed.
6744 }
6745 }
6746 }
6747
6748 /** Returns true if this window desires key events. */
6749 public final boolean canReceiveKeys() {
6750 return isVisibleOrAdding()
6751 && (mViewVisibility == View.VISIBLE)
6752 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
6753 }
6754
6755 public boolean hasDrawnLw() {
6756 return mHasDrawn;
6757 }
6758
6759 public boolean showLw(boolean doAnimation) {
6760 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
6761 mPolicyVisibility = true;
6762 mPolicyVisibilityAfterAnim = true;
6763 if (doAnimation) {
6764 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
6765 }
6766 requestAnimationLocked(0);
6767 return true;
6768 }
6769 return false;
6770 }
6771
6772 public boolean hideLw(boolean doAnimation) {
6773 boolean current = doAnimation ? mPolicyVisibilityAfterAnim
6774 : mPolicyVisibility;
6775 if (current) {
6776 if (doAnimation) {
6777 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
6778 if (mAnimation == null) {
6779 doAnimation = false;
6780 }
6781 }
6782 if (doAnimation) {
6783 mPolicyVisibilityAfterAnim = false;
6784 } else {
6785 mPolicyVisibilityAfterAnim = false;
6786 mPolicyVisibility = false;
6787 }
6788 requestAnimationLocked(0);
6789 return true;
6790 }
6791 return false;
6792 }
6793
6794 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006795 StringBuilder sb = new StringBuilder(64);
Romain Guy06882f82009-06-10 13:36:04 -07006796
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006797 pw.print(prefix); pw.print("mSession="); pw.print(mSession);
6798 pw.print(" mClient="); pw.println(mClient.asBinder());
6799 pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
6800 if (mAttachedWindow != null || mLayoutAttached) {
6801 pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
6802 pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
6803 }
6804 if (mIsImWindow) {
6805 pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
6806 }
6807 pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
6808 pw.print(" mSubLayer="); pw.print(mSubLayer);
6809 pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
6810 pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
6811 : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)));
6812 pw.print("="); pw.print(mAnimLayer);
6813 pw.print(" mLastLayer="); pw.println(mLastLayer);
6814 if (mSurface != null) {
6815 pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
6816 }
6817 pw.print(prefix); pw.print("mToken="); pw.println(mToken);
6818 pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
6819 if (mAppToken != null) {
6820 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
6821 }
6822 if (mTargetAppToken != null) {
6823 pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken);
6824 }
6825 pw.print(prefix); pw.print("mViewVisibility=0x");
6826 pw.print(Integer.toHexString(mViewVisibility));
6827 pw.print(" mLastHidden="); pw.print(mLastHidden);
6828 pw.print(" mHaveFrame="); pw.println(mHaveFrame);
6829 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
6830 pw.print(prefix); pw.print("mPolicyVisibility=");
6831 pw.print(mPolicyVisibility);
6832 pw.print(" mPolicyVisibilityAfterAnim=");
6833 pw.print(mPolicyVisibilityAfterAnim);
6834 pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
6835 }
6836 pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
6837 pw.print(" h="); pw.print(mRequestedHeight);
6838 pw.print(" x="); pw.print(mReqXPos);
6839 pw.print(" y="); pw.println(mReqYPos);
6840 pw.print(prefix); pw.print("mGivenContentInsets=");
6841 mGivenContentInsets.printShortString(pw);
6842 pw.print(" mGivenVisibleInsets=");
6843 mGivenVisibleInsets.printShortString(pw);
6844 pw.println();
6845 if (mTouchableInsets != 0 || mGivenInsetsPending) {
6846 pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
6847 pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
6848 }
6849 pw.print(prefix); pw.print("mShownFrame=");
6850 mShownFrame.printShortString(pw);
6851 pw.print(" last="); mLastShownFrame.printShortString(pw);
6852 pw.println();
6853 pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
6854 pw.print(" last="); mLastFrame.printShortString(pw);
6855 pw.println();
6856 pw.print(prefix); pw.print("mContainingFrame=");
6857 mContainingFrame.printShortString(pw);
6858 pw.print(" mDisplayFrame=");
6859 mDisplayFrame.printShortString(pw);
6860 pw.println();
6861 pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw);
6862 pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw);
6863 pw.println();
6864 pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw);
6865 pw.print(" last="); mLastContentInsets.printShortString(pw);
6866 pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw);
6867 pw.print(" last="); mLastVisibleInsets.printShortString(pw);
6868 pw.println();
6869 if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
6870 pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
6871 pw.print(" mAlpha="); pw.print(mAlpha);
6872 pw.print(" mLastAlpha="); pw.println(mLastAlpha);
6873 }
6874 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
6875 || mAnimation != null) {
6876 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
6877 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
6878 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
6879 pw.print(" mAnimation="); pw.println(mAnimation);
6880 }
6881 if (mHasTransformation || mHasLocalTransformation) {
6882 pw.print(prefix); pw.print("XForm: has=");
6883 pw.print(mHasTransformation);
6884 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
6885 pw.print(" "); mTransformation.printShortString(pw);
6886 pw.println();
6887 }
6888 pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending);
6889 pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending);
6890 pw.print(" mReadyToShow="); pw.print(mReadyToShow);
6891 pw.print(" mHasDrawn="); pw.println(mHasDrawn);
6892 if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
6893 pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
6894 pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
6895 pw.print(" mDestroying="); pw.print(mDestroying);
6896 pw.print(" mRemoved="); pw.println(mRemoved);
6897 }
6898 if (mOrientationChanging || mAppFreezing) {
6899 pw.print(prefix); pw.print("mOrientationChanging=");
6900 pw.print(mOrientationChanging);
6901 pw.print(" mAppFreezing="); pw.println(mAppFreezing);
6902 }
Mitsuru Oshima589cebe2009-07-22 20:38:58 -07006903 if (mHScale != 1 || mVScale != 1) {
6904 pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
6905 pw.print(" mVScale="); pw.println(mVScale);
6906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006907 }
6908
6909 @Override
6910 public String toString() {
6911 return "Window{"
6912 + Integer.toHexString(System.identityHashCode(this))
6913 + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
6914 }
6915 }
Romain Guy06882f82009-06-10 13:36:04 -07006916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006917 // -------------------------------------------------------------
6918 // Window Token State
6919 // -------------------------------------------------------------
6920
6921 class WindowToken {
6922 // The actual token.
6923 final IBinder token;
6924
6925 // The type of window this token is for, as per WindowManager.LayoutParams.
6926 final int windowType;
Romain Guy06882f82009-06-10 13:36:04 -07006927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006928 // Set if this token was explicitly added by a client, so should
6929 // not be removed when all windows are removed.
6930 final boolean explicit;
Romain Guy06882f82009-06-10 13:36:04 -07006931
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006932 // For printing.
6933 String stringName;
Romain Guy06882f82009-06-10 13:36:04 -07006934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006935 // If this is an AppWindowToken, this is non-null.
6936 AppWindowToken appWindowToken;
Romain Guy06882f82009-06-10 13:36:04 -07006937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006938 // All of the windows associated with this token.
6939 final ArrayList<WindowState> windows = new ArrayList<WindowState>();
6940
6941 // Is key dispatching paused for this token?
6942 boolean paused = false;
6943
6944 // Should this token's windows be hidden?
6945 boolean hidden;
6946
6947 // Temporary for finding which tokens no longer have visible windows.
6948 boolean hasVisible;
6949
6950 WindowToken(IBinder _token, int type, boolean _explicit) {
6951 token = _token;
6952 windowType = type;
6953 explicit = _explicit;
6954 }
6955
6956 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006957 pw.print(prefix); pw.print("token="); pw.println(token);
6958 pw.print(prefix); pw.print("windows="); pw.println(windows);
6959 pw.print(prefix); pw.print("windowType="); pw.print(windowType);
6960 pw.print(" hidden="); pw.print(hidden);
6961 pw.print(" hasVisible="); pw.println(hasVisible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006962 }
6963
6964 @Override
6965 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006966 if (stringName == null) {
6967 StringBuilder sb = new StringBuilder();
6968 sb.append("WindowToken{");
6969 sb.append(Integer.toHexString(System.identityHashCode(this)));
6970 sb.append(" token="); sb.append(token); sb.append('}');
6971 stringName = sb.toString();
6972 }
6973 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006974 }
6975 };
6976
6977 class AppWindowToken extends WindowToken {
6978 // Non-null only for application tokens.
6979 final IApplicationToken appToken;
6980
6981 // All of the windows and child windows that are included in this
6982 // application token. Note this list is NOT sorted!
6983 final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
6984
6985 int groupId = -1;
6986 boolean appFullscreen;
6987 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Romain Guy06882f82009-06-10 13:36:04 -07006988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 // These are used for determining when all windows associated with
6990 // an activity have been drawn, so they can be made visible together
6991 // at the same time.
6992 int lastTransactionSequence = mTransactionSequence-1;
6993 int numInterestingWindows;
6994 int numDrawnWindows;
6995 boolean inPendingTransaction;
6996 boolean allDrawn;
Romain Guy06882f82009-06-10 13:36:04 -07006997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006998 // Is this token going to be hidden in a little while? If so, it
6999 // won't be taken into account for setting the screen orientation.
7000 boolean willBeHidden;
Romain Guy06882f82009-06-10 13:36:04 -07007001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007002 // Is this window's surface needed? This is almost like hidden, except
7003 // it will sometimes be true a little earlier: when the token has
7004 // been shown, but is still waiting for its app transition to execute
7005 // before making its windows shown.
7006 boolean hiddenRequested;
Romain Guy06882f82009-06-10 13:36:04 -07007007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007008 // Have we told the window clients to hide themselves?
7009 boolean clientHidden;
Romain Guy06882f82009-06-10 13:36:04 -07007010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007011 // Last visibility state we reported to the app token.
7012 boolean reportedVisible;
7013
7014 // Set to true when the token has been removed from the window mgr.
7015 boolean removed;
7016
7017 // Have we been asked to have this token keep the screen frozen?
7018 boolean freezingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07007019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 boolean animating;
7021 Animation animation;
7022 boolean hasTransformation;
7023 final Transformation transformation = new Transformation();
Romain Guy06882f82009-06-10 13:36:04 -07007024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007025 // Offset to the window of all layers in the token, for use by
7026 // AppWindowToken animations.
7027 int animLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -07007028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007029 // Information about an application starting window if displayed.
7030 StartingData startingData;
7031 WindowState startingWindow;
7032 View startingView;
7033 boolean startingDisplayed;
7034 boolean startingMoved;
7035 boolean firstWindowDrawn;
7036
7037 AppWindowToken(IApplicationToken _token) {
7038 super(_token.asBinder(),
7039 WindowManager.LayoutParams.TYPE_APPLICATION, true);
7040 appWindowToken = this;
7041 appToken = _token;
7042 }
Romain Guy06882f82009-06-10 13:36:04 -07007043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007044 public void setAnimation(Animation anim) {
7045 if (localLOGV) Log.v(
7046 TAG, "Setting animation in " + this + ": " + anim);
7047 animation = anim;
7048 animating = false;
7049 anim.restrictDuration(MAX_ANIMATION_DURATION);
7050 anim.scaleCurrentDuration(mTransitionAnimationScale);
7051 int zorder = anim.getZAdjustment();
7052 int adj = 0;
7053 if (zorder == Animation.ZORDER_TOP) {
7054 adj = TYPE_LAYER_OFFSET;
7055 } else if (zorder == Animation.ZORDER_BOTTOM) {
7056 adj = -TYPE_LAYER_OFFSET;
7057 }
Romain Guy06882f82009-06-10 13:36:04 -07007058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007059 if (animLayerAdjustment != adj) {
7060 animLayerAdjustment = adj;
7061 updateLayers();
7062 }
7063 }
Romain Guy06882f82009-06-10 13:36:04 -07007064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007065 public void setDummyAnimation() {
7066 if (animation == null) {
7067 if (localLOGV) Log.v(
7068 TAG, "Setting dummy animation in " + this);
7069 animation = sDummyAnimation;
7070 }
7071 }
7072
7073 public void clearAnimation() {
7074 if (animation != null) {
7075 animation = null;
7076 animating = true;
7077 }
7078 }
Romain Guy06882f82009-06-10 13:36:04 -07007079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007080 void updateLayers() {
7081 final int N = allAppWindows.size();
7082 final int adj = animLayerAdjustment;
7083 for (int i=0; i<N; i++) {
7084 WindowState w = allAppWindows.get(i);
7085 w.mAnimLayer = w.mLayer + adj;
7086 if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
7087 + w.mAnimLayer);
7088 if (w == mInputMethodTarget) {
7089 setInputMethodAnimLayerAdjustment(adj);
7090 }
7091 }
7092 }
Romain Guy06882f82009-06-10 13:36:04 -07007093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007094 void sendAppVisibilityToClients() {
7095 final int N = allAppWindows.size();
7096 for (int i=0; i<N; i++) {
7097 WindowState win = allAppWindows.get(i);
7098 if (win == startingWindow && clientHidden) {
7099 // Don't hide the starting window.
7100 continue;
7101 }
7102 try {
7103 if (DEBUG_VISIBILITY) Log.v(TAG,
7104 "Setting visibility of " + win + ": " + (!clientHidden));
7105 win.mClient.dispatchAppVisibility(!clientHidden);
7106 } catch (RemoteException e) {
7107 }
7108 }
7109 }
Romain Guy06882f82009-06-10 13:36:04 -07007110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007111 void showAllWindowsLocked() {
7112 final int NW = allAppWindows.size();
7113 for (int i=0; i<NW; i++) {
7114 WindowState w = allAppWindows.get(i);
7115 if (DEBUG_VISIBILITY) Log.v(TAG,
7116 "performing show on: " + w);
7117 w.performShowLocked();
7118 }
7119 }
Romain Guy06882f82009-06-10 13:36:04 -07007120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007121 // This must be called while inside a transaction.
7122 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
7123 if (!mDisplayFrozen) {
7124 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07007125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007126 if (animation == sDummyAnimation) {
7127 // This guy is going to animate, but not yet. For now count
7128 // it is not animating for purposes of scheduling transactions;
7129 // when it is really time to animate, this will be set to
7130 // a real animation and the next call will execute normally.
7131 return false;
7132 }
Romain Guy06882f82009-06-10 13:36:04 -07007133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007134 if ((allDrawn || animating || startingDisplayed) && animation != null) {
7135 if (!animating) {
7136 if (DEBUG_ANIM) Log.v(
7137 TAG, "Starting animation in " + this +
7138 " @ " + currentTime + ": dw=" + dw + " dh=" + dh
7139 + " scale=" + mTransitionAnimationScale
7140 + " allDrawn=" + allDrawn + " animating=" + animating);
7141 animation.initialize(dw, dh, dw, dh);
7142 animation.setStartTime(currentTime);
7143 animating = true;
7144 }
7145 transformation.clear();
7146 final boolean more = animation.getTransformation(
7147 currentTime, transformation);
7148 if (DEBUG_ANIM) Log.v(
7149 TAG, "Stepped animation in " + this +
7150 ": more=" + more + ", xform=" + transformation);
7151 if (more) {
7152 // we're done!
7153 hasTransformation = true;
7154 return true;
7155 }
7156 if (DEBUG_ANIM) Log.v(
7157 TAG, "Finished animation in " + this +
7158 " @ " + currentTime);
7159 animation = null;
7160 }
7161 } else if (animation != null) {
7162 // If the display is frozen, and there is a pending animation,
7163 // clear it and make sure we run the cleanup code.
7164 animating = true;
7165 animation = null;
7166 }
7167
7168 hasTransformation = false;
Romain Guy06882f82009-06-10 13:36:04 -07007169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007170 if (!animating) {
7171 return false;
7172 }
7173
7174 clearAnimation();
7175 animating = false;
7176 if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
7177 moveInputMethodWindowsIfNeededLocked(true);
7178 }
Romain Guy06882f82009-06-10 13:36:04 -07007179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007180 if (DEBUG_ANIM) Log.v(
7181 TAG, "Animation done in " + this
7182 + ": reportedVisible=" + reportedVisible);
7183
7184 transformation.clear();
7185 if (animLayerAdjustment != 0) {
7186 animLayerAdjustment = 0;
7187 updateLayers();
7188 }
Romain Guy06882f82009-06-10 13:36:04 -07007189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007190 final int N = windows.size();
7191 for (int i=0; i<N; i++) {
7192 ((WindowState)windows.get(i)).finishExit();
7193 }
7194 updateReportedVisibilityLocked();
Romain Guy06882f82009-06-10 13:36:04 -07007195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007196 return false;
7197 }
7198
7199 void updateReportedVisibilityLocked() {
7200 if (appToken == null) {
7201 return;
7202 }
Romain Guy06882f82009-06-10 13:36:04 -07007203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007204 int numInteresting = 0;
7205 int numVisible = 0;
7206 boolean nowGone = true;
Romain Guy06882f82009-06-10 13:36:04 -07007207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007208 if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
7209 final int N = allAppWindows.size();
7210 for (int i=0; i<N; i++) {
7211 WindowState win = allAppWindows.get(i);
7212 if (win == startingWindow || win.mAppFreezing) {
7213 continue;
7214 }
7215 if (DEBUG_VISIBILITY) {
7216 Log.v(TAG, "Win " + win + ": isDisplayed="
7217 + win.isDisplayedLw()
7218 + ", isAnimating=" + win.isAnimating());
7219 if (!win.isDisplayedLw()) {
7220 Log.v(TAG, "Not displayed: s=" + win.mSurface
7221 + " pv=" + win.mPolicyVisibility
7222 + " dp=" + win.mDrawPending
7223 + " cdp=" + win.mCommitDrawPending
7224 + " ah=" + win.mAttachedHidden
7225 + " th="
7226 + (win.mAppToken != null
7227 ? win.mAppToken.hiddenRequested : false)
7228 + " a=" + win.mAnimating);
7229 }
7230 }
7231 numInteresting++;
7232 if (win.isDisplayedLw()) {
7233 if (!win.isAnimating()) {
7234 numVisible++;
7235 }
7236 nowGone = false;
7237 } else if (win.isAnimating()) {
7238 nowGone = false;
7239 }
7240 }
Romain Guy06882f82009-06-10 13:36:04 -07007241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007242 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
7243 if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
7244 + numInteresting + " visible=" + numVisible);
7245 if (nowVisible != reportedVisible) {
7246 if (DEBUG_VISIBILITY) Log.v(
7247 TAG, "Visibility changed in " + this
7248 + ": vis=" + nowVisible);
7249 reportedVisible = nowVisible;
7250 Message m = mH.obtainMessage(
7251 H.REPORT_APPLICATION_TOKEN_WINDOWS,
7252 nowVisible ? 1 : 0,
7253 nowGone ? 1 : 0,
7254 this);
7255 mH.sendMessage(m);
7256 }
7257 }
Romain Guy06882f82009-06-10 13:36:04 -07007258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007259 void dump(PrintWriter pw, String prefix) {
7260 super.dump(pw, prefix);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007261 if (appToken != null) {
7262 pw.print(prefix); pw.println("app=true");
7263 }
7264 if (allAppWindows.size() > 0) {
7265 pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
7266 }
7267 pw.print(prefix); pw.print("groupId="); pw.print(groupId);
7268 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
7269 pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
7270 pw.print(" clientHidden="); pw.print(clientHidden);
7271 pw.print(" willBeHidden="); pw.print(willBeHidden);
7272 pw.print(" reportedVisible="); pw.println(reportedVisible);
7273 if (paused || freezingScreen) {
7274 pw.print(prefix); pw.print("paused="); pw.print(paused);
7275 pw.print(" freezingScreen="); pw.println(freezingScreen);
7276 }
7277 if (numInterestingWindows != 0 || numDrawnWindows != 0
7278 || inPendingTransaction || allDrawn) {
7279 pw.print(prefix); pw.print("numInterestingWindows=");
7280 pw.print(numInterestingWindows);
7281 pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
7282 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
7283 pw.print(" allDrawn="); pw.println(allDrawn);
7284 }
7285 if (animating || animation != null) {
7286 pw.print(prefix); pw.print("animating="); pw.print(animating);
7287 pw.print(" animation="); pw.println(animation);
7288 }
7289 if (animLayerAdjustment != 0) {
7290 pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
7291 }
7292 if (hasTransformation) {
7293 pw.print(prefix); pw.print("hasTransformation="); pw.print(hasTransformation);
7294 pw.print(" transformation="); transformation.printShortString(pw);
7295 pw.println();
7296 }
7297 if (startingData != null || removed || firstWindowDrawn) {
7298 pw.print(prefix); pw.print("startingData="); pw.print(startingData);
7299 pw.print(" removed="); pw.print(removed);
7300 pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
7301 }
7302 if (startingWindow != null || startingView != null
7303 || startingDisplayed || startingMoved) {
7304 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
7305 pw.print(" startingView="); pw.print(startingView);
7306 pw.print(" startingDisplayed="); pw.print(startingDisplayed);
7307 pw.print(" startingMoved"); pw.println(startingMoved);
7308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007309 }
7310
7311 @Override
7312 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007313 if (stringName == null) {
7314 StringBuilder sb = new StringBuilder();
7315 sb.append("AppWindowToken{");
7316 sb.append(Integer.toHexString(System.identityHashCode(this)));
7317 sb.append(" token="); sb.append(token); sb.append('}');
7318 stringName = sb.toString();
7319 }
7320 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007321 }
7322 }
Romain Guy06882f82009-06-10 13:36:04 -07007323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007324 public static WindowManager.LayoutParams findAnimations(
7325 ArrayList<AppWindowToken> order,
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007326 ArrayList<AppWindowToken> openingTokenList1,
7327 ArrayList<AppWindowToken> closingTokenList2) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007328 // We need to figure out which animation to use...
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007329
7330 // First, check if there is a compatible window in opening/closing
7331 // apps, and use it if exists.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007332 WindowManager.LayoutParams animParams = null;
7333 int animSrc = 0;
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007334 animParams = findCompatibleWindowParams(openingTokenList1);
7335 if (animParams == null) {
7336 animParams = findCompatibleWindowParams(closingTokenList2);
7337 }
7338 if (animParams != null) {
7339 return animParams;
7340 }
7341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007342 //Log.i(TAG, "Looking for animations...");
7343 for (int i=order.size()-1; i>=0; i--) {
7344 AppWindowToken wtoken = order.get(i);
7345 //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007346 if (openingTokenList1.contains(wtoken) || closingTokenList2.contains(wtoken)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007347 int j = wtoken.windows.size();
7348 while (j > 0) {
7349 j--;
7350 WindowState win = wtoken.windows.get(j);
7351 //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
7352 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
7353 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
7354 //Log.i(TAG, "Found base or application window, done!");
7355 if (wtoken.appFullscreen) {
7356 return win.mAttrs;
7357 }
7358 if (animSrc < 2) {
7359 animParams = win.mAttrs;
7360 animSrc = 2;
7361 }
7362 } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
7363 //Log.i(TAG, "Found normal window, we may use this...");
7364 animParams = win.mAttrs;
7365 animSrc = 1;
7366 }
7367 }
7368 }
7369 }
Romain Guy06882f82009-06-10 13:36:04 -07007370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007371 return animParams;
7372 }
Romain Guy06882f82009-06-10 13:36:04 -07007373
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07007374 private static LayoutParams findCompatibleWindowParams(ArrayList<AppWindowToken> tokenList) {
7375 for (int appCount = tokenList.size() - 1; appCount >= 0; appCount--) {
7376 AppWindowToken wtoken = tokenList.get(appCount);
7377 // Just checking one window is sufficient as all windows have the compatible flag
7378 // if the application is in compatibility mode.
7379 if (wtoken.windows.size() > 0) {
7380 WindowManager.LayoutParams params = wtoken.windows.get(0).mAttrs;
7381 if ((params.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
7382 return params;
7383 }
7384 }
7385 }
7386 return null;
7387 }
7388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007389 // -------------------------------------------------------------
7390 // DummyAnimation
7391 // -------------------------------------------------------------
7392
7393 // This is an animation that does nothing: it just immediately finishes
7394 // itself every time it is called. It is used as a stub animation in cases
7395 // where we want to synchronize multiple things that may be animating.
7396 static final class DummyAnimation extends Animation {
7397 public boolean getTransformation(long currentTime, Transformation outTransformation) {
7398 return false;
7399 }
7400 }
7401 static final Animation sDummyAnimation = new DummyAnimation();
Romain Guy06882f82009-06-10 13:36:04 -07007402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007403 // -------------------------------------------------------------
7404 // Async Handler
7405 // -------------------------------------------------------------
7406
7407 static final class StartingData {
7408 final String pkg;
7409 final int theme;
7410 final CharSequence nonLocalizedLabel;
7411 final int labelRes;
7412 final int icon;
Romain Guy06882f82009-06-10 13:36:04 -07007413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007414 StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
7415 int _labelRes, int _icon) {
7416 pkg = _pkg;
7417 theme = _theme;
7418 nonLocalizedLabel = _nonLocalizedLabel;
7419 labelRes = _labelRes;
7420 icon = _icon;
7421 }
7422 }
7423
7424 private final class H extends Handler {
7425 public static final int REPORT_FOCUS_CHANGE = 2;
7426 public static final int REPORT_LOSING_FOCUS = 3;
7427 public static final int ANIMATE = 4;
7428 public static final int ADD_STARTING = 5;
7429 public static final int REMOVE_STARTING = 6;
7430 public static final int FINISHED_STARTING = 7;
7431 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007432 public static final int WINDOW_FREEZE_TIMEOUT = 11;
7433 public static final int HOLD_SCREEN_CHANGED = 12;
7434 public static final int APP_TRANSITION_TIMEOUT = 13;
7435 public static final int PERSIST_ANIMATION_SCALE = 14;
7436 public static final int FORCE_GC = 15;
7437 public static final int ENABLE_SCREEN = 16;
7438 public static final int APP_FREEZE_TIMEOUT = 17;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007439 public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
Romain Guy06882f82009-06-10 13:36:04 -07007440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007441 private Session mLastReportedHold;
Romain Guy06882f82009-06-10 13:36:04 -07007442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007443 public H() {
7444 }
Romain Guy06882f82009-06-10 13:36:04 -07007445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007446 @Override
7447 public void handleMessage(Message msg) {
7448 switch (msg.what) {
7449 case REPORT_FOCUS_CHANGE: {
7450 WindowState lastFocus;
7451 WindowState newFocus;
Romain Guy06882f82009-06-10 13:36:04 -07007452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007453 synchronized(mWindowMap) {
7454 lastFocus = mLastFocus;
7455 newFocus = mCurrentFocus;
7456 if (lastFocus == newFocus) {
7457 // Focus is not changing, so nothing to do.
7458 return;
7459 }
7460 mLastFocus = newFocus;
7461 //Log.i(TAG, "Focus moving from " + lastFocus
7462 // + " to " + newFocus);
7463 if (newFocus != null && lastFocus != null
7464 && !newFocus.isDisplayedLw()) {
7465 //Log.i(TAG, "Delaying loss of focus...");
7466 mLosingFocus.add(lastFocus);
7467 lastFocus = null;
7468 }
7469 }
7470
7471 if (lastFocus != newFocus) {
7472 //System.out.println("Changing focus from " + lastFocus
7473 // + " to " + newFocus);
7474 if (newFocus != null) {
7475 try {
7476 //Log.i(TAG, "Gaining focus: " + newFocus);
7477 newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7478 } catch (RemoteException e) {
7479 // Ignore if process has died.
7480 }
7481 }
7482
7483 if (lastFocus != null) {
7484 try {
7485 //Log.i(TAG, "Losing focus: " + lastFocus);
7486 lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7487 } catch (RemoteException e) {
7488 // Ignore if process has died.
7489 }
7490 }
7491 }
7492 } break;
7493
7494 case REPORT_LOSING_FOCUS: {
7495 ArrayList<WindowState> losers;
Romain Guy06882f82009-06-10 13:36:04 -07007496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007497 synchronized(mWindowMap) {
7498 losers = mLosingFocus;
7499 mLosingFocus = new ArrayList<WindowState>();
7500 }
7501
7502 final int N = losers.size();
7503 for (int i=0; i<N; i++) {
7504 try {
7505 //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
7506 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7507 } catch (RemoteException e) {
7508 // Ignore if process has died.
7509 }
7510 }
7511 } break;
7512
7513 case ANIMATE: {
7514 synchronized(mWindowMap) {
7515 mAnimationPending = false;
7516 performLayoutAndPlaceSurfacesLocked();
7517 }
7518 } break;
7519
7520 case ADD_STARTING: {
7521 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7522 final StartingData sd = wtoken.startingData;
7523
7524 if (sd == null) {
7525 // Animation has been canceled... do nothing.
7526 return;
7527 }
Romain Guy06882f82009-06-10 13:36:04 -07007528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007529 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
7530 + wtoken + ": pkg=" + sd.pkg);
Romain Guy06882f82009-06-10 13:36:04 -07007531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007532 View view = null;
7533 try {
7534 view = mPolicy.addStartingWindow(
7535 wtoken.token, sd.pkg,
7536 sd.theme, sd.nonLocalizedLabel, sd.labelRes,
7537 sd.icon);
7538 } catch (Exception e) {
7539 Log.w(TAG, "Exception when adding starting window", e);
7540 }
7541
7542 if (view != null) {
7543 boolean abort = false;
7544
7545 synchronized(mWindowMap) {
7546 if (wtoken.removed || wtoken.startingData == null) {
7547 // If the window was successfully added, then
7548 // we need to remove it.
7549 if (wtoken.startingWindow != null) {
7550 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7551 "Aborted starting " + wtoken
7552 + ": removed=" + wtoken.removed
7553 + " startingData=" + wtoken.startingData);
7554 wtoken.startingWindow = null;
7555 wtoken.startingData = null;
7556 abort = true;
7557 }
7558 } else {
7559 wtoken.startingView = view;
7560 }
7561 if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
7562 "Added starting " + wtoken
7563 + ": startingWindow="
7564 + wtoken.startingWindow + " startingView="
7565 + wtoken.startingView);
7566 }
7567
7568 if (abort) {
7569 try {
7570 mPolicy.removeStartingWindow(wtoken.token, view);
7571 } catch (Exception e) {
7572 Log.w(TAG, "Exception when removing starting window", e);
7573 }
7574 }
7575 }
7576 } break;
7577
7578 case REMOVE_STARTING: {
7579 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7580 IBinder token = null;
7581 View view = null;
7582 synchronized (mWindowMap) {
7583 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
7584 + wtoken + ": startingWindow="
7585 + wtoken.startingWindow + " startingView="
7586 + wtoken.startingView);
7587 if (wtoken.startingWindow != null) {
7588 view = wtoken.startingView;
7589 token = wtoken.token;
7590 wtoken.startingData = null;
7591 wtoken.startingView = null;
7592 wtoken.startingWindow = null;
7593 }
7594 }
7595 if (view != null) {
7596 try {
7597 mPolicy.removeStartingWindow(token, view);
7598 } catch (Exception e) {
7599 Log.w(TAG, "Exception when removing starting window", e);
7600 }
7601 }
7602 } break;
7603
7604 case FINISHED_STARTING: {
7605 IBinder token = null;
7606 View view = null;
7607 while (true) {
7608 synchronized (mWindowMap) {
7609 final int N = mFinishedStarting.size();
7610 if (N <= 0) {
7611 break;
7612 }
7613 AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7614
7615 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7616 "Finished starting " + wtoken
7617 + ": startingWindow=" + wtoken.startingWindow
7618 + " startingView=" + wtoken.startingView);
7619
7620 if (wtoken.startingWindow == null) {
7621 continue;
7622 }
7623
7624 view = wtoken.startingView;
7625 token = wtoken.token;
7626 wtoken.startingData = null;
7627 wtoken.startingView = null;
7628 wtoken.startingWindow = null;
7629 }
7630
7631 try {
7632 mPolicy.removeStartingWindow(token, view);
7633 } catch (Exception e) {
7634 Log.w(TAG, "Exception when removing starting window", e);
7635 }
7636 }
7637 } break;
7638
7639 case REPORT_APPLICATION_TOKEN_WINDOWS: {
7640 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7641
7642 boolean nowVisible = msg.arg1 != 0;
7643 boolean nowGone = msg.arg2 != 0;
7644
7645 try {
7646 if (DEBUG_VISIBILITY) Log.v(
7647 TAG, "Reporting visible in " + wtoken
7648 + " visible=" + nowVisible
7649 + " gone=" + nowGone);
7650 if (nowVisible) {
7651 wtoken.appToken.windowsVisible();
7652 } else {
7653 wtoken.appToken.windowsGone();
7654 }
7655 } catch (RemoteException ex) {
7656 }
7657 } break;
Romain Guy06882f82009-06-10 13:36:04 -07007658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007659 case WINDOW_FREEZE_TIMEOUT: {
7660 synchronized (mWindowMap) {
7661 Log.w(TAG, "Window freeze timeout expired.");
7662 int i = mWindows.size();
7663 while (i > 0) {
7664 i--;
7665 WindowState w = (WindowState)mWindows.get(i);
7666 if (w.mOrientationChanging) {
7667 w.mOrientationChanging = false;
7668 Log.w(TAG, "Force clearing orientation change: " + w);
7669 }
7670 }
7671 performLayoutAndPlaceSurfacesLocked();
7672 }
7673 break;
7674 }
Romain Guy06882f82009-06-10 13:36:04 -07007675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007676 case HOLD_SCREEN_CHANGED: {
7677 Session oldHold;
7678 Session newHold;
7679 synchronized (mWindowMap) {
7680 oldHold = mLastReportedHold;
7681 newHold = (Session)msg.obj;
7682 mLastReportedHold = newHold;
7683 }
Romain Guy06882f82009-06-10 13:36:04 -07007684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007685 if (oldHold != newHold) {
7686 try {
7687 if (oldHold != null) {
7688 mBatteryStats.noteStopWakelock(oldHold.mUid,
7689 "window",
7690 BatteryStats.WAKE_TYPE_WINDOW);
7691 }
7692 if (newHold != null) {
7693 mBatteryStats.noteStartWakelock(newHold.mUid,
7694 "window",
7695 BatteryStats.WAKE_TYPE_WINDOW);
7696 }
7697 } catch (RemoteException e) {
7698 }
7699 }
7700 break;
7701 }
Romain Guy06882f82009-06-10 13:36:04 -07007702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007703 case APP_TRANSITION_TIMEOUT: {
7704 synchronized (mWindowMap) {
7705 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
7706 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7707 "*** APP TRANSITION TIMEOUT");
7708 mAppTransitionReady = true;
7709 mAppTransitionTimeout = true;
7710 performLayoutAndPlaceSurfacesLocked();
7711 }
7712 }
7713 break;
7714 }
Romain Guy06882f82009-06-10 13:36:04 -07007715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007716 case PERSIST_ANIMATION_SCALE: {
7717 Settings.System.putFloat(mContext.getContentResolver(),
7718 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7719 Settings.System.putFloat(mContext.getContentResolver(),
7720 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7721 break;
7722 }
Romain Guy06882f82009-06-10 13:36:04 -07007723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 case FORCE_GC: {
7725 synchronized(mWindowMap) {
7726 if (mAnimationPending) {
7727 // If we are animating, don't do the gc now but
7728 // delay a bit so we don't interrupt the animation.
7729 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7730 2000);
7731 return;
7732 }
7733 // If we are currently rotating the display, it will
7734 // schedule a new message when done.
7735 if (mDisplayFrozen) {
7736 return;
7737 }
7738 mFreezeGcPending = 0;
7739 }
7740 Runtime.getRuntime().gc();
7741 break;
7742 }
Romain Guy06882f82009-06-10 13:36:04 -07007743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007744 case ENABLE_SCREEN: {
7745 performEnableScreen();
7746 break;
7747 }
Romain Guy06882f82009-06-10 13:36:04 -07007748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007749 case APP_FREEZE_TIMEOUT: {
7750 synchronized (mWindowMap) {
7751 Log.w(TAG, "App freeze timeout expired.");
7752 int i = mAppTokens.size();
7753 while (i > 0) {
7754 i--;
7755 AppWindowToken tok = mAppTokens.get(i);
7756 if (tok.freezingScreen) {
7757 Log.w(TAG, "Force clearing freeze: " + tok);
7758 unsetAppFreezingScreenLocked(tok, true, true);
7759 }
7760 }
7761 }
7762 break;
7763 }
Romain Guy06882f82009-06-10 13:36:04 -07007764
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007765 case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
Dianne Hackborncfaef692009-06-15 14:24:44 -07007766 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007767 sendNewConfiguration();
7768 }
7769 break;
7770 }
Romain Guy06882f82009-06-10 13:36:04 -07007771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007772 }
7773 }
7774 }
7775
7776 // -------------------------------------------------------------
7777 // IWindowManager API
7778 // -------------------------------------------------------------
7779
7780 public IWindowSession openSession(IInputMethodClient client,
7781 IInputContext inputContext) {
7782 if (client == null) throw new IllegalArgumentException("null client");
7783 if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7784 return new Session(client, inputContext);
7785 }
7786
7787 public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7788 synchronized (mWindowMap) {
7789 // The focus for the client is the window immediately below
7790 // where we would place the input method window.
7791 int idx = findDesiredInputMethodWindowIndexLocked(false);
7792 WindowState imFocus;
7793 if (idx > 0) {
7794 imFocus = (WindowState)mWindows.get(idx-1);
7795 if (imFocus != null) {
7796 if (imFocus.mSession.mClient != null &&
7797 imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7798 return true;
7799 }
7800 }
7801 }
7802 }
7803 return false;
7804 }
Romain Guy06882f82009-06-10 13:36:04 -07007805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007806 // -------------------------------------------------------------
7807 // Internals
7808 // -------------------------------------------------------------
7809
7810 final WindowState windowForClientLocked(Session session, IWindow client) {
7811 return windowForClientLocked(session, client.asBinder());
7812 }
Romain Guy06882f82009-06-10 13:36:04 -07007813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007814 final WindowState windowForClientLocked(Session session, IBinder client) {
7815 WindowState win = mWindowMap.get(client);
7816 if (localLOGV) Log.v(
7817 TAG, "Looking up client " + client + ": " + win);
7818 if (win == null) {
7819 RuntimeException ex = new RuntimeException();
7820 Log.w(TAG, "Requested window " + client + " does not exist", ex);
7821 return null;
7822 }
7823 if (session != null && win.mSession != session) {
7824 RuntimeException ex = new RuntimeException();
7825 Log.w(TAG, "Requested window " + client + " is in session " +
7826 win.mSession + ", not " + session, ex);
7827 return null;
7828 }
7829
7830 return win;
7831 }
7832
7833 private final void assignLayersLocked() {
7834 int N = mWindows.size();
7835 int curBaseLayer = 0;
7836 int curLayer = 0;
7837 int i;
Romain Guy06882f82009-06-10 13:36:04 -07007838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007839 for (i=0; i<N; i++) {
7840 WindowState w = (WindowState)mWindows.get(i);
7841 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
7842 curLayer += WINDOW_LAYER_MULTIPLIER;
7843 w.mLayer = curLayer;
7844 } else {
7845 curBaseLayer = curLayer = w.mBaseLayer;
7846 w.mLayer = curLayer;
7847 }
7848 if (w.mTargetAppToken != null) {
7849 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
7850 } else if (w.mAppToken != null) {
7851 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
7852 } else {
7853 w.mAnimLayer = w.mLayer;
7854 }
7855 if (w.mIsImWindow) {
7856 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
7857 }
7858 if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
7859 + w.mAnimLayer);
7860 //System.out.println(
7861 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7862 }
7863 }
7864
7865 private boolean mInLayout = false;
7866 private final void performLayoutAndPlaceSurfacesLocked() {
7867 if (mInLayout) {
Dave Bortcfe65242009-04-09 14:51:04 -07007868 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007869 throw new RuntimeException("Recursive call!");
7870 }
7871 Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7872 return;
7873 }
7874
7875 boolean recoveringMemory = false;
7876 if (mForceRemoves != null) {
7877 recoveringMemory = true;
7878 // Wait a little it for things to settle down, and off we go.
7879 for (int i=0; i<mForceRemoves.size(); i++) {
7880 WindowState ws = mForceRemoves.get(i);
7881 Log.i(TAG, "Force removing: " + ws);
7882 removeWindowInnerLocked(ws.mSession, ws);
7883 }
7884 mForceRemoves = null;
7885 Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
7886 Object tmp = new Object();
7887 synchronized (tmp) {
7888 try {
7889 tmp.wait(250);
7890 } catch (InterruptedException e) {
7891 }
7892 }
7893 }
Romain Guy06882f82009-06-10 13:36:04 -07007894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007895 mInLayout = true;
7896 try {
7897 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
Romain Guy06882f82009-06-10 13:36:04 -07007898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007899 int i = mPendingRemove.size()-1;
7900 if (i >= 0) {
7901 while (i >= 0) {
7902 WindowState w = mPendingRemove.get(i);
7903 removeWindowInnerLocked(w.mSession, w);
7904 i--;
7905 }
7906 mPendingRemove.clear();
7907
7908 mInLayout = false;
7909 assignLayersLocked();
7910 mLayoutNeeded = true;
7911 performLayoutAndPlaceSurfacesLocked();
7912
7913 } else {
7914 mInLayout = false;
7915 if (mLayoutNeeded) {
7916 requestAnimationLocked(0);
7917 }
7918 }
7919 } catch (RuntimeException e) {
7920 mInLayout = false;
7921 Log.e(TAG, "Unhandled exception while layout out windows", e);
7922 }
7923 }
7924
7925 private final void performLayoutLockedInner() {
7926 final int dw = mDisplay.getWidth();
7927 final int dh = mDisplay.getHeight();
7928
7929 final int N = mWindows.size();
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007930 int repeats = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007931 int i;
7932
7933 // FIRST LOOP: Perform a layout, if needed.
Romain Guy06882f82009-06-10 13:36:04 -07007934
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007935 while (mLayoutNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007936 mPolicy.beginLayoutLw(dw, dh);
7937
7938 // First perform layout of any root windows (not attached
7939 // to another window).
7940 int topAttached = -1;
7941 for (i = N-1; i >= 0; i--) {
7942 WindowState win = (WindowState) mWindows.get(i);
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007943
7944 // Don't do layout of a window if it is not visible, or
7945 // soon won't be visible, to avoid wasting time and funky
7946 // changes while a window is animating away.
7947 final AppWindowToken atoken = win.mAppToken;
7948 final boolean gone = win.mViewVisibility == View.GONE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007949 || !win.mRelayoutCalled
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007950 || win.mRootToken.hidden
7951 || (atoken != null && atoken.hiddenRequested)
7952 || !win.mPolicyVisibility
7953 || win.mAttachedHidden
7954 || win.mExiting || win.mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007955
7956 // If this view is GONE, then skip it -- keep the current
7957 // frame, and let the caller know so they can ignore it
7958 // if they want. (We do the normal layout for INVISIBLE
7959 // windows, since that means "perform layout as normal,
7960 // just don't display").
7961 if (!gone || !win.mHaveFrame) {
7962 if (!win.mLayoutAttached) {
7963 mPolicy.layoutWindowLw(win, win.mAttrs, null);
7964 } else {
7965 if (topAttached < 0) topAttached = i;
7966 }
7967 }
7968 }
Romain Guy06882f82009-06-10 13:36:04 -07007969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007970 // Now perform layout of attached windows, which usually
7971 // depend on the position of the window they are attached to.
7972 // XXX does not deal with windows that are attached to windows
7973 // that are themselves attached.
7974 for (i = topAttached; i >= 0; i--) {
7975 WindowState win = (WindowState) mWindows.get(i);
7976
7977 // If this view is GONE, then skip it -- keep the current
7978 // frame, and let the caller know so they can ignore it
7979 // if they want. (We do the normal layout for INVISIBLE
7980 // windows, since that means "perform layout as normal,
7981 // just don't display").
7982 if (win.mLayoutAttached) {
7983 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7984 || !win.mHaveFrame) {
7985 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7986 }
7987 }
7988 }
7989
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007990 if (!mPolicy.finishLayoutLw()) {
7991 mLayoutNeeded = false;
7992 } else if (repeats > 2) {
7993 Log.w(TAG, "Layout repeat aborted after too many iterations");
7994 mLayoutNeeded = false;
7995 } else {
7996 repeats++;
7997 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007998 }
7999 }
Romain Guy06882f82009-06-10 13:36:04 -07008000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008001 private final void performLayoutAndPlaceSurfacesLockedInner(
8002 boolean recoveringMemory) {
8003 final long currentTime = SystemClock.uptimeMillis();
8004 final int dw = mDisplay.getWidth();
8005 final int dh = mDisplay.getHeight();
8006
8007 final int N = mWindows.size();
8008 int i;
8009
8010 // FIRST LOOP: Perform a layout, if needed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008011 performLayoutLockedInner();
Romain Guy06882f82009-06-10 13:36:04 -07008012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008013 if (mFxSession == null) {
8014 mFxSession = new SurfaceSession();
8015 }
Romain Guy06882f82009-06-10 13:36:04 -07008016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008017 if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
8018
8019 // Initialize state of exiting tokens.
8020 for (i=mExitingTokens.size()-1; i>=0; i--) {
8021 mExitingTokens.get(i).hasVisible = false;
8022 }
8023
8024 // Initialize state of exiting applications.
8025 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8026 mExitingAppTokens.get(i).hasVisible = false;
8027 }
8028
8029 // SECOND LOOP: Execute animations and update visibility of windows.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008030 boolean orientationChangeComplete = true;
8031 Session holdScreen = null;
8032 float screenBrightness = -1;
8033 boolean focusDisplayed = false;
8034 boolean animating = false;
8035
8036 Surface.openTransaction();
8037 try {
8038 boolean restart;
8039
8040 do {
8041 final int transactionSequence = ++mTransactionSequence;
8042
8043 // Update animations of all applications, including those
8044 // associated with exiting/removed apps
8045 boolean tokensAnimating = false;
8046 final int NAT = mAppTokens.size();
8047 for (i=0; i<NAT; i++) {
8048 if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
8049 tokensAnimating = true;
8050 }
8051 }
8052 final int NEAT = mExitingAppTokens.size();
8053 for (i=0; i<NEAT; i++) {
8054 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
8055 tokensAnimating = true;
8056 }
8057 }
8058
8059 animating = tokensAnimating;
8060 restart = false;
8061
8062 boolean tokenMayBeDrawn = false;
8063
8064 mPolicy.beginAnimationLw(dw, dh);
8065
8066 for (i=N-1; i>=0; i--) {
8067 WindowState w = (WindowState)mWindows.get(i);
8068
8069 final WindowManager.LayoutParams attrs = w.mAttrs;
8070
8071 if (w.mSurface != null) {
8072 // Execute animation.
8073 w.commitFinishDrawingLocked(currentTime);
8074 if (w.stepAnimationLocked(currentTime, dw, dh)) {
8075 animating = true;
8076 //w.dump(" ");
8077 }
8078
8079 mPolicy.animatingWindowLw(w, attrs);
8080 }
8081
8082 final AppWindowToken atoken = w.mAppToken;
8083 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
8084 if (atoken.lastTransactionSequence != transactionSequence) {
8085 atoken.lastTransactionSequence = transactionSequence;
8086 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
8087 atoken.startingDisplayed = false;
8088 }
8089 if ((w.isOnScreen() || w.mAttrs.type
8090 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
8091 && !w.mExiting && !w.mDestroying) {
8092 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
8093 Log.v(TAG, "Eval win " + w + ": isDisplayed="
8094 + w.isDisplayedLw()
8095 + ", isAnimating=" + w.isAnimating());
8096 if (!w.isDisplayedLw()) {
8097 Log.v(TAG, "Not displayed: s=" + w.mSurface
8098 + " pv=" + w.mPolicyVisibility
8099 + " dp=" + w.mDrawPending
8100 + " cdp=" + w.mCommitDrawPending
8101 + " ah=" + w.mAttachedHidden
8102 + " th=" + atoken.hiddenRequested
8103 + " a=" + w.mAnimating);
8104 }
8105 }
8106 if (w != atoken.startingWindow) {
8107 if (!atoken.freezingScreen || !w.mAppFreezing) {
8108 atoken.numInterestingWindows++;
8109 if (w.isDisplayedLw()) {
8110 atoken.numDrawnWindows++;
8111 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
8112 "tokenMayBeDrawn: " + atoken
8113 + " freezingScreen=" + atoken.freezingScreen
8114 + " mAppFreezing=" + w.mAppFreezing);
8115 tokenMayBeDrawn = true;
8116 }
8117 }
8118 } else if (w.isDisplayedLw()) {
8119 atoken.startingDisplayed = true;
8120 }
8121 }
8122 } else if (w.mReadyToShow) {
8123 w.performShowLocked();
8124 }
8125 }
8126
8127 if (mPolicy.finishAnimationLw()) {
8128 restart = true;
8129 }
8130
8131 if (tokenMayBeDrawn) {
8132 // See if any windows have been drawn, so they (and others
8133 // associated with them) can now be shown.
8134 final int NT = mTokenList.size();
8135 for (i=0; i<NT; i++) {
8136 AppWindowToken wtoken = mTokenList.get(i).appWindowToken;
8137 if (wtoken == null) {
8138 continue;
8139 }
8140 if (wtoken.freezingScreen) {
8141 int numInteresting = wtoken.numInterestingWindows;
8142 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8143 if (DEBUG_VISIBILITY) Log.v(TAG,
8144 "allDrawn: " + wtoken
8145 + " interesting=" + numInteresting
8146 + " drawn=" + wtoken.numDrawnWindows);
8147 wtoken.showAllWindowsLocked();
8148 unsetAppFreezingScreenLocked(wtoken, false, true);
8149 orientationChangeComplete = true;
8150 }
8151 } else if (!wtoken.allDrawn) {
8152 int numInteresting = wtoken.numInterestingWindows;
8153 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8154 if (DEBUG_VISIBILITY) Log.v(TAG,
8155 "allDrawn: " + wtoken
8156 + " interesting=" + numInteresting
8157 + " drawn=" + wtoken.numDrawnWindows);
8158 wtoken.allDrawn = true;
8159 restart = true;
8160
8161 // We can now show all of the drawn windows!
8162 if (!mOpeningApps.contains(wtoken)) {
8163 wtoken.showAllWindowsLocked();
8164 }
8165 }
8166 }
8167 }
8168 }
8169
8170 // If we are ready to perform an app transition, check through
8171 // all of the app tokens to be shown and see if they are ready
8172 // to go.
8173 if (mAppTransitionReady) {
8174 int NN = mOpeningApps.size();
8175 boolean goodToGo = true;
8176 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8177 "Checking " + NN + " opening apps (frozen="
8178 + mDisplayFrozen + " timeout="
8179 + mAppTransitionTimeout + ")...");
8180 if (!mDisplayFrozen && !mAppTransitionTimeout) {
8181 // If the display isn't frozen, wait to do anything until
8182 // all of the apps are ready. Otherwise just go because
8183 // we'll unfreeze the display when everyone is ready.
8184 for (i=0; i<NN && goodToGo; i++) {
8185 AppWindowToken wtoken = mOpeningApps.get(i);
8186 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8187 "Check opening app" + wtoken + ": allDrawn="
8188 + wtoken.allDrawn + " startingDisplayed="
8189 + wtoken.startingDisplayed);
8190 if (!wtoken.allDrawn && !wtoken.startingDisplayed
8191 && !wtoken.startingMoved) {
8192 goodToGo = false;
8193 }
8194 }
8195 }
8196 if (goodToGo) {
8197 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
8198 int transit = mNextAppTransition;
8199 if (mSkipAppTransitionAnimation) {
8200 transit = WindowManagerPolicy.TRANSIT_NONE;
8201 }
8202 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8203 mAppTransitionReady = false;
8204 mAppTransitionTimeout = false;
8205 mStartingIconInTransition = false;
8206 mSkipAppTransitionAnimation = false;
8207
8208 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8209
8210 // We need to figure out which animation to use...
8211 WindowManager.LayoutParams lp = findAnimations(mAppTokens,
8212 mOpeningApps, mClosingApps);
8213
8214 NN = mOpeningApps.size();
8215 for (i=0; i<NN; i++) {
8216 AppWindowToken wtoken = mOpeningApps.get(i);
8217 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8218 "Now opening app" + wtoken);
8219 wtoken.reportedVisible = false;
8220 wtoken.inPendingTransaction = false;
8221 setTokenVisibilityLocked(wtoken, lp, true, transit, false);
8222 wtoken.updateReportedVisibilityLocked();
8223 wtoken.showAllWindowsLocked();
8224 }
8225 NN = mClosingApps.size();
8226 for (i=0; i<NN; i++) {
8227 AppWindowToken wtoken = mClosingApps.get(i);
8228 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8229 "Now closing app" + wtoken);
8230 wtoken.inPendingTransaction = false;
8231 setTokenVisibilityLocked(wtoken, lp, false, transit, false);
8232 wtoken.updateReportedVisibilityLocked();
8233 // Force the allDrawn flag, because we want to start
8234 // this guy's animations regardless of whether it's
8235 // gotten drawn.
8236 wtoken.allDrawn = true;
8237 }
8238
8239 mOpeningApps.clear();
8240 mClosingApps.clear();
8241
8242 // This has changed the visibility of windows, so perform
8243 // a new layout to get them all up-to-date.
8244 mLayoutNeeded = true;
Dianne Hackborn20583ff2009-07-27 21:51:05 -07008245 if (!moveInputMethodWindowsIfNeededLocked(true)) {
8246 assignLayersLocked();
8247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008248 performLayoutLockedInner();
8249 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
8250
8251 restart = true;
8252 }
8253 }
8254 } while (restart);
8255
8256 // THIRD LOOP: Update the surfaces of all windows.
8257
8258 final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8259
8260 boolean obscured = false;
8261 boolean blurring = false;
8262 boolean dimming = false;
8263 boolean covered = false;
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008264 boolean syswin = false;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008265 boolean backgroundFillerShown = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008266
8267 for (i=N-1; i>=0; i--) {
8268 WindowState w = (WindowState)mWindows.get(i);
8269
8270 boolean displayed = false;
8271 final WindowManager.LayoutParams attrs = w.mAttrs;
8272 final int attrFlags = attrs.flags;
8273
8274 if (w.mSurface != null) {
8275 w.computeShownFrameLocked();
8276 if (localLOGV) Log.v(
8277 TAG, "Placing surface #" + i + " " + w.mSurface
8278 + ": new=" + w.mShownFrame + ", old="
8279 + w.mLastShownFrame);
8280
8281 boolean resize;
8282 int width, height;
8283 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8284 resize = w.mLastRequestedWidth != w.mRequestedWidth ||
8285 w.mLastRequestedHeight != w.mRequestedHeight;
8286 // for a scaled surface, we just want to use
8287 // the requested size.
8288 width = w.mRequestedWidth;
8289 height = w.mRequestedHeight;
8290 w.mLastRequestedWidth = width;
8291 w.mLastRequestedHeight = height;
8292 w.mLastShownFrame.set(w.mShownFrame);
8293 try {
8294 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8295 } catch (RuntimeException e) {
8296 Log.w(TAG, "Error positioning surface in " + w, e);
8297 if (!recoveringMemory) {
8298 reclaimSomeSurfaceMemoryLocked(w, "position");
8299 }
8300 }
8301 } else {
8302 resize = !w.mLastShownFrame.equals(w.mShownFrame);
8303 width = w.mShownFrame.width();
8304 height = w.mShownFrame.height();
8305 w.mLastShownFrame.set(w.mShownFrame);
8306 if (resize) {
8307 if (SHOW_TRANSACTIONS) Log.i(
8308 TAG, " SURFACE " + w.mSurface + ": ("
8309 + w.mShownFrame.left + ","
8310 + w.mShownFrame.top + ") ("
8311 + w.mShownFrame.width() + "x"
8312 + w.mShownFrame.height() + ")");
8313 }
8314 }
8315
8316 if (resize) {
8317 if (width < 1) width = 1;
8318 if (height < 1) height = 1;
8319 if (w.mSurface != null) {
8320 try {
8321 w.mSurface.setSize(width, height);
8322 w.mSurface.setPosition(w.mShownFrame.left,
8323 w.mShownFrame.top);
8324 } catch (RuntimeException e) {
8325 // If something goes wrong with the surface (such
8326 // as running out of memory), don't take down the
8327 // entire system.
8328 Log.e(TAG, "Failure updating surface of " + w
8329 + "size=(" + width + "x" + height
8330 + "), pos=(" + w.mShownFrame.left
8331 + "," + w.mShownFrame.top + ")", e);
8332 if (!recoveringMemory) {
8333 reclaimSomeSurfaceMemoryLocked(w, "size");
8334 }
8335 }
8336 }
8337 }
8338 if (!w.mAppFreezing) {
8339 w.mContentInsetsChanged =
8340 !w.mLastContentInsets.equals(w.mContentInsets);
8341 w.mVisibleInsetsChanged =
8342 !w.mLastVisibleInsets.equals(w.mVisibleInsets);
Romain Guy06882f82009-06-10 13:36:04 -07008343 if (!w.mLastFrame.equals(w.mFrame)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008344 || w.mContentInsetsChanged
8345 || w.mVisibleInsetsChanged) {
8346 w.mLastFrame.set(w.mFrame);
8347 w.mLastContentInsets.set(w.mContentInsets);
8348 w.mLastVisibleInsets.set(w.mVisibleInsets);
8349 // If the orientation is changing, then we need to
8350 // hold off on unfreezing the display until this
8351 // window has been redrawn; to do that, we need
8352 // to go through the process of getting informed
8353 // by the application when it has finished drawing.
8354 if (w.mOrientationChanging) {
8355 if (DEBUG_ORIENTATION) Log.v(TAG,
8356 "Orientation start waiting for draw in "
8357 + w + ", surface " + w.mSurface);
8358 w.mDrawPending = true;
8359 w.mCommitDrawPending = false;
8360 w.mReadyToShow = false;
8361 if (w.mAppToken != null) {
8362 w.mAppToken.allDrawn = false;
8363 }
8364 }
Romain Guy06882f82009-06-10 13:36:04 -07008365 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008366 "Resizing window " + w + " to " + w.mFrame);
8367 mResizingWindows.add(w);
8368 } else if (w.mOrientationChanging) {
8369 if (!w.mDrawPending && !w.mCommitDrawPending) {
8370 if (DEBUG_ORIENTATION) Log.v(TAG,
8371 "Orientation not waiting for draw in "
8372 + w + ", surface " + w.mSurface);
8373 w.mOrientationChanging = false;
8374 }
8375 }
8376 }
8377
8378 if (w.mAttachedHidden) {
8379 if (!w.mLastHidden) {
8380 //dump();
8381 w.mLastHidden = true;
8382 if (SHOW_TRANSACTIONS) Log.i(
8383 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)");
8384 if (w.mSurface != null) {
8385 try {
8386 w.mSurface.hide();
8387 } catch (RuntimeException e) {
8388 Log.w(TAG, "Exception hiding surface in " + w);
8389 }
8390 }
8391 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8392 }
8393 // If we are waiting for this window to handle an
8394 // orientation change, well, it is hidden, so
8395 // doesn't really matter. Note that this does
8396 // introduce a potential glitch if the window
8397 // becomes unhidden before it has drawn for the
8398 // new orientation.
8399 if (w.mOrientationChanging) {
8400 w.mOrientationChanging = false;
8401 if (DEBUG_ORIENTATION) Log.v(TAG,
8402 "Orientation change skips hidden " + w);
8403 }
8404 } else if (!w.isReadyForDisplay()) {
8405 if (!w.mLastHidden) {
8406 //dump();
8407 w.mLastHidden = true;
8408 if (SHOW_TRANSACTIONS) Log.i(
8409 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)");
8410 if (w.mSurface != null) {
8411 try {
8412 w.mSurface.hide();
8413 } catch (RuntimeException e) {
8414 Log.w(TAG, "Exception exception hiding surface in " + w);
8415 }
8416 }
8417 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8418 }
8419 // If we are waiting for this window to handle an
8420 // orientation change, well, it is hidden, so
8421 // doesn't really matter. Note that this does
8422 // introduce a potential glitch if the window
8423 // becomes unhidden before it has drawn for the
8424 // new orientation.
8425 if (w.mOrientationChanging) {
8426 w.mOrientationChanging = false;
8427 if (DEBUG_ORIENTATION) Log.v(TAG,
8428 "Orientation change skips hidden " + w);
8429 }
8430 } else if (w.mLastLayer != w.mAnimLayer
8431 || w.mLastAlpha != w.mShownAlpha
8432 || w.mLastDsDx != w.mDsDx
8433 || w.mLastDtDx != w.mDtDx
8434 || w.mLastDsDy != w.mDsDy
8435 || w.mLastDtDy != w.mDtDy
8436 || w.mLastHScale != w.mHScale
8437 || w.mLastVScale != w.mVScale
8438 || w.mLastHidden) {
8439 displayed = true;
8440 w.mLastAlpha = w.mShownAlpha;
8441 w.mLastLayer = w.mAnimLayer;
8442 w.mLastDsDx = w.mDsDx;
8443 w.mLastDtDx = w.mDtDx;
8444 w.mLastDsDy = w.mDsDy;
8445 w.mLastDtDy = w.mDtDy;
8446 w.mLastHScale = w.mHScale;
8447 w.mLastVScale = w.mVScale;
8448 if (SHOW_TRANSACTIONS) Log.i(
8449 TAG, " SURFACE " + w.mSurface + ": alpha="
8450 + w.mShownAlpha + " layer=" + w.mAnimLayer);
8451 if (w.mSurface != null) {
8452 try {
8453 w.mSurface.setAlpha(w.mShownAlpha);
8454 w.mSurface.setLayer(w.mAnimLayer);
8455 w.mSurface.setMatrix(
8456 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8457 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8458 } catch (RuntimeException e) {
8459 Log.w(TAG, "Error updating surface in " + w, e);
8460 if (!recoveringMemory) {
8461 reclaimSomeSurfaceMemoryLocked(w, "update");
8462 }
8463 }
8464 }
8465
8466 if (w.mLastHidden && !w.mDrawPending
8467 && !w.mCommitDrawPending
8468 && !w.mReadyToShow) {
8469 if (SHOW_TRANSACTIONS) Log.i(
8470 TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)");
8471 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w
8472 + " during relayout");
8473 if (showSurfaceRobustlyLocked(w)) {
8474 w.mHasDrawn = true;
8475 w.mLastHidden = false;
8476 } else {
8477 w.mOrientationChanging = false;
8478 }
8479 }
8480 if (w.mSurface != null) {
8481 w.mToken.hasVisible = true;
8482 }
8483 } else {
8484 displayed = true;
8485 }
8486
8487 if (displayed) {
8488 if (!covered) {
8489 if (attrs.width == LayoutParams.FILL_PARENT
8490 && attrs.height == LayoutParams.FILL_PARENT) {
8491 covered = true;
8492 }
8493 }
8494 if (w.mOrientationChanging) {
8495 if (w.mDrawPending || w.mCommitDrawPending) {
8496 orientationChangeComplete = false;
8497 if (DEBUG_ORIENTATION) Log.v(TAG,
8498 "Orientation continue waiting for draw in " + w);
8499 } else {
8500 w.mOrientationChanging = false;
8501 if (DEBUG_ORIENTATION) Log.v(TAG,
8502 "Orientation change complete in " + w);
8503 }
8504 }
8505 w.mToken.hasVisible = true;
8506 }
8507 } else if (w.mOrientationChanging) {
8508 if (DEBUG_ORIENTATION) Log.v(TAG,
8509 "Orientation change skips hidden " + w);
8510 w.mOrientationChanging = false;
8511 }
8512
8513 final boolean canBeSeen = w.isDisplayedLw();
8514
8515 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8516 focusDisplayed = true;
8517 }
8518
8519 // Update effect.
8520 if (!obscured) {
8521 if (w.mSurface != null) {
8522 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8523 holdScreen = w.mSession;
8524 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008525 if (!syswin && w.mAttrs.screenBrightness >= 0
8526 && screenBrightness < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008527 screenBrightness = w.mAttrs.screenBrightness;
8528 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008529 if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8530 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8531 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
8532 syswin = true;
8533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008534 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008535
8536 boolean opaqueDrawn = w.isOpaqueDrawn();
8537 if (opaqueDrawn && w.isFullscreen(dw, dh)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008538 // This window completely covers everything behind it,
8539 // so we want to leave all of them as unblurred (for
8540 // performance reasons).
8541 obscured = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008542 } else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
8543 if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008544 // This window is in compatibility mode, and needs background filler.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008545 obscured = true;
8546 if (mBackgroundFillerSurface == null) {
8547 try {
8548 mBackgroundFillerSurface = new Surface(mFxSession, 0,
8549 0, dw, dh,
8550 PixelFormat.OPAQUE,
8551 Surface.FX_SURFACE_NORMAL);
8552 } catch (Exception e) {
8553 Log.e(TAG, "Exception creating filler surface", e);
8554 }
8555 }
8556 try {
8557 mBackgroundFillerSurface.setPosition(0, 0);
8558 mBackgroundFillerSurface.setSize(dw, dh);
8559 // Using the same layer as Dim because they will never be shown at the
8560 // same time.
8561 mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
8562 mBackgroundFillerSurface.show();
8563 } catch (RuntimeException e) {
8564 Log.e(TAG, "Exception showing filler surface");
8565 }
8566 backgroundFillerShown = true;
8567 mBackgroundFillerShown = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008568 } else if (canBeSeen && !obscured &&
8569 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8570 if (localLOGV) Log.v(TAG, "Win " + w
8571 + ": blurring=" + blurring
8572 + " obscured=" + obscured
8573 + " displayed=" + displayed);
8574 if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8575 if (!dimming) {
8576 //Log.i(TAG, "DIM BEHIND: " + w);
8577 dimming = true;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008578 if (mDimAnimator == null) {
8579 mDimAnimator = new DimAnimator(mFxSession);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008580 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008581 mDimAnimator.show(dw, dh);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008582 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008583 mDimAnimator.updateParameters(w, currentTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008584 }
8585 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8586 if (!blurring) {
8587 //Log.i(TAG, "BLUR BEHIND: " + w);
8588 blurring = true;
8589 mBlurShown = true;
8590 if (mBlurSurface == null) {
8591 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8592 + mBlurSurface + ": CREATE");
8593 try {
Romain Guy06882f82009-06-10 13:36:04 -07008594 mBlurSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008595 -1, 16, 16,
8596 PixelFormat.OPAQUE,
8597 Surface.FX_SURFACE_BLUR);
8598 } catch (Exception e) {
8599 Log.e(TAG, "Exception creating Blur surface", e);
8600 }
8601 }
8602 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8603 + mBlurSurface + ": SHOW pos=(0,0) (" +
8604 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8605 if (mBlurSurface != null) {
8606 mBlurSurface.setPosition(0, 0);
8607 mBlurSurface.setSize(dw, dh);
8608 try {
8609 mBlurSurface.show();
8610 } catch (RuntimeException e) {
8611 Log.w(TAG, "Failure showing blur surface", e);
8612 }
8613 }
8614 }
8615 mBlurSurface.setLayer(w.mAnimLayer-2);
8616 }
8617 }
8618 }
8619 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07008620
8621 if (backgroundFillerShown == false && mBackgroundFillerShown) {
8622 mBackgroundFillerShown = false;
8623 if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
8624 try {
8625 mBackgroundFillerSurface.hide();
8626 } catch (RuntimeException e) {
8627 Log.e(TAG, "Exception hiding filler surface", e);
8628 }
8629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008630
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07008631 if (mDimAnimator != null && mDimAnimator.mDimShown) {
8632 animating |= mDimAnimator.updateSurface(dimming, currentTime, mDisplayFrozen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008633 }
Romain Guy06882f82009-06-10 13:36:04 -07008634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008635 if (!blurring && mBlurShown) {
8636 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
8637 + ": HIDE");
8638 try {
8639 mBlurSurface.hide();
8640 } catch (IllegalArgumentException e) {
8641 Log.w(TAG, "Illegal argument exception hiding blur surface");
8642 }
8643 mBlurShown = false;
8644 }
8645
8646 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
8647 } catch (RuntimeException e) {
8648 Log.e(TAG, "Unhandled exception in Window Manager", e);
8649 }
8650
8651 Surface.closeTransaction();
Romain Guy06882f82009-06-10 13:36:04 -07008652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
8654 "With display frozen, orientationChangeComplete="
8655 + orientationChangeComplete);
8656 if (orientationChangeComplete) {
8657 if (mWindowsFreezingScreen) {
8658 mWindowsFreezingScreen = false;
8659 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8660 }
8661 if (mAppsFreezingScreen == 0) {
8662 stopFreezingDisplayLocked();
8663 }
8664 }
Romain Guy06882f82009-06-10 13:36:04 -07008665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008666 i = mResizingWindows.size();
8667 if (i > 0) {
8668 do {
8669 i--;
8670 WindowState win = mResizingWindows.get(i);
8671 try {
8672 win.mClient.resized(win.mFrame.width(),
8673 win.mFrame.height(), win.mLastContentInsets,
8674 win.mLastVisibleInsets, win.mDrawPending);
8675 win.mContentInsetsChanged = false;
8676 win.mVisibleInsetsChanged = false;
8677 } catch (RemoteException e) {
8678 win.mOrientationChanging = false;
8679 }
8680 } while (i > 0);
8681 mResizingWindows.clear();
8682 }
Romain Guy06882f82009-06-10 13:36:04 -07008683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008684 // Destroy the surface of any windows that are no longer visible.
8685 i = mDestroySurface.size();
8686 if (i > 0) {
8687 do {
8688 i--;
8689 WindowState win = mDestroySurface.get(i);
8690 win.mDestroying = false;
8691 if (mInputMethodWindow == win) {
8692 mInputMethodWindow = null;
8693 }
8694 win.destroySurfaceLocked();
8695 } while (i > 0);
8696 mDestroySurface.clear();
8697 }
8698
8699 // Time to remove any exiting tokens?
8700 for (i=mExitingTokens.size()-1; i>=0; i--) {
8701 WindowToken token = mExitingTokens.get(i);
8702 if (!token.hasVisible) {
8703 mExitingTokens.remove(i);
8704 }
8705 }
8706
8707 // Time to remove any exiting applications?
8708 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8709 AppWindowToken token = mExitingAppTokens.get(i);
8710 if (!token.hasVisible && !mClosingApps.contains(token)) {
8711 mAppTokens.remove(token);
8712 mExitingAppTokens.remove(i);
8713 }
8714 }
8715
8716 if (focusDisplayed) {
8717 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8718 }
8719 if (animating) {
8720 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8721 }
8722 mQueue.setHoldScreenLocked(holdScreen != null);
8723 if (screenBrightness < 0 || screenBrightness > 1.0f) {
8724 mPowerManager.setScreenBrightnessOverride(-1);
8725 } else {
8726 mPowerManager.setScreenBrightnessOverride((int)
8727 (screenBrightness * Power.BRIGHTNESS_ON));
8728 }
8729 if (holdScreen != mHoldingScreenOn) {
8730 mHoldingScreenOn = holdScreen;
8731 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8732 mH.sendMessage(m);
8733 }
8734 }
8735
8736 void requestAnimationLocked(long delay) {
8737 if (!mAnimationPending) {
8738 mAnimationPending = true;
8739 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8740 }
8741 }
Romain Guy06882f82009-06-10 13:36:04 -07008742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008743 /**
8744 * Have the surface flinger show a surface, robustly dealing with
8745 * error conditions. In particular, if there is not enough memory
8746 * to show the surface, then we will try to get rid of other surfaces
8747 * in order to succeed.
Romain Guy06882f82009-06-10 13:36:04 -07008748 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008749 * @return Returns true if the surface was successfully shown.
8750 */
8751 boolean showSurfaceRobustlyLocked(WindowState win) {
8752 try {
8753 if (win.mSurface != null) {
8754 win.mSurface.show();
8755 }
8756 return true;
8757 } catch (RuntimeException e) {
8758 Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
8759 }
Romain Guy06882f82009-06-10 13:36:04 -07008760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008761 reclaimSomeSurfaceMemoryLocked(win, "show");
Romain Guy06882f82009-06-10 13:36:04 -07008762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008763 return false;
8764 }
Romain Guy06882f82009-06-10 13:36:04 -07008765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008766 void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
8767 final Surface surface = win.mSurface;
Romain Guy06882f82009-06-10 13:36:04 -07008768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008769 EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
8770 win.mSession.mPid, operation);
Romain Guy06882f82009-06-10 13:36:04 -07008771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 if (mForceRemoves == null) {
8773 mForceRemoves = new ArrayList<WindowState>();
8774 }
Romain Guy06882f82009-06-10 13:36:04 -07008775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008776 long callingIdentity = Binder.clearCallingIdentity();
8777 try {
8778 // There was some problem... first, do a sanity check of the
8779 // window list to make sure we haven't left any dangling surfaces
8780 // around.
8781 int N = mWindows.size();
8782 boolean leakedSurface = false;
8783 Log.i(TAG, "Out of memory for surface! Looking for leaks...");
8784 for (int i=0; i<N; i++) {
8785 WindowState ws = (WindowState)mWindows.get(i);
8786 if (ws.mSurface != null) {
8787 if (!mSessions.contains(ws.mSession)) {
8788 Log.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8789 + ws + " surface=" + ws.mSurface
8790 + " token=" + win.mToken
8791 + " pid=" + ws.mSession.mPid
8792 + " uid=" + ws.mSession.mUid);
8793 ws.mSurface.clear();
8794 ws.mSurface = null;
8795 mForceRemoves.add(ws);
8796 i--;
8797 N--;
8798 leakedSurface = true;
8799 } else if (win.mAppToken != null && win.mAppToken.clientHidden) {
8800 Log.w(TAG, "LEAKED SURFACE (app token hidden): "
8801 + ws + " surface=" + ws.mSurface
8802 + " token=" + win.mAppToken);
8803 ws.mSurface.clear();
8804 ws.mSurface = null;
8805 leakedSurface = true;
8806 }
8807 }
8808 }
Romain Guy06882f82009-06-10 13:36:04 -07008809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008810 boolean killedApps = false;
8811 if (!leakedSurface) {
8812 Log.w(TAG, "No leaked surfaces; killing applicatons!");
8813 SparseIntArray pidCandidates = new SparseIntArray();
8814 for (int i=0; i<N; i++) {
8815 WindowState ws = (WindowState)mWindows.get(i);
8816 if (ws.mSurface != null) {
8817 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8818 }
8819 }
8820 if (pidCandidates.size() > 0) {
8821 int[] pids = new int[pidCandidates.size()];
8822 for (int i=0; i<pids.length; i++) {
8823 pids[i] = pidCandidates.keyAt(i);
8824 }
8825 try {
8826 if (mActivityManager.killPidsForMemory(pids)) {
8827 killedApps = true;
8828 }
8829 } catch (RemoteException e) {
8830 }
8831 }
8832 }
Romain Guy06882f82009-06-10 13:36:04 -07008833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008834 if (leakedSurface || killedApps) {
8835 // We managed to reclaim some memory, so get rid of the trouble
8836 // surface and ask the app to request another one.
8837 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8838 if (surface != null) {
8839 surface.clear();
8840 win.mSurface = null;
8841 }
Romain Guy06882f82009-06-10 13:36:04 -07008842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008843 try {
8844 win.mClient.dispatchGetNewSurface();
8845 } catch (RemoteException e) {
8846 }
8847 }
8848 } finally {
8849 Binder.restoreCallingIdentity(callingIdentity);
8850 }
8851 }
Romain Guy06882f82009-06-10 13:36:04 -07008852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008853 private boolean updateFocusedWindowLocked(int mode) {
8854 WindowState newFocus = computeFocusedWindowLocked();
8855 if (mCurrentFocus != newFocus) {
8856 // This check makes sure that we don't already have the focus
8857 // change message pending.
8858 mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8859 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8860 if (localLOGV) Log.v(
8861 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8862 final WindowState oldFocus = mCurrentFocus;
8863 mCurrentFocus = newFocus;
8864 mLosingFocus.remove(newFocus);
Romain Guy06882f82009-06-10 13:36:04 -07008865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008866 final WindowState imWindow = mInputMethodWindow;
8867 if (newFocus != imWindow && oldFocus != imWindow) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008868 if (moveInputMethodWindowsIfNeededLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008869 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008870 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8871 mLayoutNeeded = true;
8872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008873 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8874 performLayoutLockedInner();
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008875 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8876 // Client will do the layout, but we need to assign layers
8877 // for handleNewWindowLocked() below.
8878 assignLayersLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008879 }
8880 }
Romain Guy06882f82009-06-10 13:36:04 -07008881
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008882 if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8883 mKeyWaiter.handleNewWindowLocked(newFocus);
8884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008885 return true;
8886 }
8887 return false;
8888 }
8889
8890 private WindowState computeFocusedWindowLocked() {
8891 WindowState result = null;
8892 WindowState win;
8893
8894 int i = mWindows.size() - 1;
8895 int nextAppIndex = mAppTokens.size()-1;
8896 WindowToken nextApp = nextAppIndex >= 0
8897 ? mAppTokens.get(nextAppIndex) : null;
8898
8899 while (i >= 0) {
8900 win = (WindowState)mWindows.get(i);
8901
8902 if (localLOGV || DEBUG_FOCUS) Log.v(
8903 TAG, "Looking for focus: " + i
8904 + " = " + win
8905 + ", flags=" + win.mAttrs.flags
8906 + ", canReceive=" + win.canReceiveKeys());
8907
8908 AppWindowToken thisApp = win.mAppToken;
Romain Guy06882f82009-06-10 13:36:04 -07008909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008910 // If this window's application has been removed, just skip it.
8911 if (thisApp != null && thisApp.removed) {
8912 i--;
8913 continue;
8914 }
Romain Guy06882f82009-06-10 13:36:04 -07008915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008916 // If there is a focused app, don't allow focus to go to any
8917 // windows below it. If this is an application window, step
8918 // through the app tokens until we find its app.
8919 if (thisApp != null && nextApp != null && thisApp != nextApp
8920 && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8921 int origAppIndex = nextAppIndex;
8922 while (nextAppIndex > 0) {
8923 if (nextApp == mFocusedApp) {
8924 // Whoops, we are below the focused app... no focus
8925 // for you!
8926 if (localLOGV || DEBUG_FOCUS) Log.v(
8927 TAG, "Reached focused app: " + mFocusedApp);
8928 return null;
8929 }
8930 nextAppIndex--;
8931 nextApp = mAppTokens.get(nextAppIndex);
8932 if (nextApp == thisApp) {
8933 break;
8934 }
8935 }
8936 if (thisApp != nextApp) {
8937 // Uh oh, the app token doesn't exist! This shouldn't
8938 // happen, but if it does we can get totally hosed...
8939 // so restart at the original app.
8940 nextAppIndex = origAppIndex;
8941 nextApp = mAppTokens.get(nextAppIndex);
8942 }
8943 }
8944
8945 // Dispatch to this window if it is wants key events.
8946 if (win.canReceiveKeys()) {
8947 if (DEBUG_FOCUS) Log.v(
8948 TAG, "Found focus @ " + i + " = " + win);
8949 result = win;
8950 break;
8951 }
8952
8953 i--;
8954 }
8955
8956 return result;
8957 }
8958
8959 private void startFreezingDisplayLocked() {
8960 if (mDisplayFrozen) {
Chris Tate2ad63a92009-03-25 17:36:48 -07008961 // Freezing the display also suspends key event delivery, to
8962 // keep events from going astray while the display is reconfigured.
8963 // If someone has changed orientation again while the screen is
8964 // still frozen, the events will continue to be blocked while the
8965 // successive orientation change is processed. To prevent spurious
8966 // ANRs, we reset the event dispatch timeout in this case.
8967 synchronized (mKeyWaiter) {
8968 mKeyWaiter.mWasFrozen = true;
8969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 return;
8971 }
Romain Guy06882f82009-06-10 13:36:04 -07008972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008973 mScreenFrozenLock.acquire();
Romain Guy06882f82009-06-10 13:36:04 -07008974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008975 long now = SystemClock.uptimeMillis();
8976 //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8977 if (mFreezeGcPending != 0) {
8978 if (now > (mFreezeGcPending+1000)) {
8979 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
8980 mH.removeMessages(H.FORCE_GC);
8981 Runtime.getRuntime().gc();
8982 mFreezeGcPending = now;
8983 }
8984 } else {
8985 mFreezeGcPending = now;
8986 }
Romain Guy06882f82009-06-10 13:36:04 -07008987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 mDisplayFrozen = true;
8989 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
8990 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8991 mAppTransitionReady = true;
8992 }
Romain Guy06882f82009-06-10 13:36:04 -07008993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008994 if (PROFILE_ORIENTATION) {
8995 File file = new File("/data/system/frozen");
8996 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8997 }
8998 Surface.freezeDisplay(0);
8999 }
Romain Guy06882f82009-06-10 13:36:04 -07009000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009001 private void stopFreezingDisplayLocked() {
9002 if (!mDisplayFrozen) {
9003 return;
9004 }
Romain Guy06882f82009-06-10 13:36:04 -07009005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009006 mDisplayFrozen = false;
9007 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9008 if (PROFILE_ORIENTATION) {
9009 Debug.stopMethodTracing();
9010 }
9011 Surface.unfreezeDisplay(0);
Romain Guy06882f82009-06-10 13:36:04 -07009012
Chris Tate2ad63a92009-03-25 17:36:48 -07009013 // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
9014 // too because regular key delivery processing should resume immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009015 synchronized (mKeyWaiter) {
9016 mKeyWaiter.mWasFrozen = true;
9017 mKeyWaiter.notifyAll();
9018 }
9019
9020 // A little kludge: a lot could have happened while the
9021 // display was frozen, so now that we are coming back we
9022 // do a gc so that any remote references the system
9023 // processes holds on others can be released if they are
9024 // no longer needed.
9025 mH.removeMessages(H.FORCE_GC);
9026 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9027 2000);
Romain Guy06882f82009-06-10 13:36:04 -07009028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009029 mScreenFrozenLock.release();
9030 }
Romain Guy06882f82009-06-10 13:36:04 -07009031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009032 @Override
9033 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9034 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9035 != PackageManager.PERMISSION_GRANTED) {
9036 pw.println("Permission Denial: can't dump WindowManager from from pid="
9037 + Binder.getCallingPid()
9038 + ", uid=" + Binder.getCallingUid());
9039 return;
9040 }
Romain Guy06882f82009-06-10 13:36:04 -07009041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009042 synchronized(mWindowMap) {
9043 pw.println("Current Window Manager state:");
9044 for (int i=mWindows.size()-1; i>=0; i--) {
9045 WindowState w = (WindowState)mWindows.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009046 pw.print(" Window #"); pw.print(i); pw.print(' ');
9047 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009048 w.dump(pw, " ");
9049 }
9050 if (mInputMethodDialogs.size() > 0) {
9051 pw.println(" ");
9052 pw.println(" Input method dialogs:");
9053 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9054 WindowState w = mInputMethodDialogs.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009055 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 }
9057 }
9058 if (mPendingRemove.size() > 0) {
9059 pw.println(" ");
9060 pw.println(" Remove pending for:");
9061 for (int i=mPendingRemove.size()-1; i>=0; i--) {
9062 WindowState w = mPendingRemove.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009063 pw.print(" Remove #"); pw.print(i); pw.print(' ');
9064 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009065 w.dump(pw, " ");
9066 }
9067 }
9068 if (mForceRemoves != null && mForceRemoves.size() > 0) {
9069 pw.println(" ");
9070 pw.println(" Windows force removing:");
9071 for (int i=mForceRemoves.size()-1; i>=0; i--) {
9072 WindowState w = mForceRemoves.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009073 pw.print(" Removing #"); pw.print(i); pw.print(' ');
9074 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009075 w.dump(pw, " ");
9076 }
9077 }
9078 if (mDestroySurface.size() > 0) {
9079 pw.println(" ");
9080 pw.println(" Windows waiting to destroy their surface:");
9081 for (int i=mDestroySurface.size()-1; i>=0; i--) {
9082 WindowState w = mDestroySurface.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009083 pw.print(" Destroy #"); pw.print(i); pw.print(' ');
9084 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 w.dump(pw, " ");
9086 }
9087 }
9088 if (mLosingFocus.size() > 0) {
9089 pw.println(" ");
9090 pw.println(" Windows losing focus:");
9091 for (int i=mLosingFocus.size()-1; i>=0; i--) {
9092 WindowState w = mLosingFocus.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009093 pw.print(" Losing #"); pw.print(i); pw.print(' ');
9094 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 w.dump(pw, " ");
9096 }
9097 }
9098 if (mSessions.size() > 0) {
9099 pw.println(" ");
9100 pw.println(" All active sessions:");
9101 Iterator<Session> it = mSessions.iterator();
9102 while (it.hasNext()) {
9103 Session s = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009104 pw.print(" Session "); pw.print(s); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009105 s.dump(pw, " ");
9106 }
9107 }
9108 if (mTokenMap.size() > 0) {
9109 pw.println(" ");
9110 pw.println(" All tokens:");
9111 Iterator<WindowToken> it = mTokenMap.values().iterator();
9112 while (it.hasNext()) {
9113 WindowToken token = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009114 pw.print(" Token "); pw.print(token.token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009115 token.dump(pw, " ");
9116 }
9117 }
9118 if (mTokenList.size() > 0) {
9119 pw.println(" ");
9120 pw.println(" Window token list:");
9121 for (int i=0; i<mTokenList.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009122 pw.print(" #"); pw.print(i); pw.print(": ");
9123 pw.println(mTokenList.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009124 }
9125 }
9126 if (mAppTokens.size() > 0) {
9127 pw.println(" ");
9128 pw.println(" Application tokens in Z order:");
9129 for (int i=mAppTokens.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009130 pw.print(" App #"); pw.print(i); pw.print(": ");
9131 pw.println(mAppTokens.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009132 }
9133 }
9134 if (mFinishedStarting.size() > 0) {
9135 pw.println(" ");
9136 pw.println(" Finishing start of application tokens:");
9137 for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9138 WindowToken token = mFinishedStarting.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009139 pw.print(" Finished Starting #"); pw.print(i);
9140 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009141 token.dump(pw, " ");
9142 }
9143 }
9144 if (mExitingTokens.size() > 0) {
9145 pw.println(" ");
9146 pw.println(" Exiting tokens:");
9147 for (int i=mExitingTokens.size()-1; i>=0; i--) {
9148 WindowToken token = mExitingTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009149 pw.print(" Exiting #"); pw.print(i);
9150 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009151 token.dump(pw, " ");
9152 }
9153 }
9154 if (mExitingAppTokens.size() > 0) {
9155 pw.println(" ");
9156 pw.println(" Exiting application tokens:");
9157 for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9158 WindowToken token = mExitingAppTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009159 pw.print(" Exiting App #"); pw.print(i);
9160 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009161 token.dump(pw, " ");
9162 }
9163 }
9164 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009165 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
9166 pw.print(" mLastFocus="); pw.println(mLastFocus);
9167 pw.print(" mFocusedApp="); pw.println(mFocusedApp);
9168 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
9169 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
9170 pw.print(" mInTouchMode="); pw.println(mInTouchMode);
9171 pw.print(" mSystemBooted="); pw.print(mSystemBooted);
9172 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9173 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
9174 pw.print(" mBlurShown="); pw.println(mBlurShown);
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009175 if (mDimAnimator != null) {
9176 mDimAnimator.printTo(pw);
9177 } else {
9178 pw.print( " no DimAnimator ");
9179 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009180 pw.print(" mInputMethodAnimLayerAdjustment=");
9181 pw.println(mInputMethodAnimLayerAdjustment);
9182 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
9183 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9184 pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
9185 pw.print(" mRotation="); pw.print(mRotation);
9186 pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
9187 pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
9188 pw.print(" mAnimationPending="); pw.print(mAnimationPending);
9189 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9190 pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9191 pw.print(" mNextAppTransition=0x");
9192 pw.print(Integer.toHexString(mNextAppTransition));
9193 pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
9194 pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9195 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9196 pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9197 if (mOpeningApps.size() > 0) {
9198 pw.print(" mOpeningApps="); pw.println(mOpeningApps);
9199 }
9200 if (mClosingApps.size() > 0) {
9201 pw.print(" mClosingApps="); pw.println(mClosingApps);
9202 }
9203 pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth());
9204 pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009205 pw.println(" KeyWaiter state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009206 pw.print(" mLastWin="); pw.print(mKeyWaiter.mLastWin);
9207 pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
9208 pw.print(" mFinished="); pw.print(mKeyWaiter.mFinished);
9209 pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
9210 pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
9211 pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009212 }
9213 }
9214
9215 public void monitor() {
9216 synchronized (mWindowMap) { }
9217 synchronized (mKeyguardDisabled) { }
9218 synchronized (mKeyWaiter) { }
9219 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009220
Dianne Hackbornddca3ee2009-07-23 19:01:31 -07009221 public void virtualKeyFeedback(KeyEvent event) {
9222 mPolicy.keyFeedbackFromInput(event);
9223 }
9224
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009225 /**
9226 * DimAnimator class that controls the dim animation. This holds the surface and
9227 * all state used for dim animation.
9228 */
9229 private static class DimAnimator {
9230 Surface mDimSurface;
9231 boolean mDimShown = false;
9232 float mDimCurrentAlpha;
9233 float mDimTargetAlpha;
9234 float mDimDeltaPerMs;
9235 long mLastDimAnimTime;
9236
9237 DimAnimator (SurfaceSession session) {
9238 if (mDimSurface == null) {
9239 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9240 + mDimSurface + ": CREATE");
9241 try {
9242 mDimSurface = new Surface(session, 0, -1, 16, 16, PixelFormat.OPAQUE,
9243 Surface.FX_SURFACE_DIM);
9244 } catch (Exception e) {
9245 Log.e(TAG, "Exception creating Dim surface", e);
9246 }
9247 }
9248 }
9249
9250 /**
9251 * Show the dim surface.
9252 */
9253 void show(int dw, int dh) {
9254 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
9255 dw + "x" + dh + ")");
9256 mDimShown = true;
9257 try {
9258 mDimSurface.setPosition(0, 0);
9259 mDimSurface.setSize(dw, dh);
9260 mDimSurface.show();
9261 } catch (RuntimeException e) {
9262 Log.w(TAG, "Failure showing dim surface", e);
9263 }
9264 }
9265
9266 /**
9267 * Set's the dim surface's layer and update dim parameters that will be used in
9268 * {@link updateSurface} after all windows are examined.
9269 */
9270 void updateParameters(WindowState w, long currentTime) {
9271 mDimSurface.setLayer(w.mAnimLayer-1);
9272
9273 final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
9274 if (SHOW_TRANSACTIONS) Log.i(TAG, "layer=" + (w.mAnimLayer-1) + ", target=" + target);
9275 if (mDimTargetAlpha != target) {
9276 // If the desired dim level has changed, then
9277 // start an animation to it.
9278 mLastDimAnimTime = currentTime;
9279 long duration = (w.mAnimating && w.mAnimation != null)
9280 ? w.mAnimation.computeDurationHint()
9281 : DEFAULT_DIM_DURATION;
9282 if (target > mDimTargetAlpha) {
9283 // This is happening behind the activity UI,
9284 // so we can make it run a little longer to
9285 // give a stronger impression without disrupting
9286 // the user.
9287 duration *= DIM_DURATION_MULTIPLIER;
9288 }
9289 if (duration < 1) {
9290 // Don't divide by zero
9291 duration = 1;
9292 }
9293 mDimTargetAlpha = target;
9294 mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
9295 }
9296 }
9297
9298 /**
9299 * Updating the surface's alpha. Returns true if the animation continues, or returns
9300 * false when the animation is finished and the dim surface is hidden.
9301 */
9302 boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
9303 if (!dimming) {
9304 if (mDimTargetAlpha != 0) {
9305 mLastDimAnimTime = currentTime;
9306 mDimTargetAlpha = 0;
9307 mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
9308 }
9309 }
9310
9311 boolean animating = false;
9312 if (mLastDimAnimTime != 0) {
9313 mDimCurrentAlpha += mDimDeltaPerMs
9314 * (currentTime-mLastDimAnimTime);
9315 boolean more = true;
9316 if (displayFrozen) {
9317 // If the display is frozen, there is no reason to animate.
9318 more = false;
9319 } else if (mDimDeltaPerMs > 0) {
9320 if (mDimCurrentAlpha > mDimTargetAlpha) {
9321 more = false;
9322 }
9323 } else if (mDimDeltaPerMs < 0) {
9324 if (mDimCurrentAlpha < mDimTargetAlpha) {
9325 more = false;
9326 }
9327 } else {
9328 more = false;
9329 }
9330
9331 // Do we need to continue animating?
9332 if (more) {
9333 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9334 + mDimSurface + ": alpha=" + mDimCurrentAlpha);
9335 mLastDimAnimTime = currentTime;
9336 mDimSurface.setAlpha(mDimCurrentAlpha);
9337 animating = true;
9338 } else {
9339 mDimCurrentAlpha = mDimTargetAlpha;
9340 mLastDimAnimTime = 0;
9341 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
9342 + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
9343 mDimSurface.setAlpha(mDimCurrentAlpha);
9344 if (!dimming) {
9345 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
9346 + ": HIDE");
9347 try {
9348 mDimSurface.hide();
9349 } catch (RuntimeException e) {
9350 Log.w(TAG, "Illegal argument exception hiding dim surface");
9351 }
9352 mDimShown = false;
9353 }
9354 }
9355 }
9356 return animating;
9357 }
9358
9359 public void printTo(PrintWriter pw) {
9360 pw.print(" mDimShown="); pw.print(mDimShown);
9361 pw.print(" current="); pw.print(mDimCurrentAlpha);
9362 pw.print(" target="); pw.print(mDimTargetAlpha);
9363 pw.print(" delta="); pw.print(mDimDeltaPerMs);
9364 pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
9365 }
9366 }
9367
9368 /**
9369 * Animation that fade in after 0.5 interpolate time, or fade out in reverse order.
9370 * This is used for opening/closing transition for apps in compatible mode.
9371 */
9372 private static class FadeInOutAnimation extends Animation {
9373 int mWidth;
9374 boolean mFadeIn;
9375
9376 public FadeInOutAnimation(boolean fadeIn) {
9377 setInterpolator(new AccelerateInterpolator());
9378 setDuration(DEFAULT_FADE_IN_OUT_DURATION);
9379 mFadeIn = fadeIn;
9380 }
9381
9382 @Override
9383 protected void applyTransformation(float interpolatedTime, Transformation t) {
9384 float x = interpolatedTime;
9385 if (!mFadeIn) {
9386 x = 1.0f - x; // reverse the interpolation for fade out
9387 }
9388 if (x < 0.5) {
9389 // move the window out of the screen.
9390 t.getMatrix().setTranslate(mWidth, 0);
9391 } else {
9392 t.getMatrix().setTranslate(0, 0);// show
9393 t.setAlpha((x - 0.5f) * 2);
9394 }
9395 }
9396
9397 @Override
9398 public void initialize(int width, int height, int parentWidth, int parentHeight) {
9399 // width is the screen width {@see AppWindowToken#stepAnimatinoLocked}
9400 mWidth = width;
9401 }
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009402
9403 @Override
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -07009404 public int getZAdjustment() {
9405 return Animation.ZORDER_TOP;
Mitsuru Oshima0a5d2c42009-07-14 14:10:30 -07009406 }
9407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009408}