blob: 5ea750439ee426298e2fddfa629a1c0afb17f7d7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static android.os.LocalPowerManager.CHEEK_EVENT;
20import static android.os.LocalPowerManager.OTHER_EVENT;
21import static android.os.LocalPowerManager.TOUCH_EVENT;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -070022import static android.os.LocalPowerManager.LONG_TOUCH_EVENT;
23import static android.os.LocalPowerManager.TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
25import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
26import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
27import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
28import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
29import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
30import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
31import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
32import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
33import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
34import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
35import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
36import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
37import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
38import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
39import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
40import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
41
42import com.android.internal.app.IBatteryStats;
43import com.android.internal.policy.PolicyManager;
44import com.android.internal.view.IInputContext;
45import com.android.internal.view.IInputMethodClient;
46import com.android.internal.view.IInputMethodManager;
47import com.android.server.KeyInputQueue.QueuedEvent;
48import com.android.server.am.BatteryStatsService;
49
50import android.Manifest;
51import android.app.ActivityManagerNative;
52import android.app.IActivityManager;
53import android.content.Context;
54import android.content.pm.ActivityInfo;
55import android.content.pm.PackageManager;
56import android.content.res.Configuration;
57import android.graphics.Matrix;
58import android.graphics.PixelFormat;
59import android.graphics.Rect;
60import android.graphics.Region;
61import android.os.BatteryStats;
62import android.os.Binder;
63import android.os.Debug;
64import android.os.Handler;
65import android.os.IBinder;
66import android.os.LocalPowerManager;
67import android.os.Looper;
68import android.os.Message;
69import android.os.Parcel;
70import android.os.ParcelFileDescriptor;
71import android.os.Power;
72import android.os.PowerManager;
73import android.os.Process;
74import android.os.RemoteException;
75import android.os.ServiceManager;
76import android.os.SystemClock;
77import android.os.SystemProperties;
78import android.os.TokenWatcher;
79import android.provider.Settings;
Dianne Hackborn723738c2009-06-25 19:48:04 -070080import android.util.DisplayMetrics;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.util.EventLog;
82import android.util.Log;
83import android.util.SparseIntArray;
84import android.view.Display;
85import android.view.Gravity;
86import android.view.IApplicationToken;
87import android.view.IOnKeyguardExitResult;
88import android.view.IRotationWatcher;
89import android.view.IWindow;
90import android.view.IWindowManager;
91import android.view.IWindowSession;
92import android.view.KeyEvent;
93import android.view.MotionEvent;
94import android.view.RawInputEvent;
95import android.view.Surface;
96import android.view.SurfaceSession;
97import android.view.View;
98import android.view.ViewTreeObserver;
99import android.view.WindowManager;
100import android.view.WindowManagerImpl;
101import android.view.WindowManagerPolicy;
102import android.view.WindowManager.LayoutParams;
103import android.view.animation.Animation;
104import android.view.animation.AnimationUtils;
105import android.view.animation.Transformation;
106
107import java.io.BufferedWriter;
108import java.io.File;
109import java.io.FileDescriptor;
110import java.io.IOException;
111import java.io.OutputStream;
112import java.io.OutputStreamWriter;
113import java.io.PrintWriter;
114import java.io.StringWriter;
115import java.net.Socket;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121
122/** {@hide} */
123public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
124 static final String TAG = "WindowManager";
125 static final boolean DEBUG = false;
126 static final boolean DEBUG_FOCUS = false;
127 static final boolean DEBUG_ANIM = false;
128 static final boolean DEBUG_LAYERS = false;
129 static final boolean DEBUG_INPUT = false;
130 static final boolean DEBUG_INPUT_METHOD = false;
131 static final boolean DEBUG_VISIBILITY = false;
132 static final boolean DEBUG_ORIENTATION = false;
133 static final boolean DEBUG_APP_TRANSITIONS = false;
134 static final boolean DEBUG_STARTING_WINDOW = false;
135 static final boolean DEBUG_REORDER = false;
136 static final boolean SHOW_TRANSACTIONS = false;
Romain Guy06882f82009-06-10 13:36:04 -0700137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 static final boolean PROFILE_ORIENTATION = false;
139 static final boolean BLUR = true;
Dave Bortcfe65242009-04-09 14:51:04 -0700140 static final boolean localLOGV = DEBUG;
Romain Guy06882f82009-06-10 13:36:04 -0700141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
Romain Guy06882f82009-06-10 13:36:04 -0700143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 /** How long to wait for first key repeat, in milliseconds */
145 static final int KEY_REPEAT_FIRST_DELAY = 750;
Romain Guy06882f82009-06-10 13:36:04 -0700146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 /** How long to wait for subsequent key repeats, in milliseconds */
148 static final int KEY_REPEAT_DELAY = 50;
149
150 /** How much to multiply the policy's type layer, to reserve room
151 * for multiple windows of the same type and Z-ordering adjustment
152 * with TYPE_LAYER_OFFSET. */
153 static final int TYPE_LAYER_MULTIPLIER = 10000;
Romain Guy06882f82009-06-10 13:36:04 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
156 * or below others in the same layer. */
157 static final int TYPE_LAYER_OFFSET = 1000;
Romain Guy06882f82009-06-10 13:36:04 -0700158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 /** How much to increment the layer for each window, to reserve room
160 * for effect surfaces between them.
161 */
162 static final int WINDOW_LAYER_MULTIPLIER = 5;
Romain Guy06882f82009-06-10 13:36:04 -0700163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /** The maximum length we will accept for a loaded animation duration:
165 * this is 10 seconds.
166 */
167 static final int MAX_ANIMATION_DURATION = 10*1000;
168
169 /** Amount of time (in milliseconds) to animate the dim surface from one
170 * value to another, when no window animation is driving it.
171 */
172 static final int DEFAULT_DIM_DURATION = 200;
173
174 /** Adjustment to time to perform a dim, to make it more dramatic.
175 */
176 static final int DIM_DURATION_MULTIPLIER = 6;
Romain Guy06882f82009-06-10 13:36:04 -0700177
Dianne Hackborncfaef692009-06-15 14:24:44 -0700178 static final int INJECT_FAILED = 0;
179 static final int INJECT_SUCCEEDED = 1;
180 static final int INJECT_NO_PERMISSION = -1;
181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 static final int UPDATE_FOCUS_NORMAL = 0;
183 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
184 static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
185 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
Romain Guy06882f82009-06-10 13:36:04 -0700186
Michael Chane96440f2009-05-06 10:27:36 -0700187 /** The minimum time between dispatching touch events. */
188 int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
189
190 // Last touch event time
191 long mLastTouchEventTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700192
Michael Chane96440f2009-05-06 10:27:36 -0700193 // Last touch event type
194 int mLastTouchEventType = OTHER_EVENT;
Romain Guy06882f82009-06-10 13:36:04 -0700195
Michael Chane96440f2009-05-06 10:27:36 -0700196 // Time to wait before calling useractivity again. This saves CPU usage
197 // when we get a flood of touch events.
198 static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
199
200 // Last time we call user activity
201 long mLastUserActivityCallTime = 0;
202
Romain Guy06882f82009-06-10 13:36:04 -0700203 // Last time we updated battery stats
Michael Chane96440f2009-05-06 10:27:36 -0700204 long mLastBatteryStatsCallTime = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 private static final String SYSTEM_SECURE = "ro.secure";
Romain Guy06882f82009-06-10 13:36:04 -0700207 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
209 /**
210 * Condition waited on by {@link #reenableKeyguard} to know the call to
211 * the window policy has finished.
212 */
213 private boolean mWaitingUntilKeyguardReenabled = false;
214
215
216 final TokenWatcher mKeyguardDisabled = new TokenWatcher(
217 new Handler(), "WindowManagerService.mKeyguardDisabled") {
218 public void acquired() {
219 mPolicy.enableKeyguard(false);
220 }
221 public void released() {
222 synchronized (mKeyguardDisabled) {
223 mPolicy.enableKeyguard(true);
224 mWaitingUntilKeyguardReenabled = false;
225 mKeyguardDisabled.notifyAll();
226 }
227 }
228 };
229
230 final Context mContext;
231
232 final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 final boolean mLimitedAlphaCompositing;
Romain Guy06882f82009-06-10 13:36:04 -0700235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
237
238 final IActivityManager mActivityManager;
Romain Guy06882f82009-06-10 13:36:04 -0700239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 final IBatteryStats mBatteryStats;
Romain Guy06882f82009-06-10 13:36:04 -0700241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 /**
243 * All currently active sessions with clients.
244 */
245 final HashSet<Session> mSessions = new HashSet<Session>();
Romain Guy06882f82009-06-10 13:36:04 -0700246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 /**
248 * Mapping from an IWindow IBinder to the server's Window object.
249 * This is also used as the lock for all of our state.
250 */
251 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
252
253 /**
254 * Mapping from a token IBinder to a WindowToken object.
255 */
256 final HashMap<IBinder, WindowToken> mTokenMap =
257 new HashMap<IBinder, WindowToken>();
258
259 /**
260 * The same tokens as mTokenMap, stored in a list for efficient iteration
261 * over them.
262 */
263 final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 /**
266 * Window tokens that are in the process of exiting, but still
267 * on screen for animations.
268 */
269 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
270
271 /**
272 * Z-ordered (bottom-most first) list of all application tokens, for
273 * controlling the ordering of windows in different applications. This
274 * contains WindowToken objects.
275 */
276 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
277
278 /**
279 * Application tokens that are in the process of exiting, but still
280 * on screen for animations.
281 */
282 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>();
283
284 /**
285 * List of window tokens that have finished starting their application,
286 * and now need to have the policy remove their windows.
287 */
288 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
289
290 /**
291 * Z-ordered (bottom-most first) list of all Window objects.
292 */
293 final ArrayList mWindows = new ArrayList();
294
295 /**
296 * Windows that are being resized. Used so we can tell the client about
297 * the resize after closing the transaction in which we resized the
298 * underlying surface.
299 */
300 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
301
302 /**
303 * Windows whose animations have ended and now must be removed.
304 */
305 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
306
307 /**
308 * Windows whose surface should be destroyed.
309 */
310 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
311
312 /**
313 * Windows that have lost input focus and are waiting for the new
314 * focus window to be displayed before they are told about this.
315 */
316 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
317
318 /**
319 * This is set when we have run out of memory, and will either be an empty
320 * list or contain windows that need to be force removed.
321 */
322 ArrayList<WindowState> mForceRemoves;
Romain Guy06882f82009-06-10 13:36:04 -0700323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 IInputMethodManager mInputMethodManager;
Romain Guy06882f82009-06-10 13:36:04 -0700325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 SurfaceSession mFxSession;
327 Surface mDimSurface;
328 boolean mDimShown;
329 float mDimCurrentAlpha;
330 float mDimTargetAlpha;
331 float mDimDeltaPerMs;
332 long mLastDimAnimTime;
333 Surface mBlurSurface;
334 boolean mBlurShown;
Romain Guy06882f82009-06-10 13:36:04 -0700335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 int mTransactionSequence = 0;
Romain Guy06882f82009-06-10 13:36:04 -0700337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 final float[] mTmpFloats = new float[9];
339
340 boolean mSafeMode;
341 boolean mDisplayEnabled = false;
342 boolean mSystemBooted = false;
343 int mRotation = 0;
344 int mRequestedRotation = 0;
345 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Dianne Hackborn321ae682009-03-27 16:16:03 -0700346 int mLastRotationFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 ArrayList<IRotationWatcher> mRotationWatchers
348 = new ArrayList<IRotationWatcher>();
Romain Guy06882f82009-06-10 13:36:04 -0700349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 boolean mLayoutNeeded = true;
351 boolean mAnimationPending = false;
352 boolean mDisplayFrozen = false;
353 boolean mWindowsFreezingScreen = false;
354 long mFreezeGcPending = 0;
355 int mAppsFreezingScreen = 0;
356
357 // This is held as long as we have the screen frozen, to give us time to
358 // perform a rotation animation when turning off shows the lock screen which
359 // changes the orientation.
360 PowerManager.WakeLock mScreenFrozenLock;
Romain Guy06882f82009-06-10 13:36:04 -0700361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 // State management of app transitions. When we are preparing for a
363 // transition, mNextAppTransition will be the kind of transition to
364 // perform or TRANSIT_NONE if we are not waiting. If we are waiting,
365 // mOpeningApps and mClosingApps are the lists of tokens that will be
366 // made visible or hidden at the next transition.
367 int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
368 boolean mAppTransitionReady = false;
369 boolean mAppTransitionTimeout = false;
370 boolean mStartingIconInTransition = false;
371 boolean mSkipAppTransitionAnimation = false;
372 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
373 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
Romain Guy06882f82009-06-10 13:36:04 -0700374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 //flag to detect fat touch events
376 boolean mFatTouch = false;
377 Display mDisplay;
Romain Guy06882f82009-06-10 13:36:04 -0700378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 H mH = new H();
380
381 WindowState mCurrentFocus = null;
382 WindowState mLastFocus = null;
Romain Guy06882f82009-06-10 13:36:04 -0700383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 // This just indicates the window the input method is on top of, not
385 // necessarily the window its input is going to.
386 WindowState mInputMethodTarget = null;
387 WindowState mUpcomingInputMethodTarget = null;
388 boolean mInputMethodTargetWaitingAnim;
389 int mInputMethodAnimLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -0700390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 WindowState mInputMethodWindow = null;
392 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
393
394 AppWindowToken mFocusedApp = null;
395
396 PowerManagerService mPowerManager;
Romain Guy06882f82009-06-10 13:36:04 -0700397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 float mWindowAnimationScale = 1.0f;
399 float mTransitionAnimationScale = 1.0f;
Romain Guy06882f82009-06-10 13:36:04 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 final KeyWaiter mKeyWaiter = new KeyWaiter();
402 final KeyQ mQueue;
403 final InputDispatcherThread mInputThread;
404
405 // Who is holding the screen on.
406 Session mHoldingScreenOn;
Romain Guy06882f82009-06-10 13:36:04 -0700407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 /**
409 * Whether the UI is currently running in touch mode (not showing
410 * navigational focus because the user is directly pressing the screen).
411 */
412 boolean mInTouchMode = false;
413
414 private ViewServer mViewServer;
415
416 final Rect mTempRect = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -0700417
Dianne Hackbornc485a602009-03-24 22:39:49 -0700418 final Configuration mTempConfiguration = new Configuration();
Dianne Hackborn723738c2009-06-25 19:48:04 -0700419 int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 public static WindowManagerService main(Context context,
422 PowerManagerService pm, boolean haveInputMethods) {
423 WMThread thr = new WMThread(context, pm, haveInputMethods);
424 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 synchronized (thr) {
427 while (thr.mService == null) {
428 try {
429 thr.wait();
430 } catch (InterruptedException e) {
431 }
432 }
433 }
Romain Guy06882f82009-06-10 13:36:04 -0700434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 return thr.mService;
436 }
Romain Guy06882f82009-06-10 13:36:04 -0700437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 static class WMThread extends Thread {
439 WindowManagerService mService;
Romain Guy06882f82009-06-10 13:36:04 -0700440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 private final Context mContext;
442 private final PowerManagerService mPM;
443 private final boolean mHaveInputMethods;
Romain Guy06882f82009-06-10 13:36:04 -0700444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 public WMThread(Context context, PowerManagerService pm,
446 boolean haveInputMethods) {
447 super("WindowManager");
448 mContext = context;
449 mPM = pm;
450 mHaveInputMethods = haveInputMethods;
451 }
Romain Guy06882f82009-06-10 13:36:04 -0700452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 public void run() {
454 Looper.prepare();
455 WindowManagerService s = new WindowManagerService(mContext, mPM,
456 mHaveInputMethods);
457 android.os.Process.setThreadPriority(
458 android.os.Process.THREAD_PRIORITY_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 synchronized (this) {
461 mService = s;
462 notifyAll();
463 }
Romain Guy06882f82009-06-10 13:36:04 -0700464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 Looper.loop();
466 }
467 }
468
469 static class PolicyThread extends Thread {
470 private final WindowManagerPolicy mPolicy;
471 private final WindowManagerService mService;
472 private final Context mContext;
473 private final PowerManagerService mPM;
474 boolean mRunning = false;
Romain Guy06882f82009-06-10 13:36:04 -0700475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 public PolicyThread(WindowManagerPolicy policy,
477 WindowManagerService service, Context context,
478 PowerManagerService pm) {
479 super("WindowManagerPolicy");
480 mPolicy = policy;
481 mService = service;
482 mContext = context;
483 mPM = pm;
484 }
Romain Guy06882f82009-06-10 13:36:04 -0700485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 public void run() {
487 Looper.prepare();
488 //Looper.myLooper().setMessageLogging(new LogPrinter(
489 // Log.VERBOSE, "WindowManagerPolicy"));
490 android.os.Process.setThreadPriority(
491 android.os.Process.THREAD_PRIORITY_FOREGROUND);
492 mPolicy.init(mContext, mService, mPM);
Romain Guy06882f82009-06-10 13:36:04 -0700493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 synchronized (this) {
495 mRunning = true;
496 notifyAll();
497 }
Romain Guy06882f82009-06-10 13:36:04 -0700498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 Looper.loop();
500 }
501 }
502
503 private WindowManagerService(Context context, PowerManagerService pm,
504 boolean haveInputMethods) {
505 mContext = context;
506 mHaveInputMethods = haveInputMethods;
507 mLimitedAlphaCompositing = context.getResources().getBoolean(
508 com.android.internal.R.bool.config_sf_limitedAlpha);
Romain Guy06882f82009-06-10 13:36:04 -0700509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 mPowerManager = pm;
511 mPowerManager.setPolicy(mPolicy);
512 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
513 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
514 "SCREEN_FROZEN");
515 mScreenFrozenLock.setReferenceCounted(false);
516
517 mActivityManager = ActivityManagerNative.getDefault();
518 mBatteryStats = BatteryStatsService.getService();
519
520 // Get persisted window scale setting
521 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
522 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
523 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
524 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
Romain Guy06882f82009-06-10 13:36:04 -0700525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 mQueue = new KeyQ();
527
528 mInputThread = new InputDispatcherThread();
Romain Guy06882f82009-06-10 13:36:04 -0700529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
531 thr.start();
Romain Guy06882f82009-06-10 13:36:04 -0700532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 synchronized (thr) {
534 while (!thr.mRunning) {
535 try {
536 thr.wait();
537 } catch (InterruptedException e) {
538 }
539 }
540 }
Romain Guy06882f82009-06-10 13:36:04 -0700541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 mInputThread.start();
Romain Guy06882f82009-06-10 13:36:04 -0700543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 // Add ourself to the Watchdog monitors.
545 Watchdog.getInstance().addMonitor(this);
546 }
547
548 @Override
549 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
550 throws RemoteException {
551 try {
552 return super.onTransact(code, data, reply, flags);
553 } catch (RuntimeException e) {
554 // The window manager only throws security exceptions, so let's
555 // log all others.
556 if (!(e instanceof SecurityException)) {
557 Log.e(TAG, "Window Manager Crash", e);
558 }
559 throw e;
560 }
561 }
562
563 private void placeWindowAfter(Object pos, WindowState window) {
564 final int i = mWindows.indexOf(pos);
565 if (localLOGV || DEBUG_FOCUS) Log.v(
566 TAG, "Adding window " + window + " at "
567 + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
568 mWindows.add(i+1, window);
569 }
570
571 private void placeWindowBefore(Object pos, WindowState window) {
572 final int i = mWindows.indexOf(pos);
573 if (localLOGV || DEBUG_FOCUS) Log.v(
574 TAG, "Adding window " + window + " at "
575 + i + " of " + mWindows.size() + " (before " + pos + ")");
576 mWindows.add(i, window);
577 }
578
579 //This method finds out the index of a window that has the same app token as
580 //win. used for z ordering the windows in mWindows
581 private int findIdxBasedOnAppTokens(WindowState win) {
582 //use a local variable to cache mWindows
583 ArrayList localmWindows = mWindows;
584 int jmax = localmWindows.size();
585 if(jmax == 0) {
586 return -1;
587 }
588 for(int j = (jmax-1); j >= 0; j--) {
589 WindowState wentry = (WindowState)localmWindows.get(j);
590 if(wentry.mAppToken == win.mAppToken) {
591 return j;
592 }
593 }
594 return -1;
595 }
Romain Guy06882f82009-06-10 13:36:04 -0700596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
598 final IWindow client = win.mClient;
599 final WindowToken token = win.mToken;
600 final ArrayList localmWindows = mWindows;
Romain Guy06882f82009-06-10 13:36:04 -0700601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 final int N = localmWindows.size();
603 final WindowState attached = win.mAttachedWindow;
604 int i;
605 if (attached == null) {
606 int tokenWindowsPos = token.windows.size();
607 if (token.appWindowToken != null) {
608 int index = tokenWindowsPos-1;
609 if (index >= 0) {
610 // If this application has existing windows, we
611 // simply place the new window on top of them... but
612 // keep the starting window on top.
613 if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
614 // Base windows go behind everything else.
615 placeWindowBefore(token.windows.get(0), win);
616 tokenWindowsPos = 0;
617 } else {
618 AppWindowToken atoken = win.mAppToken;
619 if (atoken != null &&
620 token.windows.get(index) == atoken.startingWindow) {
621 placeWindowBefore(token.windows.get(index), win);
622 tokenWindowsPos--;
623 } else {
624 int newIdx = findIdxBasedOnAppTokens(win);
625 if(newIdx != -1) {
Romain Guy06882f82009-06-10 13:36:04 -0700626 //there is a window above this one associated with the same
627 //apptoken note that the window could be a floating window
628 //that was created later or a window at the top of the list of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 //windows associated with this token.
630 localmWindows.add(newIdx+1, win);
Romain Guy06882f82009-06-10 13:36:04 -0700631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
633 }
634 } else {
635 if (localLOGV) Log.v(
636 TAG, "Figuring out where to add app window "
637 + client.asBinder() + " (token=" + token + ")");
638 // Figure out where the window should go, based on the
639 // order of applications.
640 final int NA = mAppTokens.size();
641 Object pos = null;
642 for (i=NA-1; i>=0; i--) {
643 AppWindowToken t = mAppTokens.get(i);
644 if (t == token) {
645 i--;
646 break;
647 }
648 if (t.windows.size() > 0) {
649 pos = t.windows.get(0);
650 }
651 }
652 // We now know the index into the apps. If we found
653 // an app window above, that gives us the position; else
654 // we need to look some more.
655 if (pos != null) {
656 // Move behind any windows attached to this one.
Romain Guy06882f82009-06-10 13:36:04 -0700657 WindowToken atoken =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 mTokenMap.get(((WindowState)pos).mClient.asBinder());
659 if (atoken != null) {
660 final int NC = atoken.windows.size();
661 if (NC > 0) {
662 WindowState bottom = atoken.windows.get(0);
663 if (bottom.mSubLayer < 0) {
664 pos = bottom;
665 }
666 }
667 }
668 placeWindowBefore(pos, win);
669 } else {
670 while (i >= 0) {
671 AppWindowToken t = mAppTokens.get(i);
672 final int NW = t.windows.size();
673 if (NW > 0) {
674 pos = t.windows.get(NW-1);
675 break;
676 }
677 i--;
678 }
679 if (pos != null) {
680 // Move in front of any windows attached to this
681 // one.
682 WindowToken atoken =
683 mTokenMap.get(((WindowState)pos).mClient.asBinder());
684 if (atoken != null) {
685 final int NC = atoken.windows.size();
686 if (NC > 0) {
687 WindowState top = atoken.windows.get(NC-1);
688 if (top.mSubLayer >= 0) {
689 pos = top;
690 }
691 }
692 }
693 placeWindowAfter(pos, win);
694 } else {
695 // Just search for the start of this layer.
696 final int myLayer = win.mBaseLayer;
697 for (i=0; i<N; i++) {
698 WindowState w = (WindowState)localmWindows.get(i);
699 if (w.mBaseLayer > myLayer) {
700 break;
701 }
702 }
703 if (localLOGV || DEBUG_FOCUS) Log.v(
704 TAG, "Adding window " + win + " at "
705 + i + " of " + N);
706 localmWindows.add(i, win);
707 }
708 }
709 }
710 } else {
711 // Figure out where window should go, based on layer.
712 final int myLayer = win.mBaseLayer;
713 for (i=N-1; i>=0; i--) {
714 if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) {
715 i++;
716 break;
717 }
718 }
719 if (i < 0) i = 0;
720 if (localLOGV || DEBUG_FOCUS) Log.v(
721 TAG, "Adding window " + win + " at "
722 + i + " of " + N);
723 localmWindows.add(i, win);
724 }
725 if (addToToken) {
726 token.windows.add(tokenWindowsPos, win);
727 }
728
729 } else {
730 // Figure out this window's ordering relative to the window
731 // it is attached to.
732 final int NA = token.windows.size();
733 final int sublayer = win.mSubLayer;
734 int largestSublayer = Integer.MIN_VALUE;
735 WindowState windowWithLargestSublayer = null;
736 for (i=0; i<NA; i++) {
737 WindowState w = token.windows.get(i);
738 final int wSublayer = w.mSubLayer;
739 if (wSublayer >= largestSublayer) {
740 largestSublayer = wSublayer;
741 windowWithLargestSublayer = w;
742 }
743 if (sublayer < 0) {
744 // For negative sublayers, we go below all windows
745 // in the same sublayer.
746 if (wSublayer >= sublayer) {
747 if (addToToken) {
748 token.windows.add(i, win);
749 }
750 placeWindowBefore(
751 wSublayer >= 0 ? attached : w, win);
752 break;
753 }
754 } else {
755 // For positive sublayers, we go above all windows
756 // in the same sublayer.
757 if (wSublayer > sublayer) {
758 if (addToToken) {
759 token.windows.add(i, win);
760 }
761 placeWindowBefore(w, win);
762 break;
763 }
764 }
765 }
766 if (i >= NA) {
767 if (addToToken) {
768 token.windows.add(win);
769 }
770 if (sublayer < 0) {
771 placeWindowBefore(attached, win);
772 } else {
773 placeWindowAfter(largestSublayer >= 0
774 ? windowWithLargestSublayer
775 : attached,
776 win);
777 }
778 }
779 }
Romain Guy06882f82009-06-10 13:36:04 -0700780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 if (win.mAppToken != null && addToToken) {
782 win.mAppToken.allAppWindows.add(win);
783 }
784 }
Romain Guy06882f82009-06-10 13:36:04 -0700785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 static boolean canBeImeTarget(WindowState w) {
787 final int fl = w.mAttrs.flags
788 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
789 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
790 return w.isVisibleOrAdding();
791 }
792 return false;
793 }
Romain Guy06882f82009-06-10 13:36:04 -0700794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
796 final ArrayList localmWindows = mWindows;
797 final int N = localmWindows.size();
798 WindowState w = null;
799 int i = N;
800 while (i > 0) {
801 i--;
802 w = (WindowState)localmWindows.get(i);
Romain Guy06882f82009-06-10 13:36:04 -0700803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
805 // + Integer.toHexString(w.mAttrs.flags));
806 if (canBeImeTarget(w)) {
807 //Log.i(TAG, "Putting input method here!");
Romain Guy06882f82009-06-10 13:36:04 -0700808
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 // Yet more tricksyness! If this window is a "starting"
810 // window, we do actually want to be on top of it, but
811 // it is not -really- where input will go. So if the caller
812 // is not actually looking to move the IME, look down below
813 // for a real window to target...
814 if (!willMove
815 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
816 && i > 0) {
817 WindowState wb = (WindowState)localmWindows.get(i-1);
818 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
819 i--;
820 w = wb;
821 }
822 }
823 break;
824 }
825 }
Romain Guy06882f82009-06-10 13:36:04 -0700826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 mUpcomingInputMethodTarget = w;
Romain Guy06882f82009-06-10 13:36:04 -0700828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
830 + w + " willMove=" + willMove);
Romain Guy06882f82009-06-10 13:36:04 -0700831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 if (willMove && w != null) {
833 final WindowState curTarget = mInputMethodTarget;
834 if (curTarget != null && curTarget.mAppToken != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 // Now some fun for dealing with window animations that
837 // modify the Z order. We need to look at all windows below
838 // the current target that are in this app, finding the highest
839 // visible one in layering.
840 AppWindowToken token = curTarget.mAppToken;
841 WindowState highestTarget = null;
842 int highestPos = 0;
843 if (token.animating || token.animation != null) {
844 int pos = 0;
845 pos = localmWindows.indexOf(curTarget);
846 while (pos >= 0) {
847 WindowState win = (WindowState)localmWindows.get(pos);
848 if (win.mAppToken != token) {
849 break;
850 }
851 if (!win.mRemoved) {
852 if (highestTarget == null || win.mAnimLayer >
853 highestTarget.mAnimLayer) {
854 highestTarget = win;
855 highestPos = pos;
856 }
857 }
858 pos--;
859 }
860 }
Romain Guy06882f82009-06-10 13:36:04 -0700861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 if (highestTarget != null) {
Romain Guy06882f82009-06-10 13:36:04 -0700863 if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 + mNextAppTransition + " " + highestTarget
865 + " animating=" + highestTarget.isAnimating()
866 + " layer=" + highestTarget.mAnimLayer
867 + " new layer=" + w.mAnimLayer);
Romain Guy06882f82009-06-10 13:36:04 -0700868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
870 // If we are currently setting up for an animation,
871 // hold everything until we can find out what will happen.
872 mInputMethodTargetWaitingAnim = true;
873 mInputMethodTarget = highestTarget;
874 return highestPos + 1;
875 } else if (highestTarget.isAnimating() &&
876 highestTarget.mAnimLayer > w.mAnimLayer) {
877 // If the window we are currently targeting is involved
878 // with an animation, and it is on top of the next target
879 // we will be over, then hold off on moving until
880 // that is done.
881 mInputMethodTarget = highestTarget;
882 return highestPos + 1;
883 }
884 }
885 }
886 }
Romain Guy06882f82009-06-10 13:36:04 -0700887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 //Log.i(TAG, "Placing input method @" + (i+1));
889 if (w != null) {
890 if (willMove) {
891 RuntimeException e = new RuntimeException();
892 e.fillInStackTrace();
893 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
894 + mInputMethodTarget + " to " + w, e);
895 mInputMethodTarget = w;
896 if (w.mAppToken != null) {
897 setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
898 } else {
899 setInputMethodAnimLayerAdjustment(0);
900 }
901 }
902 return i+1;
903 }
904 if (willMove) {
905 RuntimeException e = new RuntimeException();
906 e.fillInStackTrace();
907 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
908 + mInputMethodTarget + " to null", e);
909 mInputMethodTarget = null;
910 setInputMethodAnimLayerAdjustment(0);
911 }
912 return -1;
913 }
Romain Guy06882f82009-06-10 13:36:04 -0700914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 void addInputMethodWindowToListLocked(WindowState win) {
916 int pos = findDesiredInputMethodWindowIndexLocked(true);
917 if (pos >= 0) {
918 win.mTargetAppToken = mInputMethodTarget.mAppToken;
919 mWindows.add(pos, win);
920 moveInputMethodDialogsLocked(pos+1);
921 return;
922 }
923 win.mTargetAppToken = null;
924 addWindowToListInOrderLocked(win, true);
925 moveInputMethodDialogsLocked(pos);
926 }
Romain Guy06882f82009-06-10 13:36:04 -0700927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 void setInputMethodAnimLayerAdjustment(int adj) {
929 if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
930 mInputMethodAnimLayerAdjustment = adj;
931 WindowState imw = mInputMethodWindow;
932 if (imw != null) {
933 imw.mAnimLayer = imw.mLayer + adj;
934 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
935 + " anim layer: " + imw.mAnimLayer);
936 int wi = imw.mChildWindows.size();
937 while (wi > 0) {
938 wi--;
939 WindowState cw = (WindowState)imw.mChildWindows.get(wi);
940 cw.mAnimLayer = cw.mLayer + adj;
941 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
942 + " anim layer: " + cw.mAnimLayer);
943 }
944 }
945 int di = mInputMethodDialogs.size();
946 while (di > 0) {
947 di --;
948 imw = mInputMethodDialogs.get(di);
949 imw.mAnimLayer = imw.mLayer + adj;
950 if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
951 + " anim layer: " + imw.mAnimLayer);
952 }
953 }
Romain Guy06882f82009-06-10 13:36:04 -0700954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
956 int wpos = mWindows.indexOf(win);
957 if (wpos >= 0) {
958 if (wpos < interestingPos) interestingPos--;
959 mWindows.remove(wpos);
960 int NC = win.mChildWindows.size();
961 while (NC > 0) {
962 NC--;
963 WindowState cw = (WindowState)win.mChildWindows.get(NC);
964 int cpos = mWindows.indexOf(cw);
965 if (cpos >= 0) {
966 if (cpos < interestingPos) interestingPos--;
967 mWindows.remove(cpos);
968 }
969 }
970 }
971 return interestingPos;
972 }
Romain Guy06882f82009-06-10 13:36:04 -0700973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 private void reAddWindowToListInOrderLocked(WindowState win) {
975 addWindowToListInOrderLocked(win, false);
976 // This is a hack to get all of the child windows added as well
977 // at the right position. Child windows should be rare and
978 // this case should be rare, so it shouldn't be that big a deal.
979 int wpos = mWindows.indexOf(win);
980 if (wpos >= 0) {
981 mWindows.remove(wpos);
982 reAddWindowLocked(wpos, win);
983 }
984 }
Romain Guy06882f82009-06-10 13:36:04 -0700985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 void logWindowList(String prefix) {
987 int N = mWindows.size();
988 while (N > 0) {
989 N--;
990 Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
991 }
992 }
Romain Guy06882f82009-06-10 13:36:04 -0700993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 void moveInputMethodDialogsLocked(int pos) {
995 ArrayList<WindowState> dialogs = mInputMethodDialogs;
Romain Guy06882f82009-06-10 13:36:04 -0700996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 final int N = dialogs.size();
998 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
999 for (int i=0; i<N; i++) {
1000 pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
1001 }
1002 if (DEBUG_INPUT_METHOD) {
1003 Log.v(TAG, "Window list w/pos=" + pos);
1004 logWindowList(" ");
1005 }
Romain Guy06882f82009-06-10 13:36:04 -07001006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 if (pos >= 0) {
1008 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
1009 if (pos < mWindows.size()) {
1010 WindowState wp = (WindowState)mWindows.get(pos);
1011 if (wp == mInputMethodWindow) {
1012 pos++;
1013 }
1014 }
1015 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
1016 for (int i=0; i<N; i++) {
1017 WindowState win = dialogs.get(i);
1018 win.mTargetAppToken = targetAppToken;
1019 pos = reAddWindowLocked(pos, win);
1020 }
1021 if (DEBUG_INPUT_METHOD) {
1022 Log.v(TAG, "Final window list:");
1023 logWindowList(" ");
1024 }
1025 return;
1026 }
1027 for (int i=0; i<N; i++) {
1028 WindowState win = dialogs.get(i);
1029 win.mTargetAppToken = null;
1030 reAddWindowToListInOrderLocked(win);
1031 if (DEBUG_INPUT_METHOD) {
1032 Log.v(TAG, "No IM target, final list:");
1033 logWindowList(" ");
1034 }
1035 }
1036 }
Romain Guy06882f82009-06-10 13:36:04 -07001037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
1039 final WindowState imWin = mInputMethodWindow;
1040 final int DN = mInputMethodDialogs.size();
1041 if (imWin == null && DN == 0) {
1042 return false;
1043 }
Romain Guy06882f82009-06-10 13:36:04 -07001044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 int imPos = findDesiredInputMethodWindowIndexLocked(true);
1046 if (imPos >= 0) {
1047 // In this case, the input method windows are to be placed
1048 // immediately above the window they are targeting.
Romain Guy06882f82009-06-10 13:36:04 -07001049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 // First check to see if the input method windows are already
1051 // located here, and contiguous.
1052 final int N = mWindows.size();
1053 WindowState firstImWin = imPos < N
1054 ? (WindowState)mWindows.get(imPos) : null;
Romain Guy06882f82009-06-10 13:36:04 -07001055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 // Figure out the actual input method window that should be
1057 // at the bottom of their stack.
1058 WindowState baseImWin = imWin != null
1059 ? imWin : mInputMethodDialogs.get(0);
1060 if (baseImWin.mChildWindows.size() > 0) {
1061 WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
1062 if (cw.mSubLayer < 0) baseImWin = cw;
1063 }
Romain Guy06882f82009-06-10 13:36:04 -07001064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 if (firstImWin == baseImWin) {
1066 // The windows haven't moved... but are they still contiguous?
1067 // First find the top IM window.
1068 int pos = imPos+1;
1069 while (pos < N) {
1070 if (!((WindowState)mWindows.get(pos)).mIsImWindow) {
1071 break;
1072 }
1073 pos++;
1074 }
1075 pos++;
1076 // Now there should be no more input method windows above.
1077 while (pos < N) {
1078 if (((WindowState)mWindows.get(pos)).mIsImWindow) {
1079 break;
1080 }
1081 pos++;
1082 }
1083 if (pos >= N) {
1084 // All is good!
1085 return false;
1086 }
1087 }
Romain Guy06882f82009-06-10 13:36:04 -07001088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 if (imWin != null) {
1090 if (DEBUG_INPUT_METHOD) {
1091 Log.v(TAG, "Moving IM from " + imPos);
1092 logWindowList(" ");
1093 }
1094 imPos = tmpRemoveWindowLocked(imPos, imWin);
1095 if (DEBUG_INPUT_METHOD) {
1096 Log.v(TAG, "List after moving with new pos " + imPos + ":");
1097 logWindowList(" ");
1098 }
1099 imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
1100 reAddWindowLocked(imPos, imWin);
1101 if (DEBUG_INPUT_METHOD) {
1102 Log.v(TAG, "List after moving IM to " + imPos + ":");
1103 logWindowList(" ");
1104 }
1105 if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
1106 } else {
1107 moveInputMethodDialogsLocked(imPos);
1108 }
Romain Guy06882f82009-06-10 13:36:04 -07001109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 } else {
1111 // In this case, the input method windows go in a fixed layer,
1112 // because they aren't currently associated with a focus window.
Romain Guy06882f82009-06-10 13:36:04 -07001113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 if (imWin != null) {
1115 if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
1116 tmpRemoveWindowLocked(0, imWin);
1117 imWin.mTargetAppToken = null;
1118 reAddWindowToListInOrderLocked(imWin);
1119 if (DEBUG_INPUT_METHOD) {
1120 Log.v(TAG, "List with no IM target:");
1121 logWindowList(" ");
1122 }
1123 if (DN > 0) moveInputMethodDialogsLocked(-1);;
1124 } else {
1125 moveInputMethodDialogsLocked(-1);;
1126 }
Romain Guy06882f82009-06-10 13:36:04 -07001127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
Romain Guy06882f82009-06-10 13:36:04 -07001129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 if (needAssignLayers) {
1131 assignLayersLocked();
1132 }
Romain Guy06882f82009-06-10 13:36:04 -07001133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 return true;
1135 }
Romain Guy06882f82009-06-10 13:36:04 -07001136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 void adjustInputMethodDialogsLocked() {
1138 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
1139 }
Romain Guy06882f82009-06-10 13:36:04 -07001140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 public int addWindow(Session session, IWindow client,
1142 WindowManager.LayoutParams attrs, int viewVisibility,
1143 Rect outContentInsets) {
1144 int res = mPolicy.checkAddPermission(attrs);
1145 if (res != WindowManagerImpl.ADD_OKAY) {
1146 return res;
1147 }
Romain Guy06882f82009-06-10 13:36:04 -07001148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 boolean reportNewConfig = false;
1150 WindowState attachedWindow = null;
1151 WindowState win = null;
Romain Guy06882f82009-06-10 13:36:04 -07001152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 synchronized(mWindowMap) {
1154 // Instantiating a Display requires talking with the simulator,
1155 // so don't do it until we know the system is mostly up and
1156 // running.
1157 if (mDisplay == null) {
1158 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1159 mDisplay = wm.getDefaultDisplay();
1160 mQueue.setDisplay(mDisplay);
1161 reportNewConfig = true;
1162 }
Romain Guy06882f82009-06-10 13:36:04 -07001163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 if (mWindowMap.containsKey(client.asBinder())) {
1165 Log.w(TAG, "Window " + client + " is already added");
1166 return WindowManagerImpl.ADD_DUPLICATE_ADD;
1167 }
1168
1169 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
Romain Guy06882f82009-06-10 13:36:04 -07001170 attachedWindow = windowForClientLocked(null, attrs.token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 if (attachedWindow == null) {
1172 Log.w(TAG, "Attempted to add window with token that is not a window: "
1173 + attrs.token + ". Aborting.");
1174 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1175 }
1176 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
1177 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1178 Log.w(TAG, "Attempted to add window with token that is a sub-window: "
1179 + attrs.token + ". Aborting.");
1180 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
1181 }
1182 }
1183
1184 boolean addToken = false;
1185 WindowToken token = mTokenMap.get(attrs.token);
1186 if (token == null) {
1187 if (attrs.type >= FIRST_APPLICATION_WINDOW
1188 && attrs.type <= LAST_APPLICATION_WINDOW) {
1189 Log.w(TAG, "Attempted to add application window with unknown token "
1190 + attrs.token + ". Aborting.");
1191 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1192 }
1193 if (attrs.type == TYPE_INPUT_METHOD) {
1194 Log.w(TAG, "Attempted to add input method window with unknown token "
1195 + attrs.token + ". Aborting.");
1196 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1197 }
1198 token = new WindowToken(attrs.token, -1, false);
1199 addToken = true;
1200 } else if (attrs.type >= FIRST_APPLICATION_WINDOW
1201 && attrs.type <= LAST_APPLICATION_WINDOW) {
1202 AppWindowToken atoken = token.appWindowToken;
1203 if (atoken == null) {
1204 Log.w(TAG, "Attempted to add window with non-application token "
1205 + token + ". Aborting.");
1206 return WindowManagerImpl.ADD_NOT_APP_TOKEN;
1207 } else if (atoken.removed) {
1208 Log.w(TAG, "Attempted to add window with exiting application token "
1209 + token + ". Aborting.");
1210 return WindowManagerImpl.ADD_APP_EXITING;
1211 }
1212 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
1213 // No need for this guy!
1214 if (localLOGV) Log.v(
1215 TAG, "**** NO NEED TO START: " + attrs.getTitle());
1216 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
1217 }
1218 } else if (attrs.type == TYPE_INPUT_METHOD) {
1219 if (token.windowType != TYPE_INPUT_METHOD) {
1220 Log.w(TAG, "Attempted to add input method window with bad token "
1221 + attrs.token + ". Aborting.");
1222 return WindowManagerImpl.ADD_BAD_APP_TOKEN;
1223 }
1224 }
1225
1226 win = new WindowState(session, client, token,
1227 attachedWindow, attrs, viewVisibility);
1228 if (win.mDeathRecipient == null) {
1229 // Client has apparently died, so there is no reason to
1230 // continue.
1231 Log.w(TAG, "Adding window client " + client.asBinder()
1232 + " that is dead, aborting.");
1233 return WindowManagerImpl.ADD_APP_EXITING;
1234 }
1235
1236 mPolicy.adjustWindowParamsLw(win.mAttrs);
Romain Guy06882f82009-06-10 13:36:04 -07001237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 res = mPolicy.prepareAddWindowLw(win, attrs);
1239 if (res != WindowManagerImpl.ADD_OKAY) {
1240 return res;
1241 }
1242
1243 // From now on, no exceptions or errors allowed!
1244
1245 res = WindowManagerImpl.ADD_OKAY;
Romain Guy06882f82009-06-10 13:36:04 -07001246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 if (addToken) {
1250 mTokenMap.put(attrs.token, token);
1251 mTokenList.add(token);
1252 }
1253 win.attach();
1254 mWindowMap.put(client.asBinder(), win);
1255
1256 if (attrs.type == TYPE_APPLICATION_STARTING &&
1257 token.appWindowToken != null) {
1258 token.appWindowToken.startingWindow = win;
1259 }
1260
1261 boolean imMayMove = true;
Romain Guy06882f82009-06-10 13:36:04 -07001262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 if (attrs.type == TYPE_INPUT_METHOD) {
1264 mInputMethodWindow = win;
1265 addInputMethodWindowToListLocked(win);
1266 imMayMove = false;
1267 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
1268 mInputMethodDialogs.add(win);
1269 addWindowToListInOrderLocked(win, true);
1270 adjustInputMethodDialogsLocked();
1271 imMayMove = false;
1272 } else {
1273 addWindowToListInOrderLocked(win, true);
1274 }
Romain Guy06882f82009-06-10 13:36:04 -07001275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 win.mEnterAnimationPending = true;
Romain Guy06882f82009-06-10 13:36:04 -07001277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
Romain Guy06882f82009-06-10 13:36:04 -07001279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 if (mInTouchMode) {
1281 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
1282 }
1283 if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
1284 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
1285 }
Romain Guy06882f82009-06-10 13:36:04 -07001286
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001287 boolean focusChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 if (win.canReceiveKeys()) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001289 if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
1290 == true) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 imMayMove = false;
1292 }
1293 }
Romain Guy06882f82009-06-10 13:36:04 -07001294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 if (imMayMove) {
Romain Guy06882f82009-06-10 13:36:04 -07001296 moveInputMethodWindowsIfNeededLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 }
Romain Guy06882f82009-06-10 13:36:04 -07001298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 assignLayersLocked();
1300 // Don't do layout here, the window must call
1301 // relayout to be displayed, so we'll do it there.
Romain Guy06882f82009-06-10 13:36:04 -07001302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 //dump();
1304
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001305 if (focusChanged) {
1306 if (mCurrentFocus != null) {
1307 mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
1308 }
1309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 if (localLOGV) Log.v(
1311 TAG, "New client " + client.asBinder()
1312 + ": window=" + win);
1313 }
1314
1315 // sendNewConfiguration() checks caller permissions so we must call it with
1316 // privilege. updateOrientationFromAppTokens() clears and resets the caller
1317 // identity anyway, so it's safe to just clear & restore around this whole
1318 // block.
1319 final long origId = Binder.clearCallingIdentity();
1320 if (reportNewConfig) {
1321 sendNewConfiguration();
1322 } else {
1323 // Update Orientation after adding a window, only if the window needs to be
1324 // displayed right away
1325 if (win.isVisibleOrAdding()) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001326 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 sendNewConfiguration();
1328 }
1329 }
1330 }
1331 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 return res;
1334 }
Romain Guy06882f82009-06-10 13:36:04 -07001335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 public void removeWindow(Session session, IWindow client) {
1337 synchronized(mWindowMap) {
1338 WindowState win = windowForClientLocked(session, client);
1339 if (win == null) {
1340 return;
1341 }
1342 removeWindowLocked(session, win);
1343 }
1344 }
Romain Guy06882f82009-06-10 13:36:04 -07001345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 public void removeWindowLocked(Session session, WindowState win) {
1347
1348 if (localLOGV || DEBUG_FOCUS) Log.v(
1349 TAG, "Remove " + win + " client="
1350 + Integer.toHexString(System.identityHashCode(
1351 win.mClient.asBinder()))
1352 + ", surface=" + win.mSurface);
1353
1354 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 if (DEBUG_APP_TRANSITIONS) Log.v(
1357 TAG, "Remove " + win + ": mSurface=" + win.mSurface
1358 + " mExiting=" + win.mExiting
1359 + " isAnimating=" + win.isAnimating()
1360 + " app-animation="
1361 + (win.mAppToken != null ? win.mAppToken.animation : null)
1362 + " inPendingTransaction="
1363 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
1364 + " mDisplayFrozen=" + mDisplayFrozen);
1365 // Visibility of the removed window. Will be used later to update orientation later on.
1366 boolean wasVisible = false;
1367 // First, see if we need to run an animation. If we do, we have
1368 // to hold off on removing the window until the animation is done.
1369 // If the display is frozen, just remove immediately, since the
1370 // animation wouldn't be seen.
1371 if (win.mSurface != null && !mDisplayFrozen) {
1372 // If we are not currently running the exit animation, we
1373 // need to see about starting one.
1374 if (wasVisible=win.isWinVisibleLw()) {
Romain Guy06882f82009-06-10 13:36:04 -07001375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1377 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1378 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1379 }
1380 // Try starting an animation.
1381 if (applyAnimationLocked(win, transit, false)) {
1382 win.mExiting = true;
1383 }
1384 }
1385 if (win.mExiting || win.isAnimating()) {
1386 // The exit animation is running... wait for it!
1387 //Log.i(TAG, "*** Running exit animation...");
1388 win.mExiting = true;
1389 win.mRemoveOnExit = true;
1390 mLayoutNeeded = true;
1391 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
1392 performLayoutAndPlaceSurfacesLocked();
1393 if (win.mAppToken != null) {
1394 win.mAppToken.updateReportedVisibilityLocked();
1395 }
1396 //dump();
1397 Binder.restoreCallingIdentity(origId);
1398 return;
1399 }
1400 }
1401
1402 removeWindowInnerLocked(session, win);
1403 // Removing a visible window will effect the computed orientation
1404 // So just update orientation if needed.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001405 if (wasVisible && computeForcedAppOrientationLocked()
1406 != mForcedAppOrientation) {
1407 mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 }
1409 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
1410 Binder.restoreCallingIdentity(origId);
1411 }
Romain Guy06882f82009-06-10 13:36:04 -07001412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 private void removeWindowInnerLocked(Session session, WindowState win) {
1414 mKeyWaiter.releasePendingPointerLocked(win.mSession);
1415 mKeyWaiter.releasePendingTrackballLocked(win.mSession);
Romain Guy06882f82009-06-10 13:36:04 -07001416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 win.mRemoved = true;
Romain Guy06882f82009-06-10 13:36:04 -07001418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 if (mInputMethodTarget == win) {
1420 moveInputMethodWindowsIfNeededLocked(false);
1421 }
Romain Guy06882f82009-06-10 13:36:04 -07001422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 mPolicy.removeWindowLw(win);
1424 win.removeLocked();
1425
1426 mWindowMap.remove(win.mClient.asBinder());
1427 mWindows.remove(win);
1428
1429 if (mInputMethodWindow == win) {
1430 mInputMethodWindow = null;
1431 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
1432 mInputMethodDialogs.remove(win);
1433 }
Romain Guy06882f82009-06-10 13:36:04 -07001434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 final WindowToken token = win.mToken;
1436 final AppWindowToken atoken = win.mAppToken;
1437 token.windows.remove(win);
1438 if (atoken != null) {
1439 atoken.allAppWindows.remove(win);
1440 }
1441 if (localLOGV) Log.v(
1442 TAG, "**** Removing window " + win + ": count="
1443 + token.windows.size());
1444 if (token.windows.size() == 0) {
1445 if (!token.explicit) {
1446 mTokenMap.remove(token.token);
1447 mTokenList.remove(token);
1448 } else if (atoken != null) {
1449 atoken.firstWindowDrawn = false;
1450 }
1451 }
1452
1453 if (atoken != null) {
1454 if (atoken.startingWindow == win) {
1455 atoken.startingWindow = null;
1456 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
1457 // If this is the last window and we had requested a starting
1458 // transition window, well there is no point now.
1459 atoken.startingData = null;
1460 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
1461 // If this is the last window except for a starting transition
1462 // window, we need to get rid of the starting transition.
1463 if (DEBUG_STARTING_WINDOW) {
1464 Log.v(TAG, "Schedule remove starting " + token
1465 + ": no more real windows");
1466 }
1467 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
1468 mH.sendMessage(m);
1469 }
1470 }
Romain Guy06882f82009-06-10 13:36:04 -07001471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 if (!mInLayout) {
1473 assignLayersLocked();
1474 mLayoutNeeded = true;
1475 performLayoutAndPlaceSurfacesLocked();
1476 if (win.mAppToken != null) {
1477 win.mAppToken.updateReportedVisibilityLocked();
1478 }
1479 }
1480 }
1481
1482 private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
1483 long origId = Binder.clearCallingIdentity();
1484 try {
1485 synchronized (mWindowMap) {
1486 WindowState w = windowForClientLocked(session, client);
1487 if ((w != null) && (w.mSurface != null)) {
1488 Surface.openTransaction();
1489 try {
1490 w.mSurface.setTransparentRegionHint(region);
1491 } finally {
1492 Surface.closeTransaction();
1493 }
1494 }
1495 }
1496 } finally {
1497 Binder.restoreCallingIdentity(origId);
1498 }
1499 }
1500
1501 void setInsetsWindow(Session session, IWindow client,
Romain Guy06882f82009-06-10 13:36:04 -07001502 int touchableInsets, Rect contentInsets,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 Rect visibleInsets) {
1504 long origId = Binder.clearCallingIdentity();
1505 try {
1506 synchronized (mWindowMap) {
1507 WindowState w = windowForClientLocked(session, client);
1508 if (w != null) {
1509 w.mGivenInsetsPending = false;
1510 w.mGivenContentInsets.set(contentInsets);
1511 w.mGivenVisibleInsets.set(visibleInsets);
1512 w.mTouchableInsets = touchableInsets;
1513 mLayoutNeeded = true;
1514 performLayoutAndPlaceSurfacesLocked();
1515 }
1516 }
1517 } finally {
1518 Binder.restoreCallingIdentity(origId);
1519 }
1520 }
Romain Guy06882f82009-06-10 13:36:04 -07001521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 public void getWindowDisplayFrame(Session session, IWindow client,
1523 Rect outDisplayFrame) {
1524 synchronized(mWindowMap) {
1525 WindowState win = windowForClientLocked(session, client);
1526 if (win == null) {
1527 outDisplayFrame.setEmpty();
1528 return;
1529 }
1530 outDisplayFrame.set(win.mDisplayFrame);
1531 }
1532 }
1533
1534 public int relayoutWindow(Session session, IWindow client,
1535 WindowManager.LayoutParams attrs, int requestedWidth,
1536 int requestedHeight, int viewVisibility, boolean insetsPending,
1537 Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
1538 Surface outSurface) {
1539 boolean displayed = false;
1540 boolean inTouchMode;
1541 Configuration newConfig = null;
1542 long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 synchronized(mWindowMap) {
1545 WindowState win = windowForClientLocked(session, client);
1546 if (win == null) {
1547 return 0;
1548 }
1549 win.mRequestedWidth = requestedWidth;
1550 win.mRequestedHeight = requestedHeight;
1551
1552 if (attrs != null) {
1553 mPolicy.adjustWindowParamsLw(attrs);
1554 }
Romain Guy06882f82009-06-10 13:36:04 -07001555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 int attrChanges = 0;
1557 int flagChanges = 0;
1558 if (attrs != null) {
1559 flagChanges = win.mAttrs.flags ^= attrs.flags;
1560 attrChanges = win.mAttrs.copyFrom(attrs);
1561 }
1562
1563 if (localLOGV) Log.v(
1564 TAG, "Relayout given client " + client.asBinder()
1565 + " (" + win.mAttrs.getTitle() + ")");
1566
1567
1568 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
1569 win.mAlpha = attrs.alpha;
1570 }
1571
1572 final boolean scaledWindow =
1573 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
1574
1575 if (scaledWindow) {
1576 // requested{Width|Height} Surface's physical size
1577 // attrs.{width|height} Size on screen
1578 win.mHScale = (attrs.width != requestedWidth) ?
1579 (attrs.width / (float)requestedWidth) : 1.0f;
1580 win.mVScale = (attrs.height != requestedHeight) ?
1581 (attrs.height / (float)requestedHeight) : 1.0f;
1582 }
1583
1584 boolean imMayMove = (flagChanges&(
1585 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
1586 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07001587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 boolean focusMayChange = win.mViewVisibility != viewVisibility
1589 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
1590 || (!win.mRelayoutCalled);
Romain Guy06882f82009-06-10 13:36:04 -07001591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 win.mRelayoutCalled = true;
1593 final int oldVisibility = win.mViewVisibility;
1594 win.mViewVisibility = viewVisibility;
1595 if (viewVisibility == View.VISIBLE &&
1596 (win.mAppToken == null || !win.mAppToken.clientHidden)) {
1597 displayed = !win.isVisibleLw();
1598 if (win.mExiting) {
1599 win.mExiting = false;
1600 win.mAnimation = null;
1601 }
1602 if (win.mDestroying) {
1603 win.mDestroying = false;
1604 mDestroySurface.remove(win);
1605 }
1606 if (oldVisibility == View.GONE) {
1607 win.mEnterAnimationPending = true;
1608 }
1609 if (displayed && win.mSurface != null && !win.mDrawPending
1610 && !win.mCommitDrawPending && !mDisplayFrozen) {
1611 applyEnterAnimationLocked(win);
1612 }
1613 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
1614 // To change the format, we need to re-build the surface.
1615 win.destroySurfaceLocked();
1616 displayed = true;
1617 }
1618 try {
1619 Surface surface = win.createSurfaceLocked();
1620 if (surface != null) {
1621 outSurface.copyFrom(surface);
1622 } else {
1623 outSurface.clear();
1624 }
1625 } catch (Exception e) {
1626 Log.w(TAG, "Exception thrown when creating surface for client "
1627 + client + " (" + win.mAttrs.getTitle() + ")",
1628 e);
1629 Binder.restoreCallingIdentity(origId);
1630 return 0;
1631 }
1632 if (displayed) {
1633 focusMayChange = true;
1634 }
1635 if (win.mAttrs.type == TYPE_INPUT_METHOD
1636 && mInputMethodWindow == null) {
1637 mInputMethodWindow = win;
1638 imMayMove = true;
1639 }
1640 } else {
1641 win.mEnterAnimationPending = false;
1642 if (win.mSurface != null) {
1643 // If we are not currently running the exit animation, we
1644 // need to see about starting one.
1645 if (!win.mExiting) {
1646 // Try starting an animation; if there isn't one, we
1647 // can destroy the surface right away.
1648 int transit = WindowManagerPolicy.TRANSIT_EXIT;
1649 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
1650 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
1651 }
1652 if (win.isWinVisibleLw() &&
1653 applyAnimationLocked(win, transit, false)) {
1654 win.mExiting = true;
1655 mKeyWaiter.finishedKey(session, client, true,
1656 KeyWaiter.RETURN_NOTHING);
1657 } else if (win.isAnimating()) {
1658 // Currently in a hide animation... turn this into
1659 // an exit.
1660 win.mExiting = true;
1661 } else {
1662 if (mInputMethodWindow == win) {
1663 mInputMethodWindow = null;
1664 }
1665 win.destroySurfaceLocked();
1666 }
1667 }
1668 }
1669 outSurface.clear();
1670 }
1671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 if (focusMayChange) {
1673 //System.out.println("Focus may change: " + win.mAttrs.getTitle());
1674 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 imMayMove = false;
1676 }
1677 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
1678 }
Romain Guy06882f82009-06-10 13:36:04 -07001679
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08001680 // updateFocusedWindowLocked() already assigned layers so we only need to
1681 // reassign them at this point if the IM window state gets shuffled
1682 boolean assignLayers = false;
Romain Guy06882f82009-06-10 13:36:04 -07001683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 if (imMayMove) {
1685 if (moveInputMethodWindowsIfNeededLocked(false)) {
1686 assignLayers = true;
1687 }
1688 }
Romain Guy06882f82009-06-10 13:36:04 -07001689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 mLayoutNeeded = true;
1691 win.mGivenInsetsPending = insetsPending;
1692 if (assignLayers) {
1693 assignLayersLocked();
1694 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001695 newConfig = updateOrientationFromAppTokensLocked(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 performLayoutAndPlaceSurfacesLocked();
1697 if (win.mAppToken != null) {
1698 win.mAppToken.updateReportedVisibilityLocked();
1699 }
1700 outFrame.set(win.mFrame);
1701 outContentInsets.set(win.mContentInsets);
1702 outVisibleInsets.set(win.mVisibleInsets);
1703 if (localLOGV) Log.v(
1704 TAG, "Relayout given client " + client.asBinder()
Romain Guy06882f82009-06-10 13:36:04 -07001705 + ", requestedWidth=" + requestedWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 + ", requestedHeight=" + requestedHeight
1707 + ", viewVisibility=" + viewVisibility
1708 + "\nRelayout returning frame=" + outFrame
1709 + ", surface=" + outSurface);
1710
1711 if (localLOGV || DEBUG_FOCUS) Log.v(
1712 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
1713
1714 inTouchMode = mInTouchMode;
1715 }
1716
1717 if (newConfig != null) {
1718 sendNewConfiguration();
1719 }
Romain Guy06882f82009-06-10 13:36:04 -07001720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 Binder.restoreCallingIdentity(origId);
Romain Guy06882f82009-06-10 13:36:04 -07001722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
1724 | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
1725 }
1726
1727 public void finishDrawingWindow(Session session, IWindow client) {
1728 final long origId = Binder.clearCallingIdentity();
1729 synchronized(mWindowMap) {
1730 WindowState win = windowForClientLocked(session, client);
1731 if (win != null && win.finishDrawingLocked()) {
1732 mLayoutNeeded = true;
1733 performLayoutAndPlaceSurfacesLocked();
1734 }
1735 }
1736 Binder.restoreCallingIdentity(origId);
1737 }
1738
1739 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
1740 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
1741 + (lp != null ? lp.packageName : null)
1742 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
1743 if (lp != null && lp.windowAnimations != 0) {
1744 // If this is a system resource, don't try to load it from the
1745 // application resources. It is nice to avoid loading application
1746 // resources if we can.
1747 String packageName = lp.packageName != null ? lp.packageName : "android";
1748 int resId = lp.windowAnimations;
1749 if ((resId&0xFF000000) == 0x01000000) {
1750 packageName = "android";
1751 }
1752 if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
1753 + packageName);
1754 return AttributeCache.instance().get(packageName, resId,
1755 com.android.internal.R.styleable.WindowAnimation);
1756 }
1757 return null;
1758 }
Romain Guy06882f82009-06-10 13:36:04 -07001759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 private void applyEnterAnimationLocked(WindowState win) {
1761 int transit = WindowManagerPolicy.TRANSIT_SHOW;
1762 if (win.mEnterAnimationPending) {
1763 win.mEnterAnimationPending = false;
1764 transit = WindowManagerPolicy.TRANSIT_ENTER;
1765 }
1766
1767 applyAnimationLocked(win, transit, true);
1768 }
1769
1770 private boolean applyAnimationLocked(WindowState win,
1771 int transit, boolean isEntrance) {
1772 if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
1773 // If we are trying to apply an animation, but already running
1774 // an animation of the same type, then just leave that one alone.
1775 return true;
1776 }
Romain Guy06882f82009-06-10 13:36:04 -07001777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 // Only apply an animation if the display isn't frozen. If it is
1779 // frozen, there is no reason to animate and it can cause strange
1780 // artifacts when we unfreeze the display if some different animation
1781 // is running.
1782 if (!mDisplayFrozen) {
1783 int anim = mPolicy.selectAnimationLw(win, transit);
1784 int attr = -1;
1785 Animation a = null;
1786 if (anim != 0) {
1787 a = AnimationUtils.loadAnimation(mContext, anim);
1788 } else {
1789 switch (transit) {
1790 case WindowManagerPolicy.TRANSIT_ENTER:
1791 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
1792 break;
1793 case WindowManagerPolicy.TRANSIT_EXIT:
1794 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
1795 break;
1796 case WindowManagerPolicy.TRANSIT_SHOW:
1797 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
1798 break;
1799 case WindowManagerPolicy.TRANSIT_HIDE:
1800 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
1801 break;
1802 }
1803 if (attr >= 0) {
1804 a = loadAnimation(win.mAttrs, attr);
1805 }
1806 }
1807 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
1808 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
1809 + " mAnimation=" + win.mAnimation
1810 + " isEntrance=" + isEntrance);
1811 if (a != null) {
1812 if (DEBUG_ANIM) {
1813 RuntimeException e = new RuntimeException();
1814 e.fillInStackTrace();
1815 Log.v(TAG, "Loaded animation " + a + " for " + win, e);
1816 }
1817 win.setAnimation(a);
1818 win.mAnimationIsEntrance = isEntrance;
1819 }
1820 } else {
1821 win.clearAnimation();
1822 }
1823
1824 return win.mAnimation != null;
1825 }
1826
1827 private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
1828 int anim = 0;
1829 Context context = mContext;
1830 if (animAttr >= 0) {
1831 AttributeCache.Entry ent = getCachedAnimations(lp);
1832 if (ent != null) {
1833 context = ent.context;
1834 anim = ent.array.getResourceId(animAttr, 0);
1835 }
1836 }
1837 if (anim != 0) {
1838 return AnimationUtils.loadAnimation(context, anim);
1839 }
1840 return null;
1841 }
Romain Guy06882f82009-06-10 13:36:04 -07001842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 private boolean applyAnimationLocked(AppWindowToken wtoken,
1844 WindowManager.LayoutParams lp, int transit, boolean enter) {
1845 // Only apply an animation if the display isn't frozen. If it is
1846 // frozen, there is no reason to animate and it can cause strange
1847 // artifacts when we unfreeze the display if some different animation
1848 // is running.
1849 if (!mDisplayFrozen) {
1850 int animAttr = 0;
1851 switch (transit) {
1852 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
1853 animAttr = enter
1854 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
1855 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
1856 break;
1857 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
1858 animAttr = enter
1859 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
1860 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
1861 break;
1862 case WindowManagerPolicy.TRANSIT_TASK_OPEN:
1863 animAttr = enter
1864 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
1865 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
1866 break;
1867 case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
1868 animAttr = enter
1869 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
1870 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
1871 break;
1872 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
1873 animAttr = enter
1874 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
1875 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
1876 break;
1877 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
1878 animAttr = enter
1879 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
1880 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
1881 break;
1882 }
1883 Animation a = loadAnimation(lp, animAttr);
1884 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
1885 + " anim=" + a
1886 + " animAttr=0x" + Integer.toHexString(animAttr)
1887 + " transit=" + transit);
1888 if (a != null) {
1889 if (DEBUG_ANIM) {
1890 RuntimeException e = new RuntimeException();
1891 e.fillInStackTrace();
1892 Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
1893 }
1894 wtoken.setAnimation(a);
1895 }
1896 } else {
1897 wtoken.clearAnimation();
1898 }
1899
1900 return wtoken.animation != null;
1901 }
1902
1903 // -------------------------------------------------------------
1904 // Application Window Tokens
1905 // -------------------------------------------------------------
1906
1907 public void validateAppTokens(List tokens) {
1908 int v = tokens.size()-1;
1909 int m = mAppTokens.size()-1;
1910 while (v >= 0 && m >= 0) {
1911 AppWindowToken wtoken = mAppTokens.get(m);
1912 if (wtoken.removed) {
1913 m--;
1914 continue;
1915 }
1916 if (tokens.get(v) != wtoken.token) {
1917 Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
1918 + " @ " + v + ", internal is " + wtoken.token + " @ " + m);
1919 }
1920 v--;
1921 m--;
1922 }
1923 while (v >= 0) {
1924 Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
1925 v--;
1926 }
1927 while (m >= 0) {
1928 AppWindowToken wtoken = mAppTokens.get(m);
1929 if (!wtoken.removed) {
1930 Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
1931 }
1932 m--;
1933 }
1934 }
1935
1936 boolean checkCallingPermission(String permission, String func) {
1937 // Quick check: if the calling permission is me, it's all okay.
1938 if (Binder.getCallingPid() == Process.myPid()) {
1939 return true;
1940 }
Romain Guy06882f82009-06-10 13:36:04 -07001941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 if (mContext.checkCallingPermission(permission)
1943 == PackageManager.PERMISSION_GRANTED) {
1944 return true;
1945 }
1946 String msg = "Permission Denial: " + func + " from pid="
1947 + Binder.getCallingPid()
1948 + ", uid=" + Binder.getCallingUid()
1949 + " requires " + permission;
1950 Log.w(TAG, msg);
1951 return false;
1952 }
Romain Guy06882f82009-06-10 13:36:04 -07001953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 AppWindowToken findAppWindowToken(IBinder token) {
1955 WindowToken wtoken = mTokenMap.get(token);
1956 if (wtoken == null) {
1957 return null;
1958 }
1959 return wtoken.appWindowToken;
1960 }
Romain Guy06882f82009-06-10 13:36:04 -07001961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 public void addWindowToken(IBinder token, int type) {
1963 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1964 "addWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001965 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 }
Romain Guy06882f82009-06-10 13:36:04 -07001967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 synchronized(mWindowMap) {
1969 WindowToken wtoken = mTokenMap.get(token);
1970 if (wtoken != null) {
1971 Log.w(TAG, "Attempted to add existing input method token: " + token);
1972 return;
1973 }
1974 wtoken = new WindowToken(token, type, true);
1975 mTokenMap.put(token, wtoken);
1976 mTokenList.add(wtoken);
1977 }
1978 }
Romain Guy06882f82009-06-10 13:36:04 -07001979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 public void removeWindowToken(IBinder token) {
1981 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
1982 "removeWindowToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07001983 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 }
1985
1986 final long origId = Binder.clearCallingIdentity();
1987 synchronized(mWindowMap) {
1988 WindowToken wtoken = mTokenMap.remove(token);
1989 mTokenList.remove(wtoken);
1990 if (wtoken != null) {
1991 boolean delayed = false;
1992 if (!wtoken.hidden) {
1993 wtoken.hidden = true;
Romain Guy06882f82009-06-10 13:36:04 -07001994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 final int N = wtoken.windows.size();
1996 boolean changed = false;
Romain Guy06882f82009-06-10 13:36:04 -07001997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 for (int i=0; i<N; i++) {
1999 WindowState win = wtoken.windows.get(i);
2000
2001 if (win.isAnimating()) {
2002 delayed = true;
2003 }
Romain Guy06882f82009-06-10 13:36:04 -07002004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 if (win.isVisibleNow()) {
2006 applyAnimationLocked(win,
2007 WindowManagerPolicy.TRANSIT_EXIT, false);
2008 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2009 KeyWaiter.RETURN_NOTHING);
2010 changed = true;
2011 }
2012 }
2013
2014 if (changed) {
2015 mLayoutNeeded = true;
2016 performLayoutAndPlaceSurfacesLocked();
2017 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2018 }
Romain Guy06882f82009-06-10 13:36:04 -07002019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 if (delayed) {
2021 mExitingTokens.add(wtoken);
2022 }
2023 }
Romain Guy06882f82009-06-10 13:36:04 -07002024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 } else {
2026 Log.w(TAG, "Attempted to remove non-existing token: " + token);
2027 }
2028 }
2029 Binder.restoreCallingIdentity(origId);
2030 }
2031
2032 public void addAppToken(int addPos, IApplicationToken token,
2033 int groupId, int requestedOrientation, boolean fullscreen) {
2034 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2035 "addAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002036 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 }
Romain Guy06882f82009-06-10 13:36:04 -07002038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 synchronized(mWindowMap) {
2040 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2041 if (wtoken != null) {
2042 Log.w(TAG, "Attempted to add existing app token: " + token);
2043 return;
2044 }
2045 wtoken = new AppWindowToken(token);
2046 wtoken.groupId = groupId;
2047 wtoken.appFullscreen = fullscreen;
2048 wtoken.requestedOrientation = requestedOrientation;
2049 mAppTokens.add(addPos, wtoken);
Dave Bortcfe65242009-04-09 14:51:04 -07002050 if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 mTokenMap.put(token.asBinder(), wtoken);
2052 mTokenList.add(wtoken);
Romain Guy06882f82009-06-10 13:36:04 -07002053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 // Application tokens start out hidden.
2055 wtoken.hidden = true;
2056 wtoken.hiddenRequested = true;
Romain Guy06882f82009-06-10 13:36:04 -07002057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 //dump();
2059 }
2060 }
Romain Guy06882f82009-06-10 13:36:04 -07002061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062 public void setAppGroupId(IBinder token, int groupId) {
2063 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2064 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002065 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067
2068 synchronized(mWindowMap) {
2069 AppWindowToken wtoken = findAppWindowToken(token);
2070 if (wtoken == null) {
2071 Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
2072 return;
2073 }
2074 wtoken.groupId = groupId;
2075 }
2076 }
Romain Guy06882f82009-06-10 13:36:04 -07002077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 public int getOrientationFromWindowsLocked() {
2079 int pos = mWindows.size() - 1;
2080 while (pos >= 0) {
2081 WindowState wtoken = (WindowState) mWindows.get(pos);
2082 pos--;
2083 if (wtoken.mAppToken != null) {
2084 // We hit an application window. so the orientation will be determined by the
2085 // app window. No point in continuing further.
2086 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2087 }
2088 if (!wtoken.isVisibleLw()) {
2089 continue;
2090 }
2091 int req = wtoken.mAttrs.screenOrientation;
2092 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
2093 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
2094 continue;
2095 } else {
2096 return req;
2097 }
2098 }
2099 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2100 }
Romain Guy06882f82009-06-10 13:36:04 -07002101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 public int getOrientationFromAppTokensLocked() {
2103 int pos = mAppTokens.size() - 1;
2104 int curGroup = 0;
2105 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Owen Lin3413b892009-05-01 17:12:32 -07002106 boolean findingBehind = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 boolean haveGroup = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002108 boolean lastFullscreen = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 while (pos >= 0) {
2110 AppWindowToken wtoken = mAppTokens.get(pos);
2111 pos--;
Owen Lin3413b892009-05-01 17:12:32 -07002112 // if we're about to tear down this window and not seek for
2113 // the behind activity, don't use it for orientation
2114 if (!findingBehind
2115 && (!wtoken.hidden && wtoken.hiddenRequested)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002116 continue;
2117 }
2118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 if (!haveGroup) {
2120 // We ignore any hidden applications on the top.
2121 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
2122 continue;
2123 }
2124 haveGroup = true;
2125 curGroup = wtoken.groupId;
2126 lastOrientation = wtoken.requestedOrientation;
2127 } else if (curGroup != wtoken.groupId) {
2128 // If we have hit a new application group, and the bottom
2129 // of the previous group didn't explicitly say to use
The Android Open Source Project4df24232009-03-05 14:34:35 -08002130 // the orientation behind it, and the last app was
2131 // full screen, then we'll stick with the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 // user's orientation.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002133 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
2134 && lastFullscreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 return lastOrientation;
2136 }
2137 }
2138 int or = wtoken.requestedOrientation;
Owen Lin3413b892009-05-01 17:12:32 -07002139 // If this application is fullscreen, and didn't explicitly say
2140 // to use the orientation behind it, then just take whatever
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 // orientation it has and ignores whatever is under it.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002142 lastFullscreen = wtoken.appFullscreen;
Romain Guy06882f82009-06-10 13:36:04 -07002143 if (lastFullscreen
Owen Lin3413b892009-05-01 17:12:32 -07002144 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 return or;
2146 }
2147 // If this application has requested an explicit orientation,
2148 // then use it.
2149 if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
2150 or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
2151 or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
2152 or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
2153 or == ActivityInfo.SCREEN_ORIENTATION_USER) {
2154 return or;
2155 }
Owen Lin3413b892009-05-01 17:12:32 -07002156 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 }
2158 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2159 }
Romain Guy06882f82009-06-10 13:36:04 -07002160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 public Configuration updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002162 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002163 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2164 "updateOrientationFromAppTokens()")) {
2165 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
2166 }
2167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168 Configuration config;
2169 long ident = Binder.clearCallingIdentity();
Dianne Hackborncfaef692009-06-15 14:24:44 -07002170 config = updateOrientationFromAppTokensUnchecked(currentConfig,
2171 freezeThisOneIfNeeded);
2172 Binder.restoreCallingIdentity(ident);
2173 return config;
2174 }
2175
2176 Configuration updateOrientationFromAppTokensUnchecked(
2177 Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
2178 Configuration config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 synchronized(mWindowMap) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002180 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 }
2182 if (config != null) {
2183 mLayoutNeeded = true;
2184 performLayoutAndPlaceSurfacesLocked();
2185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 return config;
2187 }
Romain Guy06882f82009-06-10 13:36:04 -07002188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 /*
2190 * The orientation is computed from non-application windows first. If none of
2191 * the non-application windows specify orientation, the orientation is computed from
Romain Guy06882f82009-06-10 13:36:04 -07002192 * application tokens.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 * @see android.view.IWindowManager#updateOrientationFromAppTokens(
2194 * android.os.IBinder)
2195 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002196 Configuration updateOrientationFromAppTokensLocked(
The Android Open Source Project10592532009-03-18 17:39:46 -07002197 Configuration appConfig, IBinder freezeThisOneIfNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 boolean changed = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 long ident = Binder.clearCallingIdentity();
2200 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002201 int req = computeForcedAppOrientationLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 if (req != mForcedAppOrientation) {
2204 changed = true;
2205 mForcedAppOrientation = req;
2206 //send a message to Policy indicating orientation change to take
2207 //action like disabling/enabling sensors etc.,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002208 mPolicy.setCurrentOrientationLw(req);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 }
Romain Guy06882f82009-06-10 13:36:04 -07002210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 if (changed) {
2212 changed = setRotationUncheckedLocked(
Dianne Hackborn321ae682009-03-27 16:16:03 -07002213 WindowManagerPolicy.USE_LAST_ROTATION,
2214 mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 if (changed) {
2216 if (freezeThisOneIfNeeded != null) {
2217 AppWindowToken wtoken = findAppWindowToken(
2218 freezeThisOneIfNeeded);
2219 if (wtoken != null) {
2220 startAppFreezingScreenLocked(wtoken,
2221 ActivityInfo.CONFIG_ORIENTATION);
2222 }
2223 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07002224 return computeNewConfigurationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 }
2226 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002227
2228 // No obvious action we need to take, but if our current
2229 // state mismatches the activity maanager's, update it
2230 if (appConfig != null) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07002231 mTempConfiguration.setToDefaults();
2232 if (computeNewConfigurationLocked(mTempConfiguration)) {
2233 if (appConfig.diff(mTempConfiguration) != 0) {
2234 Log.i(TAG, "Config changed: " + mTempConfiguration);
2235 return new Configuration(mTempConfiguration);
2236 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002237 }
2238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 } finally {
2240 Binder.restoreCallingIdentity(ident);
2241 }
Romain Guy06882f82009-06-10 13:36:04 -07002242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243 return null;
2244 }
Romain Guy06882f82009-06-10 13:36:04 -07002245
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002246 int computeForcedAppOrientationLocked() {
2247 int req = getOrientationFromWindowsLocked();
2248 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
2249 req = getOrientationFromAppTokensLocked();
2250 }
2251 return req;
2252 }
Romain Guy06882f82009-06-10 13:36:04 -07002253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
2255 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2256 "setAppOrientation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002257 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 }
Romain Guy06882f82009-06-10 13:36:04 -07002259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002260 synchronized(mWindowMap) {
2261 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2262 if (wtoken == null) {
2263 Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
2264 return;
2265 }
Romain Guy06882f82009-06-10 13:36:04 -07002266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 wtoken.requestedOrientation = requestedOrientation;
2268 }
2269 }
Romain Guy06882f82009-06-10 13:36:04 -07002270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 public int getAppOrientation(IApplicationToken token) {
2272 synchronized(mWindowMap) {
2273 AppWindowToken wtoken = findAppWindowToken(token.asBinder());
2274 if (wtoken == null) {
2275 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
2276 }
Romain Guy06882f82009-06-10 13:36:04 -07002277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 return wtoken.requestedOrientation;
2279 }
2280 }
Romain Guy06882f82009-06-10 13:36:04 -07002281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002282 public void setFocusedApp(IBinder token, boolean moveFocusNow) {
2283 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2284 "setFocusedApp()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002285 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002286 }
2287
2288 synchronized(mWindowMap) {
2289 boolean changed = false;
2290 if (token == null) {
2291 if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
2292 changed = mFocusedApp != null;
2293 mFocusedApp = null;
2294 mKeyWaiter.tickle();
2295 } else {
2296 AppWindowToken newFocus = findAppWindowToken(token);
2297 if (newFocus == null) {
2298 Log.w(TAG, "Attempted to set focus to non-existing app token: " + token);
2299 return;
2300 }
2301 changed = mFocusedApp != newFocus;
2302 mFocusedApp = newFocus;
2303 if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp);
2304 mKeyWaiter.tickle();
2305 }
2306
2307 if (moveFocusNow && changed) {
2308 final long origId = Binder.clearCallingIdentity();
2309 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2310 Binder.restoreCallingIdentity(origId);
2311 }
2312 }
2313 }
2314
2315 public void prepareAppTransition(int transit) {
2316 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2317 "prepareAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002318 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002319 }
Romain Guy06882f82009-06-10 13:36:04 -07002320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 synchronized(mWindowMap) {
2322 if (DEBUG_APP_TRANSITIONS) Log.v(
2323 TAG, "Prepare app transition: transit=" + transit
2324 + " mNextAppTransition=" + mNextAppTransition);
2325 if (!mDisplayFrozen) {
2326 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
2327 mNextAppTransition = transit;
2328 }
2329 mAppTransitionReady = false;
2330 mAppTransitionTimeout = false;
2331 mStartingIconInTransition = false;
2332 mSkipAppTransitionAnimation = false;
2333 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2334 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
2335 5000);
2336 }
2337 }
2338 }
2339
2340 public int getPendingAppTransition() {
2341 return mNextAppTransition;
2342 }
Romain Guy06882f82009-06-10 13:36:04 -07002343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 public void executeAppTransition() {
2345 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2346 "executeAppTransition()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002347 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002348 }
Romain Guy06882f82009-06-10 13:36:04 -07002349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 synchronized(mWindowMap) {
2351 if (DEBUG_APP_TRANSITIONS) Log.v(
2352 TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
2353 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2354 mAppTransitionReady = true;
2355 final long origId = Binder.clearCallingIdentity();
2356 performLayoutAndPlaceSurfacesLocked();
2357 Binder.restoreCallingIdentity(origId);
2358 }
2359 }
2360 }
2361
2362 public void setAppStartingWindow(IBinder token, String pkg,
2363 int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
2364 IBinder transferFrom, boolean createIfNeeded) {
2365 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2366 "setAppStartingIcon()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002367 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002368 }
2369
2370 synchronized(mWindowMap) {
2371 if (DEBUG_STARTING_WINDOW) Log.v(
2372 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
2373 + " transferFrom=" + transferFrom);
Romain Guy06882f82009-06-10 13:36:04 -07002374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002375 AppWindowToken wtoken = findAppWindowToken(token);
2376 if (wtoken == null) {
2377 Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
2378 return;
2379 }
2380
2381 // If the display is frozen, we won't do anything until the
2382 // actual window is displayed so there is no reason to put in
2383 // the starting window.
2384 if (mDisplayFrozen) {
2385 return;
2386 }
Romain Guy06882f82009-06-10 13:36:04 -07002387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002388 if (wtoken.startingData != null) {
2389 return;
2390 }
Romain Guy06882f82009-06-10 13:36:04 -07002391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 if (transferFrom != null) {
2393 AppWindowToken ttoken = findAppWindowToken(transferFrom);
2394 if (ttoken != null) {
2395 WindowState startingWindow = ttoken.startingWindow;
2396 if (startingWindow != null) {
2397 if (mStartingIconInTransition) {
2398 // In this case, the starting icon has already
2399 // been displayed, so start letting windows get
2400 // shown immediately without any more transitions.
2401 mSkipAppTransitionAnimation = true;
2402 }
2403 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2404 "Moving existing starting from " + ttoken
2405 + " to " + wtoken);
2406 final long origId = Binder.clearCallingIdentity();
Romain Guy06882f82009-06-10 13:36:04 -07002407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 // Transfer the starting window over to the new
2409 // token.
2410 wtoken.startingData = ttoken.startingData;
2411 wtoken.startingView = ttoken.startingView;
2412 wtoken.startingWindow = startingWindow;
2413 ttoken.startingData = null;
2414 ttoken.startingView = null;
2415 ttoken.startingWindow = null;
2416 ttoken.startingMoved = true;
2417 startingWindow.mToken = wtoken;
Dianne Hackbornef49c572009-03-24 19:27:32 -07002418 startingWindow.mRootToken = wtoken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002419 startingWindow.mAppToken = wtoken;
2420 mWindows.remove(startingWindow);
2421 ttoken.windows.remove(startingWindow);
2422 ttoken.allAppWindows.remove(startingWindow);
2423 addWindowToListInOrderLocked(startingWindow, true);
2424 wtoken.allAppWindows.add(startingWindow);
Romain Guy06882f82009-06-10 13:36:04 -07002425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002426 // Propagate other interesting state between the
2427 // tokens. If the old token is displayed, we should
2428 // immediately force the new one to be displayed. If
2429 // it is animating, we need to move that animation to
2430 // the new one.
2431 if (ttoken.allDrawn) {
2432 wtoken.allDrawn = true;
2433 }
2434 if (ttoken.firstWindowDrawn) {
2435 wtoken.firstWindowDrawn = true;
2436 }
2437 if (!ttoken.hidden) {
2438 wtoken.hidden = false;
2439 wtoken.hiddenRequested = false;
2440 wtoken.willBeHidden = false;
2441 }
2442 if (wtoken.clientHidden != ttoken.clientHidden) {
2443 wtoken.clientHidden = ttoken.clientHidden;
2444 wtoken.sendAppVisibilityToClients();
2445 }
2446 if (ttoken.animation != null) {
2447 wtoken.animation = ttoken.animation;
2448 wtoken.animating = ttoken.animating;
2449 wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
2450 ttoken.animation = null;
2451 ttoken.animLayerAdjustment = 0;
2452 wtoken.updateLayers();
2453 ttoken.updateLayers();
2454 }
Romain Guy06882f82009-06-10 13:36:04 -07002455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002456 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 mLayoutNeeded = true;
2458 performLayoutAndPlaceSurfacesLocked();
2459 Binder.restoreCallingIdentity(origId);
2460 return;
2461 } else if (ttoken.startingData != null) {
2462 // The previous app was getting ready to show a
2463 // starting window, but hasn't yet done so. Steal it!
2464 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
2465 "Moving pending starting from " + ttoken
2466 + " to " + wtoken);
2467 wtoken.startingData = ttoken.startingData;
2468 ttoken.startingData = null;
2469 ttoken.startingMoved = true;
2470 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2471 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2472 // want to process the message ASAP, before any other queued
2473 // messages.
2474 mH.sendMessageAtFrontOfQueue(m);
2475 return;
2476 }
2477 }
2478 }
2479
2480 // There is no existing starting window, and the caller doesn't
2481 // want us to create one, so that's it!
2482 if (!createIfNeeded) {
2483 return;
2484 }
Romain Guy06882f82009-06-10 13:36:04 -07002485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486 mStartingIconInTransition = true;
2487 wtoken.startingData = new StartingData(
2488 pkg, theme, nonLocalizedLabel,
2489 labelRes, icon);
2490 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
2491 // Note: we really want to do sendMessageAtFrontOfQueue() because we
2492 // want to process the message ASAP, before any other queued
2493 // messages.
2494 mH.sendMessageAtFrontOfQueue(m);
2495 }
2496 }
2497
2498 public void setAppWillBeHidden(IBinder token) {
2499 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2500 "setAppWillBeHidden()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002501 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002502 }
2503
2504 AppWindowToken wtoken;
2505
2506 synchronized(mWindowMap) {
2507 wtoken = findAppWindowToken(token);
2508 if (wtoken == null) {
2509 Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
2510 return;
2511 }
2512 wtoken.willBeHidden = true;
2513 }
2514 }
Romain Guy06882f82009-06-10 13:36:04 -07002515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
2517 boolean visible, int transit, boolean performLayout) {
2518 boolean delayed = false;
2519
2520 if (wtoken.clientHidden == visible) {
2521 wtoken.clientHidden = !visible;
2522 wtoken.sendAppVisibilityToClients();
2523 }
Romain Guy06882f82009-06-10 13:36:04 -07002524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 wtoken.willBeHidden = false;
2526 if (wtoken.hidden == visible) {
2527 final int N = wtoken.allAppWindows.size();
2528 boolean changed = false;
2529 if (DEBUG_APP_TRANSITIONS) Log.v(
2530 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
2531 + " performLayout=" + performLayout);
Romain Guy06882f82009-06-10 13:36:04 -07002532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 boolean runningAppAnimation = false;
Romain Guy06882f82009-06-10 13:36:04 -07002534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 if (transit != WindowManagerPolicy.TRANSIT_NONE) {
2536 if (wtoken.animation == sDummyAnimation) {
2537 wtoken.animation = null;
2538 }
2539 applyAnimationLocked(wtoken, lp, transit, visible);
2540 changed = true;
2541 if (wtoken.animation != null) {
2542 delayed = runningAppAnimation = true;
2543 }
2544 }
Romain Guy06882f82009-06-10 13:36:04 -07002545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 for (int i=0; i<N; i++) {
2547 WindowState win = wtoken.allAppWindows.get(i);
2548 if (win == wtoken.startingWindow) {
2549 continue;
2550 }
2551
2552 if (win.isAnimating()) {
2553 delayed = true;
2554 }
Romain Guy06882f82009-06-10 13:36:04 -07002555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
2557 //win.dump(" ");
2558 if (visible) {
2559 if (!win.isVisibleNow()) {
2560 if (!runningAppAnimation) {
2561 applyAnimationLocked(win,
2562 WindowManagerPolicy.TRANSIT_ENTER, true);
2563 }
2564 changed = true;
2565 }
2566 } else if (win.isVisibleNow()) {
2567 if (!runningAppAnimation) {
2568 applyAnimationLocked(win,
2569 WindowManagerPolicy.TRANSIT_EXIT, false);
2570 }
2571 mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
2572 KeyWaiter.RETURN_NOTHING);
2573 changed = true;
2574 }
2575 }
2576
2577 wtoken.hidden = wtoken.hiddenRequested = !visible;
2578 if (!visible) {
2579 unsetAppFreezingScreenLocked(wtoken, true, true);
2580 } else {
2581 // If we are being set visible, and the starting window is
2582 // not yet displayed, then make sure it doesn't get displayed.
2583 WindowState swin = wtoken.startingWindow;
2584 if (swin != null && (swin.mDrawPending
2585 || swin.mCommitDrawPending)) {
2586 swin.mPolicyVisibility = false;
2587 swin.mPolicyVisibilityAfterAnim = false;
2588 }
2589 }
Romain Guy06882f82009-06-10 13:36:04 -07002590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
2592 + ": hidden=" + wtoken.hidden + " hiddenRequested="
2593 + wtoken.hiddenRequested);
Romain Guy06882f82009-06-10 13:36:04 -07002594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 if (changed && performLayout) {
2596 mLayoutNeeded = true;
2597 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002598 performLayoutAndPlaceSurfacesLocked();
2599 }
2600 }
2601
2602 if (wtoken.animation != null) {
2603 delayed = true;
2604 }
Romain Guy06882f82009-06-10 13:36:04 -07002605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002606 return delayed;
2607 }
2608
2609 public void setAppVisibility(IBinder token, boolean visible) {
2610 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2611 "setAppVisibility()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002612 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 }
2614
2615 AppWindowToken wtoken;
2616
2617 synchronized(mWindowMap) {
2618 wtoken = findAppWindowToken(token);
2619 if (wtoken == null) {
2620 Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
2621 return;
2622 }
2623
2624 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
2625 RuntimeException e = new RuntimeException();
2626 e.fillInStackTrace();
2627 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
2628 + "): mNextAppTransition=" + mNextAppTransition
2629 + " hidden=" + wtoken.hidden
2630 + " hiddenRequested=" + wtoken.hiddenRequested, e);
2631 }
Romain Guy06882f82009-06-10 13:36:04 -07002632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 // If we are preparing an app transition, then delay changing
2634 // the visibility of this token until we execute that transition.
2635 if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2636 // Already in requested state, don't do anything more.
2637 if (wtoken.hiddenRequested != visible) {
2638 return;
2639 }
2640 wtoken.hiddenRequested = !visible;
Romain Guy06882f82009-06-10 13:36:04 -07002641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002642 if (DEBUG_APP_TRANSITIONS) Log.v(
2643 TAG, "Setting dummy animation on: " + wtoken);
2644 wtoken.setDummyAnimation();
2645 mOpeningApps.remove(wtoken);
2646 mClosingApps.remove(wtoken);
2647 wtoken.inPendingTransaction = true;
2648 if (visible) {
2649 mOpeningApps.add(wtoken);
2650 wtoken.allDrawn = false;
2651 wtoken.startingDisplayed = false;
2652 wtoken.startingMoved = false;
Romain Guy06882f82009-06-10 13:36:04 -07002653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 if (wtoken.clientHidden) {
2655 // In the case where we are making an app visible
2656 // but holding off for a transition, we still need
2657 // to tell the client to make its windows visible so
2658 // they get drawn. Otherwise, we will wait on
2659 // performing the transition until all windows have
2660 // been drawn, they never will be, and we are sad.
2661 wtoken.clientHidden = false;
2662 wtoken.sendAppVisibilityToClients();
2663 }
2664 } else {
2665 mClosingApps.add(wtoken);
2666 }
2667 return;
2668 }
Romain Guy06882f82009-06-10 13:36:04 -07002669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 final long origId = Binder.clearCallingIdentity();
2671 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
2672 wtoken.updateReportedVisibilityLocked();
2673 Binder.restoreCallingIdentity(origId);
2674 }
2675 }
2676
2677 void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
2678 boolean unfreezeSurfaceNow, boolean force) {
2679 if (wtoken.freezingScreen) {
2680 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
2681 + " force=" + force);
2682 final int N = wtoken.allAppWindows.size();
2683 boolean unfrozeWindows = false;
2684 for (int i=0; i<N; i++) {
2685 WindowState w = wtoken.allAppWindows.get(i);
2686 if (w.mAppFreezing) {
2687 w.mAppFreezing = false;
2688 if (w.mSurface != null && !w.mOrientationChanging) {
2689 w.mOrientationChanging = true;
2690 }
2691 unfrozeWindows = true;
2692 }
2693 }
2694 if (force || unfrozeWindows) {
2695 if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
2696 wtoken.freezingScreen = false;
2697 mAppsFreezingScreen--;
2698 }
2699 if (unfreezeSurfaceNow) {
2700 if (unfrozeWindows) {
2701 mLayoutNeeded = true;
2702 performLayoutAndPlaceSurfacesLocked();
2703 }
2704 if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
2705 stopFreezingDisplayLocked();
2706 }
2707 }
2708 }
2709 }
Romain Guy06882f82009-06-10 13:36:04 -07002710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 public void startAppFreezingScreenLocked(AppWindowToken wtoken,
2712 int configChanges) {
2713 if (DEBUG_ORIENTATION) {
2714 RuntimeException e = new RuntimeException();
2715 e.fillInStackTrace();
2716 Log.i(TAG, "Set freezing of " + wtoken.appToken
2717 + ": hidden=" + wtoken.hidden + " freezing="
2718 + wtoken.freezingScreen, e);
2719 }
2720 if (!wtoken.hiddenRequested) {
2721 if (!wtoken.freezingScreen) {
2722 wtoken.freezingScreen = true;
2723 mAppsFreezingScreen++;
2724 if (mAppsFreezingScreen == 1) {
2725 startFreezingDisplayLocked();
2726 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
2727 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
2728 5000);
2729 }
2730 }
2731 final int N = wtoken.allAppWindows.size();
2732 for (int i=0; i<N; i++) {
2733 WindowState w = wtoken.allAppWindows.get(i);
2734 w.mAppFreezing = true;
2735 }
2736 }
2737 }
Romain Guy06882f82009-06-10 13:36:04 -07002738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 public void startAppFreezingScreen(IBinder token, int configChanges) {
2740 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2741 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002742 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002743 }
2744
2745 synchronized(mWindowMap) {
2746 if (configChanges == 0 && !mDisplayFrozen) {
2747 if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
2748 return;
2749 }
Romain Guy06882f82009-06-10 13:36:04 -07002750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002751 AppWindowToken wtoken = findAppWindowToken(token);
2752 if (wtoken == null || wtoken.appToken == null) {
2753 Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
2754 return;
2755 }
2756 final long origId = Binder.clearCallingIdentity();
2757 startAppFreezingScreenLocked(wtoken, configChanges);
2758 Binder.restoreCallingIdentity(origId);
2759 }
2760 }
Romain Guy06882f82009-06-10 13:36:04 -07002761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002762 public void stopAppFreezingScreen(IBinder token, boolean force) {
2763 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2764 "setAppFreezingScreen()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002765 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 }
2767
2768 synchronized(mWindowMap) {
2769 AppWindowToken wtoken = findAppWindowToken(token);
2770 if (wtoken == null || wtoken.appToken == null) {
2771 return;
2772 }
2773 final long origId = Binder.clearCallingIdentity();
2774 if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
2775 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
2776 unsetAppFreezingScreenLocked(wtoken, true, force);
2777 Binder.restoreCallingIdentity(origId);
2778 }
2779 }
Romain Guy06882f82009-06-10 13:36:04 -07002780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 public void removeAppToken(IBinder token) {
2782 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2783 "removeAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002784 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002785 }
2786
2787 AppWindowToken wtoken = null;
2788 AppWindowToken startingToken = null;
2789 boolean delayed = false;
2790
2791 final long origId = Binder.clearCallingIdentity();
2792 synchronized(mWindowMap) {
2793 WindowToken basewtoken = mTokenMap.remove(token);
2794 mTokenList.remove(basewtoken);
2795 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
2796 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
2797 delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
2798 wtoken.inPendingTransaction = false;
2799 mOpeningApps.remove(wtoken);
2800 if (mClosingApps.contains(wtoken)) {
2801 delayed = true;
2802 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
2803 mClosingApps.add(wtoken);
2804 delayed = true;
2805 }
2806 if (DEBUG_APP_TRANSITIONS) Log.v(
2807 TAG, "Removing app " + wtoken + " delayed=" + delayed
2808 + " animation=" + wtoken.animation
2809 + " animating=" + wtoken.animating);
2810 if (delayed) {
2811 // set the token aside because it has an active animation to be finished
2812 mExitingAppTokens.add(wtoken);
2813 }
2814 mAppTokens.remove(wtoken);
2815 wtoken.removed = true;
2816 if (wtoken.startingData != null) {
2817 startingToken = wtoken;
2818 }
2819 unsetAppFreezingScreenLocked(wtoken, true, true);
2820 if (mFocusedApp == wtoken) {
2821 if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
2822 mFocusedApp = null;
2823 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
2824 mKeyWaiter.tickle();
2825 }
2826 } else {
2827 Log.w(TAG, "Attempted to remove non-existing app token: " + token);
2828 }
Romain Guy06882f82009-06-10 13:36:04 -07002829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002830 if (!delayed && wtoken != null) {
2831 wtoken.updateReportedVisibilityLocked();
2832 }
2833 }
2834 Binder.restoreCallingIdentity(origId);
2835
2836 if (startingToken != null) {
2837 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
2838 + startingToken + ": app token removed");
2839 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
2840 mH.sendMessage(m);
2841 }
2842 }
2843
2844 private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
2845 final int NW = token.windows.size();
2846 for (int i=0; i<NW; i++) {
2847 WindowState win = token.windows.get(i);
2848 mWindows.remove(win);
2849 int j = win.mChildWindows.size();
2850 while (j > 0) {
2851 j--;
2852 mWindows.remove(win.mChildWindows.get(j));
2853 }
2854 }
2855 return NW > 0;
2856 }
2857
2858 void dumpAppTokensLocked() {
2859 for (int i=mAppTokens.size()-1; i>=0; i--) {
2860 Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
2861 }
2862 }
Romain Guy06882f82009-06-10 13:36:04 -07002863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 void dumpWindowsLocked() {
2865 for (int i=mWindows.size()-1; i>=0; i--) {
2866 Log.v(TAG, " #" + i + ": " + mWindows.get(i));
2867 }
2868 }
Romain Guy06882f82009-06-10 13:36:04 -07002869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002870 private int findWindowOffsetLocked(int tokenPos) {
2871 final int NW = mWindows.size();
2872
2873 if (tokenPos >= mAppTokens.size()) {
2874 int i = NW;
2875 while (i > 0) {
2876 i--;
2877 WindowState win = (WindowState)mWindows.get(i);
2878 if (win.getAppToken() != null) {
2879 return i+1;
2880 }
2881 }
2882 }
2883
2884 while (tokenPos > 0) {
2885 // Find the first app token below the new position that has
2886 // a window displayed.
2887 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
2888 if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
2889 + tokenPos + " -- " + wtoken.token);
2890 int i = wtoken.windows.size();
2891 while (i > 0) {
2892 i--;
2893 WindowState win = wtoken.windows.get(i);
2894 int j = win.mChildWindows.size();
2895 while (j > 0) {
2896 j--;
2897 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2898 if (cwin.mSubLayer >= 0 ) {
2899 for (int pos=NW-1; pos>=0; pos--) {
2900 if (mWindows.get(pos) == cwin) {
2901 if (DEBUG_REORDER) Log.v(TAG,
2902 "Found child win @" + (pos+1));
2903 return pos+1;
2904 }
2905 }
2906 }
2907 }
2908 for (int pos=NW-1; pos>=0; pos--) {
2909 if (mWindows.get(pos) == win) {
2910 if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
2911 return pos+1;
2912 }
2913 }
2914 }
2915 tokenPos--;
2916 }
2917
2918 return 0;
2919 }
2920
2921 private final int reAddWindowLocked(int index, WindowState win) {
2922 final int NCW = win.mChildWindows.size();
2923 boolean added = false;
2924 for (int j=0; j<NCW; j++) {
2925 WindowState cwin = (WindowState)win.mChildWindows.get(j);
2926 if (!added && cwin.mSubLayer >= 0) {
2927 mWindows.add(index, win);
2928 index++;
2929 added = true;
2930 }
2931 mWindows.add(index, cwin);
2932 index++;
2933 }
2934 if (!added) {
2935 mWindows.add(index, win);
2936 index++;
2937 }
2938 return index;
2939 }
Romain Guy06882f82009-06-10 13:36:04 -07002940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002941 private final int reAddAppWindowsLocked(int index, WindowToken token) {
2942 final int NW = token.windows.size();
2943 for (int i=0; i<NW; i++) {
2944 index = reAddWindowLocked(index, token.windows.get(i));
2945 }
2946 return index;
2947 }
2948
2949 public void moveAppToken(int index, IBinder token) {
2950 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
2951 "moveAppToken()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07002952 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 }
2954
2955 synchronized(mWindowMap) {
2956 if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
2957 if (DEBUG_REORDER) dumpAppTokensLocked();
2958 final AppWindowToken wtoken = findAppWindowToken(token);
2959 if (wtoken == null || !mAppTokens.remove(wtoken)) {
2960 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
2961 + token + " (" + wtoken + ")");
2962 return;
2963 }
2964 mAppTokens.add(index, wtoken);
2965 if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
2966 if (DEBUG_REORDER) dumpAppTokensLocked();
Romain Guy06882f82009-06-10 13:36:04 -07002967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 final long origId = Binder.clearCallingIdentity();
2969 if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
2970 if (DEBUG_REORDER) dumpWindowsLocked();
2971 if (tmpRemoveAppWindowsLocked(wtoken)) {
2972 if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:");
2973 if (DEBUG_REORDER) dumpWindowsLocked();
2974 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
2975 if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
2976 if (DEBUG_REORDER) dumpWindowsLocked();
2977 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 mLayoutNeeded = true;
2979 performLayoutAndPlaceSurfacesLocked();
2980 }
2981 Binder.restoreCallingIdentity(origId);
2982 }
2983 }
2984
2985 private void removeAppTokensLocked(List<IBinder> tokens) {
2986 // XXX This should be done more efficiently!
2987 // (take advantage of the fact that both lists should be
2988 // ordered in the same way.)
2989 int N = tokens.size();
2990 for (int i=0; i<N; i++) {
2991 IBinder token = tokens.get(i);
2992 final AppWindowToken wtoken = findAppWindowToken(token);
2993 if (!mAppTokens.remove(wtoken)) {
2994 Log.w(TAG, "Attempting to reorder token that doesn't exist: "
2995 + token + " (" + wtoken + ")");
2996 i--;
2997 N--;
2998 }
2999 }
3000 }
3001
3002 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
3003 // First remove all of the windows from the list.
3004 final int N = tokens.size();
3005 int i;
3006 for (i=0; i<N; i++) {
3007 WindowToken token = mTokenMap.get(tokens.get(i));
3008 if (token != null) {
3009 tmpRemoveAppWindowsLocked(token);
3010 }
3011 }
3012
3013 // Where to start adding?
3014 int pos = findWindowOffsetLocked(tokenPos);
3015
3016 // And now add them back at the correct place.
3017 for (i=0; i<N; i++) {
3018 WindowToken token = mTokenMap.get(tokens.get(i));
3019 if (token != null) {
3020 pos = reAddAppWindowsLocked(pos, token);
3021 }
3022 }
3023
3024 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003025 mLayoutNeeded = true;
3026 performLayoutAndPlaceSurfacesLocked();
3027
3028 //dump();
3029 }
3030
3031 public void moveAppTokensToTop(List<IBinder> tokens) {
3032 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3033 "moveAppTokensToTop()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003034 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035 }
3036
3037 final long origId = Binder.clearCallingIdentity();
3038 synchronized(mWindowMap) {
3039 removeAppTokensLocked(tokens);
3040 final int N = tokens.size();
3041 for (int i=0; i<N; i++) {
3042 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3043 if (wt != null) {
3044 mAppTokens.add(wt);
3045 }
3046 }
3047 moveAppWindowsLocked(tokens, mAppTokens.size());
3048 }
3049 Binder.restoreCallingIdentity(origId);
3050 }
3051
3052 public void moveAppTokensToBottom(List<IBinder> tokens) {
3053 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3054 "moveAppTokensToBottom()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003055 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003056 }
3057
3058 final long origId = Binder.clearCallingIdentity();
3059 synchronized(mWindowMap) {
3060 removeAppTokensLocked(tokens);
3061 final int N = tokens.size();
3062 int pos = 0;
3063 for (int i=0; i<N; i++) {
3064 AppWindowToken wt = findAppWindowToken(tokens.get(i));
3065 if (wt != null) {
3066 mAppTokens.add(pos, wt);
3067 pos++;
3068 }
3069 }
3070 moveAppWindowsLocked(tokens, 0);
3071 }
3072 Binder.restoreCallingIdentity(origId);
3073 }
3074
3075 // -------------------------------------------------------------
3076 // Misc IWindowSession methods
3077 // -------------------------------------------------------------
Romain Guy06882f82009-06-10 13:36:04 -07003078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 public void disableKeyguard(IBinder token, String tag) {
3080 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3081 != PackageManager.PERMISSION_GRANTED) {
3082 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3083 }
3084 mKeyguardDisabled.acquire(token, tag);
3085 }
3086
3087 public void reenableKeyguard(IBinder token) {
3088 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3089 != PackageManager.PERMISSION_GRANTED) {
3090 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3091 }
3092 synchronized (mKeyguardDisabled) {
3093 mKeyguardDisabled.release(token);
3094
3095 if (!mKeyguardDisabled.isAcquired()) {
3096 // if we are the last one to reenable the keyguard wait until
3097 // we have actaully finished reenabling until returning
3098 mWaitingUntilKeyguardReenabled = true;
3099 while (mWaitingUntilKeyguardReenabled) {
3100 try {
3101 mKeyguardDisabled.wait();
3102 } catch (InterruptedException e) {
3103 Thread.currentThread().interrupt();
3104 }
3105 }
3106 }
3107 }
3108 }
3109
3110 /**
3111 * @see android.app.KeyguardManager#exitKeyguardSecurely
3112 */
3113 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
3114 if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
3115 != PackageManager.PERMISSION_GRANTED) {
3116 throw new SecurityException("Requires DISABLE_KEYGUARD permission");
3117 }
3118 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
3119 public void onKeyguardExitResult(boolean success) {
3120 try {
3121 callback.onKeyguardExitResult(success);
3122 } catch (RemoteException e) {
3123 // Client has died, we don't care.
3124 }
3125 }
3126 });
3127 }
3128
3129 public boolean inKeyguardRestrictedInputMode() {
3130 return mPolicy.inKeyguardRestrictedKeyInputMode();
3131 }
Romain Guy06882f82009-06-10 13:36:04 -07003132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003133 static float fixScale(float scale) {
3134 if (scale < 0) scale = 0;
3135 else if (scale > 20) scale = 20;
3136 return Math.abs(scale);
3137 }
Romain Guy06882f82009-06-10 13:36:04 -07003138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003139 public void setAnimationScale(int which, float scale) {
3140 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3141 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003142 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 }
3144
3145 if (scale < 0) scale = 0;
3146 else if (scale > 20) scale = 20;
3147 scale = Math.abs(scale);
3148 switch (which) {
3149 case 0: mWindowAnimationScale = fixScale(scale); break;
3150 case 1: mTransitionAnimationScale = fixScale(scale); break;
3151 }
Romain Guy06882f82009-06-10 13:36:04 -07003152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 // Persist setting
3154 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3155 }
Romain Guy06882f82009-06-10 13:36:04 -07003156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 public void setAnimationScales(float[] scales) {
3158 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
3159 "setAnimationScale()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003160 throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 }
3162
3163 if (scales != null) {
3164 if (scales.length >= 1) {
3165 mWindowAnimationScale = fixScale(scales[0]);
3166 }
3167 if (scales.length >= 2) {
3168 mTransitionAnimationScale = fixScale(scales[1]);
3169 }
3170 }
Romain Guy06882f82009-06-10 13:36:04 -07003171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 // Persist setting
3173 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
3174 }
Romain Guy06882f82009-06-10 13:36:04 -07003175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 public float getAnimationScale(int which) {
3177 switch (which) {
3178 case 0: return mWindowAnimationScale;
3179 case 1: return mTransitionAnimationScale;
3180 }
3181 return 0;
3182 }
Romain Guy06882f82009-06-10 13:36:04 -07003183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 public float[] getAnimationScales() {
3185 return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
3186 }
Romain Guy06882f82009-06-10 13:36:04 -07003187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 public int getSwitchState(int sw) {
3189 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3190 "getSwitchState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003191 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 }
3193 return KeyInputQueue.getSwitchState(sw);
3194 }
Romain Guy06882f82009-06-10 13:36:04 -07003195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 public int getSwitchStateForDevice(int devid, int sw) {
3197 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3198 "getSwitchStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003199 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 }
3201 return KeyInputQueue.getSwitchState(devid, sw);
3202 }
Romain Guy06882f82009-06-10 13:36:04 -07003203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003204 public int getScancodeState(int sw) {
3205 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3206 "getScancodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003207 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 }
3209 return KeyInputQueue.getScancodeState(sw);
3210 }
Romain Guy06882f82009-06-10 13:36:04 -07003211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 public int getScancodeStateForDevice(int devid, int sw) {
3213 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3214 "getScancodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003215 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
3217 return KeyInputQueue.getScancodeState(devid, sw);
3218 }
Romain Guy06882f82009-06-10 13:36:04 -07003219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 public int getKeycodeState(int sw) {
3221 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3222 "getKeycodeState()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003223 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 }
3225 return KeyInputQueue.getKeycodeState(sw);
3226 }
Romain Guy06882f82009-06-10 13:36:04 -07003227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 public int getKeycodeStateForDevice(int devid, int sw) {
3229 if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
3230 "getKeycodeStateForDevice()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003231 throw new SecurityException("Requires READ_INPUT_STATE permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 }
3233 return KeyInputQueue.getKeycodeState(devid, sw);
3234 }
Romain Guy06882f82009-06-10 13:36:04 -07003235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
3237 return KeyInputQueue.hasKeys(keycodes, keyExists);
3238 }
Romain Guy06882f82009-06-10 13:36:04 -07003239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 public void enableScreenAfterBoot() {
3241 synchronized(mWindowMap) {
3242 if (mSystemBooted) {
3243 return;
3244 }
3245 mSystemBooted = true;
3246 }
Romain Guy06882f82009-06-10 13:36:04 -07003247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 performEnableScreen();
3249 }
Romain Guy06882f82009-06-10 13:36:04 -07003250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 public void enableScreenIfNeededLocked() {
3252 if (mDisplayEnabled) {
3253 return;
3254 }
3255 if (!mSystemBooted) {
3256 return;
3257 }
3258 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
3259 }
Romain Guy06882f82009-06-10 13:36:04 -07003260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 public void performEnableScreen() {
3262 synchronized(mWindowMap) {
3263 if (mDisplayEnabled) {
3264 return;
3265 }
3266 if (!mSystemBooted) {
3267 return;
3268 }
Romain Guy06882f82009-06-10 13:36:04 -07003269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 // Don't enable the screen until all existing windows
3271 // have been drawn.
3272 final int N = mWindows.size();
3273 for (int i=0; i<N; i++) {
3274 WindowState w = (WindowState)mWindows.get(i);
3275 if (w.isVisibleLw() && !w.isDisplayedLw()) {
3276 return;
3277 }
3278 }
Romain Guy06882f82009-06-10 13:36:04 -07003279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 mDisplayEnabled = true;
3281 if (false) {
3282 Log.i(TAG, "ENABLING SCREEN!");
3283 StringWriter sw = new StringWriter();
3284 PrintWriter pw = new PrintWriter(sw);
3285 this.dump(null, pw, null);
3286 Log.i(TAG, sw.toString());
3287 }
3288 try {
3289 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
3290 if (surfaceFlinger != null) {
3291 //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
3292 Parcel data = Parcel.obtain();
3293 data.writeInterfaceToken("android.ui.ISurfaceComposer");
3294 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
3295 data, null, 0);
3296 data.recycle();
3297 }
3298 } catch (RemoteException ex) {
3299 Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
3300 }
3301 }
Romain Guy06882f82009-06-10 13:36:04 -07003302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003303 mPolicy.enableScreenAfterBoot();
Romain Guy06882f82009-06-10 13:36:04 -07003304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305 // Make sure the last requested orientation has been applied.
Dianne Hackborn321ae682009-03-27 16:16:03 -07003306 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
3307 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 }
Romain Guy06882f82009-06-10 13:36:04 -07003309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 public void setInTouchMode(boolean mode) {
3311 synchronized(mWindowMap) {
3312 mInTouchMode = mode;
3313 }
3314 }
3315
Romain Guy06882f82009-06-10 13:36:04 -07003316 public void setRotation(int rotation,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003317 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003319 "setRotation()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07003320 throw new SecurityException("Requires SET_ORIENTATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 }
3322
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003323 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 }
Romain Guy06882f82009-06-10 13:36:04 -07003325
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003326 public void setRotationUnchecked(int rotation,
3327 boolean alwaysSendConfiguration, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 if(DEBUG_ORIENTATION) Log.v(TAG,
3329 "alwaysSendConfiguration set to "+alwaysSendConfiguration);
Romain Guy06882f82009-06-10 13:36:04 -07003330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 long origId = Binder.clearCallingIdentity();
3332 boolean changed;
3333 synchronized(mWindowMap) {
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003334 changed = setRotationUncheckedLocked(rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
Romain Guy06882f82009-06-10 13:36:04 -07003336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003337 if (changed) {
3338 sendNewConfiguration();
3339 synchronized(mWindowMap) {
3340 mLayoutNeeded = true;
3341 performLayoutAndPlaceSurfacesLocked();
3342 }
3343 } else if (alwaysSendConfiguration) {
3344 //update configuration ignoring orientation change
3345 sendNewConfiguration();
3346 }
Romain Guy06882f82009-06-10 13:36:04 -07003347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003348 Binder.restoreCallingIdentity(origId);
3349 }
Romain Guy06882f82009-06-10 13:36:04 -07003350
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003351 public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 boolean changed;
3353 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
3354 rotation = mRequestedRotation;
3355 } else {
3356 mRequestedRotation = rotation;
Dianne Hackborn321ae682009-03-27 16:16:03 -07003357 mLastRotationFlags = animFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358 }
3359 if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07003360 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 mRotation, mDisplayEnabled);
3362 if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
3363 changed = mDisplayEnabled && mRotation != rotation;
Romain Guy06882f82009-06-10 13:36:04 -07003364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 if (changed) {
Romain Guy06882f82009-06-10 13:36:04 -07003366 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 "Rotation changed to " + rotation
3368 + " from " + mRotation
3369 + " (forceApp=" + mForcedAppOrientation
3370 + ", req=" + mRequestedRotation + ")");
3371 mRotation = rotation;
3372 mWindowsFreezingScreen = true;
3373 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
3374 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
3375 2000);
3376 startFreezingDisplayLocked();
Dianne Hackborn1e880db2009-03-27 16:04:08 -07003377 Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 mQueue.setOrientation(rotation);
3379 if (mDisplayEnabled) {
Dianne Hackborn321ae682009-03-27 16:16:03 -07003380 Surface.setOrientation(0, rotation, animFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 }
3382 for (int i=mWindows.size()-1; i>=0; i--) {
3383 WindowState w = (WindowState)mWindows.get(i);
3384 if (w.mSurface != null) {
3385 w.mOrientationChanging = true;
3386 }
3387 }
3388 for (int i=mRotationWatchers.size()-1; i>=0; i--) {
3389 try {
3390 mRotationWatchers.get(i).onRotationChanged(rotation);
3391 } catch (RemoteException e) {
3392 }
3393 }
3394 } //end if changed
Romain Guy06882f82009-06-10 13:36:04 -07003395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 return changed;
3397 }
Romain Guy06882f82009-06-10 13:36:04 -07003398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003399 public int getRotation() {
3400 return mRotation;
3401 }
3402
3403 public int watchRotation(IRotationWatcher watcher) {
3404 final IBinder watcherBinder = watcher.asBinder();
3405 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
3406 public void binderDied() {
3407 synchronized (mWindowMap) {
3408 for (int i=0; i<mRotationWatchers.size(); i++) {
3409 if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
3410 mRotationWatchers.remove(i);
3411 i--;
3412 }
3413 }
3414 }
3415 }
3416 };
Romain Guy06882f82009-06-10 13:36:04 -07003417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 synchronized (mWindowMap) {
3419 try {
3420 watcher.asBinder().linkToDeath(dr, 0);
3421 mRotationWatchers.add(watcher);
3422 } catch (RemoteException e) {
3423 // Client died, no cleanup needed.
3424 }
Romain Guy06882f82009-06-10 13:36:04 -07003425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426 return mRotation;
3427 }
3428 }
3429
3430 /**
3431 * Starts the view server on the specified port.
3432 *
3433 * @param port The port to listener to.
3434 *
3435 * @return True if the server was successfully started, false otherwise.
3436 *
3437 * @see com.android.server.ViewServer
3438 * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
3439 */
3440 public boolean startViewServer(int port) {
Romain Guy06882f82009-06-10 13:36:04 -07003441 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 return false;
3443 }
3444
3445 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
3446 return false;
3447 }
3448
3449 if (port < 1024) {
3450 return false;
3451 }
3452
3453 if (mViewServer != null) {
3454 if (!mViewServer.isRunning()) {
3455 try {
3456 return mViewServer.start();
3457 } catch (IOException e) {
Romain Guy06882f82009-06-10 13:36:04 -07003458 Log.w(TAG, "View server did not start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 }
3460 }
3461 return false;
3462 }
3463
3464 try {
3465 mViewServer = new ViewServer(this, port);
3466 return mViewServer.start();
3467 } catch (IOException e) {
3468 Log.w(TAG, "View server did not start");
3469 }
3470 return false;
3471 }
3472
Romain Guy06882f82009-06-10 13:36:04 -07003473 private boolean isSystemSecure() {
3474 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
3475 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
3476 }
3477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 /**
3479 * Stops the view server if it exists.
3480 *
3481 * @return True if the server stopped, false if it wasn't started or
3482 * couldn't be stopped.
3483 *
3484 * @see com.android.server.ViewServer
3485 */
3486 public boolean stopViewServer() {
Romain Guy06882f82009-06-10 13:36:04 -07003487 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 return false;
3489 }
3490
3491 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
3492 return false;
3493 }
3494
3495 if (mViewServer != null) {
3496 return mViewServer.stop();
3497 }
3498 return false;
3499 }
3500
3501 /**
3502 * Indicates whether the view server is running.
3503 *
3504 * @return True if the server is running, false otherwise.
3505 *
3506 * @see com.android.server.ViewServer
3507 */
3508 public boolean isViewServerRunning() {
Romain Guy06882f82009-06-10 13:36:04 -07003509 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003510 return false;
3511 }
3512
3513 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
3514 return false;
3515 }
3516
3517 return mViewServer != null && mViewServer.isRunning();
3518 }
3519
3520 /**
3521 * Lists all availble windows in the system. The listing is written in the
3522 * specified Socket's output stream with the following syntax:
3523 * windowHashCodeInHexadecimal windowName
3524 * Each line of the ouput represents a different window.
3525 *
3526 * @param client The remote client to send the listing to.
3527 * @return False if an error occured, true otherwise.
3528 */
3529 boolean viewServerListWindows(Socket client) {
Romain Guy06882f82009-06-10 13:36:04 -07003530 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 return false;
3532 }
3533
3534 boolean result = true;
3535
3536 Object[] windows;
3537 synchronized (mWindowMap) {
3538 windows = new Object[mWindows.size()];
3539 //noinspection unchecked
3540 windows = mWindows.toArray(windows);
3541 }
3542
3543 BufferedWriter out = null;
3544
3545 // Any uncaught exception will crash the system process
3546 try {
3547 OutputStream clientStream = client.getOutputStream();
3548 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
3549
3550 final int count = windows.length;
3551 for (int i = 0; i < count; i++) {
3552 final WindowState w = (WindowState) windows[i];
3553 out.write(Integer.toHexString(System.identityHashCode(w)));
3554 out.write(' ');
3555 out.append(w.mAttrs.getTitle());
3556 out.write('\n');
3557 }
3558
3559 out.write("DONE.\n");
3560 out.flush();
3561 } catch (Exception e) {
3562 result = false;
3563 } finally {
3564 if (out != null) {
3565 try {
3566 out.close();
3567 } catch (IOException e) {
3568 result = false;
3569 }
3570 }
3571 }
3572
3573 return result;
3574 }
3575
3576 /**
3577 * Sends a command to a target window. The result of the command, if any, will be
3578 * written in the output stream of the specified socket.
3579 *
3580 * The parameters must follow this syntax:
3581 * windowHashcode extra
3582 *
3583 * Where XX is the length in characeters of the windowTitle.
3584 *
3585 * The first parameter is the target window. The window with the specified hashcode
3586 * will be the target. If no target can be found, nothing happens. The extra parameters
3587 * will be delivered to the target window and as parameters to the command itself.
3588 *
3589 * @param client The remote client to sent the result, if any, to.
3590 * @param command The command to execute.
3591 * @param parameters The command parameters.
3592 *
3593 * @return True if the command was successfully delivered, false otherwise. This does
3594 * not indicate whether the command itself was successful.
3595 */
3596 boolean viewServerWindowCommand(Socket client, String command, String parameters) {
Romain Guy06882f82009-06-10 13:36:04 -07003597 if (isSystemSecure()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 return false;
3599 }
3600
3601 boolean success = true;
3602 Parcel data = null;
3603 Parcel reply = null;
3604
3605 // Any uncaught exception will crash the system process
3606 try {
3607 // Find the hashcode of the window
3608 int index = parameters.indexOf(' ');
3609 if (index == -1) {
3610 index = parameters.length();
3611 }
3612 final String code = parameters.substring(0, index);
3613 int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
3614
3615 // Extract the command's parameter after the window description
3616 if (index < parameters.length()) {
3617 parameters = parameters.substring(index + 1);
3618 } else {
3619 parameters = "";
3620 }
3621
3622 final WindowManagerService.WindowState window = findWindow(hashCode);
3623 if (window == null) {
3624 return false;
3625 }
3626
3627 data = Parcel.obtain();
3628 data.writeInterfaceToken("android.view.IWindow");
3629 data.writeString(command);
3630 data.writeString(parameters);
3631 data.writeInt(1);
3632 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
3633
3634 reply = Parcel.obtain();
3635
3636 final IBinder binder = window.mClient.asBinder();
3637 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
3638 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
3639
3640 reply.readException();
3641
3642 } catch (Exception e) {
3643 Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
3644 success = false;
3645 } finally {
3646 if (data != null) {
3647 data.recycle();
3648 }
3649 if (reply != null) {
3650 reply.recycle();
3651 }
3652 }
3653
3654 return success;
3655 }
3656
3657 private WindowState findWindow(int hashCode) {
3658 if (hashCode == -1) {
3659 return getFocusedWindow();
3660 }
3661
3662 synchronized (mWindowMap) {
3663 final ArrayList windows = mWindows;
3664 final int count = windows.size();
3665
3666 for (int i = 0; i < count; i++) {
3667 WindowState w = (WindowState) windows.get(i);
3668 if (System.identityHashCode(w) == hashCode) {
3669 return w;
3670 }
3671 }
3672 }
3673
3674 return null;
3675 }
3676
3677 /*
3678 * Instruct the Activity Manager to fetch the current configuration and broadcast
3679 * that to config-changed listeners if appropriate.
3680 */
3681 void sendNewConfiguration() {
3682 try {
3683 mActivityManager.updateConfiguration(null);
3684 } catch (RemoteException e) {
3685 }
3686 }
Romain Guy06882f82009-06-10 13:36:04 -07003687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 public Configuration computeNewConfiguration() {
3689 synchronized (mWindowMap) {
Dianne Hackbornc485a602009-03-24 22:39:49 -07003690 return computeNewConfigurationLocked();
3691 }
3692 }
Romain Guy06882f82009-06-10 13:36:04 -07003693
Dianne Hackbornc485a602009-03-24 22:39:49 -07003694 Configuration computeNewConfigurationLocked() {
3695 Configuration config = new Configuration();
3696 if (!computeNewConfigurationLocked(config)) {
3697 return null;
3698 }
3699 Log.i(TAG, "Config changed: " + config);
3700 long now = SystemClock.uptimeMillis();
3701 //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
3702 if (mFreezeGcPending != 0) {
3703 if (now > (mFreezeGcPending+1000)) {
3704 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
3705 mH.removeMessages(H.FORCE_GC);
3706 Runtime.getRuntime().gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 mFreezeGcPending = now;
3708 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003709 } else {
3710 mFreezeGcPending = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 }
Dianne Hackbornc485a602009-03-24 22:39:49 -07003712 return config;
3713 }
Romain Guy06882f82009-06-10 13:36:04 -07003714
Dianne Hackbornc485a602009-03-24 22:39:49 -07003715 boolean computeNewConfigurationLocked(Configuration config) {
3716 if (mDisplay == null) {
3717 return false;
3718 }
3719 mQueue.getInputConfiguration(config);
3720 final int dw = mDisplay.getWidth();
3721 final int dh = mDisplay.getHeight();
3722 int orientation = Configuration.ORIENTATION_SQUARE;
3723 if (dw < dh) {
3724 orientation = Configuration.ORIENTATION_PORTRAIT;
3725 } else if (dw > dh) {
3726 orientation = Configuration.ORIENTATION_LANDSCAPE;
3727 }
3728 config.orientation = orientation;
Dianne Hackborn723738c2009-06-25 19:48:04 -07003729
3730 if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
3731 // Note we only do this once because at this point we don't
3732 // expect the screen to change in this way at runtime, and want
3733 // to avoid all of this computation for every config change.
3734 DisplayMetrics dm = new DisplayMetrics();
3735 mDisplay.getMetrics(dm);
3736 int longSize = dw;
3737 int shortSize = dh;
3738 if (longSize < shortSize) {
3739 int tmp = longSize;
3740 longSize = shortSize;
3741 shortSize = tmp;
3742 }
3743 longSize = (int)(longSize/dm.density);
3744 shortSize = (int)(shortSize/dm.density);
3745
3746 // These semi-magic numbers define our compatibility modes for
3747 // applications with different screens. Don't change unless you
3748 // make sure to test lots and lots of apps!
3749 if (longSize < 470) {
3750 // This is shorter than an HVGA normal density screen (which
3751 // is 480 pixels on its long side).
3752 screenLayout = Configuration.SCREENLAYOUT_SMALL;
3753 } else if (longSize > 490 && shortSize > 330) {
3754 // This is larger than an HVGA normal density screen (which
3755 // is 480x320 pixels).
3756 screenLayout = Configuration.SCREENLAYOUT_LARGE;
3757 } else {
3758 screenLayout = Configuration.SCREENLAYOUT_NORMAL;
3759 }
3760 }
3761 config.screenLayout = screenLayout;
3762
Dianne Hackbornc485a602009-03-24 22:39:49 -07003763 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
3764 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
3765 mPolicy.adjustConfigurationLw(config);
3766 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 }
Romain Guy06882f82009-06-10 13:36:04 -07003768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769 // -------------------------------------------------------------
3770 // Input Events and Focus Management
3771 // -------------------------------------------------------------
3772
3773 private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
Michael Chane96440f2009-05-06 10:27:36 -07003774 long curTime = SystemClock.uptimeMillis();
3775
3776 if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
3777 if (mLastTouchEventType == eventType &&
3778 (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
3779 return;
3780 }
3781 mLastUserActivityCallTime = curTime;
3782 mLastTouchEventType = eventType;
3783 }
3784
3785 if (targetWin == null
3786 || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
3787 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 }
3789 }
3790
3791 // tells if it's a cheek event or not -- this function is stateful
3792 private static final int EVENT_NONE = 0;
3793 private static final int EVENT_UNKNOWN = 0;
3794 private static final int EVENT_CHEEK = 0;
3795 private static final int EVENT_IGNORE_DURATION = 300; // ms
3796 private static final float CHEEK_THRESHOLD = 0.6f;
3797 private int mEventState = EVENT_NONE;
3798 private float mEventSize;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003800 private int eventType(MotionEvent ev) {
3801 float size = ev.getSize();
3802 switch (ev.getAction()) {
3803 case MotionEvent.ACTION_DOWN:
3804 mEventSize = size;
3805 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
3806 case MotionEvent.ACTION_UP:
3807 if (size > mEventSize) mEventSize = size;
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003808 return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003809 case MotionEvent.ACTION_MOVE:
3810 final int N = ev.getHistorySize();
3811 if (size > mEventSize) mEventSize = size;
3812 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3813 for (int i=0; i<N; i++) {
3814 size = ev.getHistoricalSize(i);
3815 if (size > mEventSize) mEventSize = size;
3816 if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
3817 }
3818 if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
3819 return TOUCH_EVENT;
3820 } else {
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07003821 return LONG_TOUCH_EVENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 }
3823 default:
3824 // not good
3825 return OTHER_EVENT;
3826 }
3827 }
3828
3829 /**
3830 * @return Returns true if event was dispatched, false if it was dropped for any reason
3831 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07003832 private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
3834 "dispatchPointer " + ev);
3835
3836 Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
3837 ev, true, false);
Romain Guy06882f82009-06-10 13:36:04 -07003838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003839 int action = ev.getAction();
Romain Guy06882f82009-06-10 13:36:04 -07003840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003841 if (action == MotionEvent.ACTION_UP) {
3842 // let go of our target
3843 mKeyWaiter.mMotionTarget = null;
3844 mPowerManager.logPointerUpEvent();
3845 } else if (action == MotionEvent.ACTION_DOWN) {
3846 mPowerManager.logPointerDownEvent();
3847 }
3848
3849 if (targetObj == null) {
3850 // In this case we are either dropping the event, or have received
3851 // a move or up without a down. It is common to receive move
3852 // events in such a way, since this means the user is moving the
3853 // pointer without actually pressing down. All other cases should
3854 // be atypical, so let's log them.
Michael Chane96440f2009-05-06 10:27:36 -07003855 if (action != MotionEvent.ACTION_MOVE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003856 Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
3857 }
3858 if (qev != null) {
3859 mQueue.recycleEvent(qev);
3860 }
3861 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003862 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003863 }
3864 if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
3865 if (qev != null) {
3866 mQueue.recycleEvent(qev);
3867 }
3868 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003869 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870 }
Romain Guy06882f82009-06-10 13:36:04 -07003871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872 WindowState target = (WindowState)targetObj;
Romain Guy06882f82009-06-10 13:36:04 -07003873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07003875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 //Log.i(TAG, "Sending " + ev + " to " + target);
3877
3878 if (uid != 0 && uid != target.mSession.mUid) {
3879 if (mContext.checkPermission(
3880 android.Manifest.permission.INJECT_EVENTS, pid, uid)
3881 != PackageManager.PERMISSION_GRANTED) {
3882 Log.w(TAG, "Permission denied: injecting pointer event from pid "
3883 + pid + " uid " + uid + " to window " + target
3884 + " owned by uid " + target.mSession.mUid);
3885 if (qev != null) {
3886 mQueue.recycleEvent(qev);
3887 }
3888 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003889 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 }
3891 }
Romain Guy06882f82009-06-10 13:36:04 -07003892
3893 if ((target.mAttrs.flags &
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003894 WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
3895 //target wants to ignore fat touch events
3896 boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
3897 //explicit flag to return without processing event further
3898 boolean returnFlag = false;
3899 if((action == MotionEvent.ACTION_DOWN)) {
3900 mFatTouch = false;
3901 if(cheekPress) {
3902 mFatTouch = true;
3903 returnFlag = true;
3904 }
3905 } else {
3906 if(action == MotionEvent.ACTION_UP) {
3907 if(mFatTouch) {
3908 //earlier even was invalid doesnt matter if current up is cheekpress or not
3909 mFatTouch = false;
3910 returnFlag = true;
3911 } else if(cheekPress) {
3912 //cancel the earlier event
3913 ev.setAction(MotionEvent.ACTION_CANCEL);
3914 action = MotionEvent.ACTION_CANCEL;
3915 }
3916 } else if(action == MotionEvent.ACTION_MOVE) {
3917 if(mFatTouch) {
3918 //two cases here
3919 //an invalid down followed by 0 or moves(valid or invalid)
Romain Guy06882f82009-06-10 13:36:04 -07003920 //a valid down, invalid move, more moves. want to ignore till up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921 returnFlag = true;
3922 } else if(cheekPress) {
3923 //valid down followed by invalid moves
3924 //an invalid move have to cancel earlier action
3925 ev.setAction(MotionEvent.ACTION_CANCEL);
3926 action = MotionEvent.ACTION_CANCEL;
3927 if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE");
3928 //note that the subsequent invalid moves will not get here
3929 mFatTouch = true;
3930 }
3931 }
3932 } //else if action
3933 if(returnFlag) {
3934 //recycle que, ev
3935 if (qev != null) {
3936 mQueue.recycleEvent(qev);
3937 }
3938 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07003939 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003940 }
3941 } //end if target
Michael Chane96440f2009-05-06 10:27:36 -07003942
3943 // TODO remove once we settle on a value or make it app specific
3944 if (action == MotionEvent.ACTION_DOWN) {
3945 int max_events_per_sec = 35;
3946 try {
3947 max_events_per_sec = Integer.parseInt(SystemProperties
3948 .get("windowsmgr.max_events_per_sec"));
3949 if (max_events_per_sec < 1) {
3950 max_events_per_sec = 35;
3951 }
3952 } catch (NumberFormatException e) {
3953 }
3954 mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
3955 }
3956
3957 /*
3958 * Throttle events to minimize CPU usage when there's a flood of events
3959 * e.g. constant contact with the screen
3960 */
3961 if (action == MotionEvent.ACTION_MOVE) {
3962 long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
3963 long now = SystemClock.uptimeMillis();
3964 if (now < nextEventTime) {
3965 try {
3966 Thread.sleep(nextEventTime - now);
3967 } catch (InterruptedException e) {
3968 }
3969 mLastTouchEventTime = nextEventTime;
3970 } else {
3971 mLastTouchEventTime = now;
3972 }
3973 }
3974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003975 synchronized(mWindowMap) {
3976 if (qev != null && action == MotionEvent.ACTION_MOVE) {
3977 mKeyWaiter.bindTargetWindowLocked(target,
3978 KeyWaiter.RETURN_PENDING_POINTER, qev);
3979 ev = null;
3980 } else {
3981 if (action == MotionEvent.ACTION_DOWN) {
3982 WindowState out = mKeyWaiter.mOutsideTouchTargets;
3983 if (out != null) {
3984 MotionEvent oev = MotionEvent.obtain(ev);
3985 oev.setAction(MotionEvent.ACTION_OUTSIDE);
3986 do {
3987 final Rect frame = out.mFrame;
3988 oev.offsetLocation(-(float)frame.left, -(float)frame.top);
3989 try {
3990 out.mClient.dispatchPointer(oev, eventTime);
3991 } catch (android.os.RemoteException e) {
3992 Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
3993 }
3994 oev.offsetLocation((float)frame.left, (float)frame.top);
3995 out = out.mNextOutsideTouch;
3996 } while (out != null);
3997 mKeyWaiter.mOutsideTouchTargets = null;
3998 }
3999 }
4000 final Rect frame = target.mFrame;
4001 ev.offsetLocation(-(float)frame.left, -(float)frame.top);
4002 mKeyWaiter.bindTargetWindowLocked(target);
4003 }
4004 }
Romain Guy06882f82009-06-10 13:36:04 -07004005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004006 // finally offset the event to the target's coordinate system and
4007 // dispatch the event.
4008 try {
4009 if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
4010 Log.v(TAG, "Delivering pointer " + qev + " to " + target);
4011 }
4012 target.mClient.dispatchPointer(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004013 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014 } catch (android.os.RemoteException e) {
4015 Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
4016 mKeyWaiter.mMotionTarget = null;
4017 try {
4018 removeWindow(target.mSession, target.mClient);
4019 } catch (java.util.NoSuchElementException ex) {
4020 // This will happen if the window has already been
4021 // removed.
4022 }
4023 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004024 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004025 }
Romain Guy06882f82009-06-10 13:36:04 -07004026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 /**
4028 * @return Returns true if event was dispatched, false if it was dropped for any reason
4029 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004030 private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004031 if (DEBUG_INPUT) Log.v(
4032 TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
Romain Guy06882f82009-06-10 13:36:04 -07004033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004034 Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
4035 ev, false, false);
4036 if (focusObj == null) {
4037 Log.w(TAG, "No focus window, dropping trackball: " + ev);
4038 if (qev != null) {
4039 mQueue.recycleEvent(qev);
4040 }
4041 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004042 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 }
4044 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
4045 if (qev != null) {
4046 mQueue.recycleEvent(qev);
4047 }
4048 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004049 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004050 }
Romain Guy06882f82009-06-10 13:36:04 -07004051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004052 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 if (uid != 0 && uid != focus.mSession.mUid) {
4055 if (mContext.checkPermission(
4056 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4057 != PackageManager.PERMISSION_GRANTED) {
4058 Log.w(TAG, "Permission denied: injecting key event from pid "
4059 + pid + " uid " + uid + " to window " + focus
4060 + " owned by uid " + focus.mSession.mUid);
4061 if (qev != null) {
4062 mQueue.recycleEvent(qev);
4063 }
4064 ev.recycle();
Dianne Hackborncfaef692009-06-15 14:24:44 -07004065 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004066 }
4067 }
Romain Guy06882f82009-06-10 13:36:04 -07004068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004069 final long eventTime = ev.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004071 synchronized(mWindowMap) {
4072 if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
4073 mKeyWaiter.bindTargetWindowLocked(focus,
4074 KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
4075 // We don't deliver movement events to the client, we hold
4076 // them and wait for them to call back.
4077 ev = null;
4078 } else {
4079 mKeyWaiter.bindTargetWindowLocked(focus);
4080 }
4081 }
Romain Guy06882f82009-06-10 13:36:04 -07004082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004083 try {
4084 focus.mClient.dispatchTrackball(ev, eventTime);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004085 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004086 } catch (android.os.RemoteException e) {
4087 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4088 try {
4089 removeWindow(focus.mSession, focus.mClient);
4090 } catch (java.util.NoSuchElementException ex) {
4091 // This will happen if the window has already been
4092 // removed.
4093 }
4094 }
Romain Guy06882f82009-06-10 13:36:04 -07004095
Dianne Hackborncfaef692009-06-15 14:24:44 -07004096 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 }
Romain Guy06882f82009-06-10 13:36:04 -07004098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 /**
4100 * @return Returns true if event was dispatched, false if it was dropped for any reason
4101 */
Dianne Hackborncfaef692009-06-15 14:24:44 -07004102 private int dispatchKey(KeyEvent event, int pid, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
4104
4105 Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
4106 null, false, false);
4107 if (focusObj == null) {
4108 Log.w(TAG, "No focus window, dropping: " + event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004109 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004110 }
4111 if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004112 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004113 }
Romain Guy06882f82009-06-10 13:36:04 -07004114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004115 WindowState focus = (WindowState)focusObj;
Romain Guy06882f82009-06-10 13:36:04 -07004116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004117 if (DEBUG_INPUT) Log.v(
4118 TAG, "Dispatching to " + focus + ": " + event);
4119
4120 if (uid != 0 && uid != focus.mSession.mUid) {
4121 if (mContext.checkPermission(
4122 android.Manifest.permission.INJECT_EVENTS, pid, uid)
4123 != PackageManager.PERMISSION_GRANTED) {
4124 Log.w(TAG, "Permission denied: injecting key event from pid "
4125 + pid + " uid " + uid + " to window " + focus
4126 + " owned by uid " + focus.mSession.mUid);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004127 return INJECT_NO_PERMISSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128 }
4129 }
Romain Guy06882f82009-06-10 13:36:04 -07004130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004131 synchronized(mWindowMap) {
4132 mKeyWaiter.bindTargetWindowLocked(focus);
4133 }
4134
4135 // NOSHIP extra state logging
4136 mKeyWaiter.recordDispatchState(event, focus);
4137 // END NOSHIP
Romain Guy06882f82009-06-10 13:36:04 -07004138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 try {
4140 if (DEBUG_INPUT || DEBUG_FOCUS) {
4141 Log.v(TAG, "Delivering key " + event.getKeyCode()
4142 + " to " + focus);
4143 }
4144 focus.mClient.dispatchKey(event);
Dianne Hackborncfaef692009-06-15 14:24:44 -07004145 return INJECT_SUCCEEDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004146 } catch (android.os.RemoteException e) {
4147 Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
4148 try {
4149 removeWindow(focus.mSession, focus.mClient);
4150 } catch (java.util.NoSuchElementException ex) {
4151 // This will happen if the window has already been
4152 // removed.
4153 }
4154 }
Romain Guy06882f82009-06-10 13:36:04 -07004155
Dianne Hackborncfaef692009-06-15 14:24:44 -07004156 return INJECT_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004157 }
Romain Guy06882f82009-06-10 13:36:04 -07004158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 public void pauseKeyDispatching(IBinder _token) {
4160 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4161 "pauseKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004162 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004163 }
4164
4165 synchronized (mWindowMap) {
4166 WindowToken token = mTokenMap.get(_token);
4167 if (token != null) {
4168 mKeyWaiter.pauseDispatchingLocked(token);
4169 }
4170 }
4171 }
4172
4173 public void resumeKeyDispatching(IBinder _token) {
4174 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4175 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004176 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004177 }
4178
4179 synchronized (mWindowMap) {
4180 WindowToken token = mTokenMap.get(_token);
4181 if (token != null) {
4182 mKeyWaiter.resumeDispatchingLocked(token);
4183 }
4184 }
4185 }
4186
4187 public void setEventDispatching(boolean enabled) {
4188 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4189 "resumeKeyDispatching()")) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004190 throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004191 }
4192
4193 synchronized (mWindowMap) {
4194 mKeyWaiter.setEventDispatchingLocked(enabled);
4195 }
4196 }
Romain Guy06882f82009-06-10 13:36:04 -07004197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004198 /**
4199 * Injects a keystroke event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004200 *
4201 * @param ev A motion event describing the keystroke action. (Be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004202 * {@link SystemClock#uptimeMillis()} as the timebase.)
4203 * @param sync If true, wait for the event to be completed before returning to the caller.
4204 * @return Returns true if event was dispatched, false if it was dropped for any reason
4205 */
4206 public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
4207 long downTime = ev.getDownTime();
4208 long eventTime = ev.getEventTime();
4209
4210 int action = ev.getAction();
4211 int code = ev.getKeyCode();
4212 int repeatCount = ev.getRepeatCount();
4213 int metaState = ev.getMetaState();
4214 int deviceId = ev.getDeviceId();
4215 int scancode = ev.getScanCode();
4216
4217 if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
4218 if (downTime == 0) downTime = eventTime;
4219
4220 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
The Android Open Source Project10592532009-03-18 17:39:46 -07004221 deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004222
Dianne Hackborncfaef692009-06-15 14:24:44 -07004223 int result = dispatchKey(newEvent, Binder.getCallingPid(), Binder.getCallingUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004224 if (sync) {
4225 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
4226 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004227 switch (result) {
4228 case INJECT_NO_PERMISSION:
4229 throw new SecurityException(
4230 "Injecting to another application requires INJECT_EVENT permission");
4231 case INJECT_SUCCEEDED:
4232 return true;
4233 }
4234 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004235 }
4236
4237 /**
4238 * Inject a pointer (touch) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004239 *
4240 * @param ev A motion event describing the pointer (touch) action. (As noted in
4241 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004242 * {@link SystemClock#uptimeMillis()} as the timebase.)
4243 * @param sync If true, wait for the event to be completed before returning to the caller.
4244 * @return Returns true if event was dispatched, false if it was dropped for any reason
4245 */
4246 public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004247 int result = dispatchPointer(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004248 if (sync) {
4249 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
4250 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004251 switch (result) {
4252 case INJECT_NO_PERMISSION:
4253 throw new SecurityException(
4254 "Injecting to another application requires INJECT_EVENT permission");
4255 case INJECT_SUCCEEDED:
4256 return true;
4257 }
4258 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004259 }
Romain Guy06882f82009-06-10 13:36:04 -07004260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004261 /**
4262 * Inject a trackball (navigation device) event into the UI.
Romain Guy06882f82009-06-10 13:36:04 -07004263 *
4264 * @param ev A motion event describing the trackball action. (As noted in
4265 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266 * {@link SystemClock#uptimeMillis()} as the timebase.)
4267 * @param sync If true, wait for the event to be completed before returning to the caller.
4268 * @return Returns true if event was dispatched, false if it was dropped for any reason
4269 */
4270 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
Dianne Hackborncfaef692009-06-15 14:24:44 -07004271 int result = dispatchTrackball(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004272 if (sync) {
4273 mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
4274 }
Dianne Hackborncfaef692009-06-15 14:24:44 -07004275 switch (result) {
4276 case INJECT_NO_PERMISSION:
4277 throw new SecurityException(
4278 "Injecting to another application requires INJECT_EVENT permission");
4279 case INJECT_SUCCEEDED:
4280 return true;
4281 }
4282 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004283 }
Romain Guy06882f82009-06-10 13:36:04 -07004284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004285 private WindowState getFocusedWindow() {
4286 synchronized (mWindowMap) {
4287 return getFocusedWindowLocked();
4288 }
4289 }
4290
4291 private WindowState getFocusedWindowLocked() {
4292 return mCurrentFocus;
4293 }
Romain Guy06882f82009-06-10 13:36:04 -07004294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004295 /**
4296 * This class holds the state for dispatching key events. This state
4297 * is protected by the KeyWaiter instance, NOT by the window lock. You
4298 * can be holding the main window lock while acquire the KeyWaiter lock,
4299 * but not the other way around.
4300 */
4301 final class KeyWaiter {
4302 // NOSHIP debugging
4303 public class DispatchState {
4304 private KeyEvent event;
4305 private WindowState focus;
4306 private long time;
4307 private WindowState lastWin;
4308 private IBinder lastBinder;
4309 private boolean finished;
4310 private boolean gotFirstWindow;
4311 private boolean eventDispatching;
4312 private long timeToSwitch;
4313 private boolean wasFrozen;
4314 private boolean focusPaused;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004315 private WindowState curFocus;
Romain Guy06882f82009-06-10 13:36:04 -07004316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004317 DispatchState(KeyEvent theEvent, WindowState theFocus) {
4318 focus = theFocus;
4319 event = theEvent;
4320 time = System.currentTimeMillis();
4321 // snapshot KeyWaiter state
4322 lastWin = mLastWin;
4323 lastBinder = mLastBinder;
4324 finished = mFinished;
4325 gotFirstWindow = mGotFirstWindow;
4326 eventDispatching = mEventDispatching;
4327 timeToSwitch = mTimeToSwitch;
4328 wasFrozen = mWasFrozen;
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004329 curFocus = mCurrentFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004330 // cache the paused state at ctor time as well
4331 if (theFocus == null || theFocus.mToken == null) {
4332 Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
4333 focusPaused = false;
4334 } else {
4335 focusPaused = theFocus.mToken.paused;
4336 }
4337 }
Romain Guy06882f82009-06-10 13:36:04 -07004338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004339 public String toString() {
4340 return "{{" + event + " to " + focus + " @ " + time
4341 + " lw=" + lastWin + " lb=" + lastBinder
4342 + " fin=" + finished + " gfw=" + gotFirstWindow
4343 + " ed=" + eventDispatching + " tts=" + timeToSwitch
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004344 + " wf=" + wasFrozen + " fp=" + focusPaused
4345 + " mcf=" + mCurrentFocus + "}}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004346 }
4347 };
4348 private DispatchState mDispatchState = null;
4349 public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
4350 mDispatchState = new DispatchState(theEvent, theFocus);
4351 }
4352 // END NOSHIP
4353
4354 public static final int RETURN_NOTHING = 0;
4355 public static final int RETURN_PENDING_POINTER = 1;
4356 public static final int RETURN_PENDING_TRACKBALL = 2;
Romain Guy06882f82009-06-10 13:36:04 -07004357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004358 final Object SKIP_TARGET_TOKEN = new Object();
4359 final Object CONSUMED_EVENT_TOKEN = new Object();
Romain Guy06882f82009-06-10 13:36:04 -07004360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004361 private WindowState mLastWin = null;
4362 private IBinder mLastBinder = null;
4363 private boolean mFinished = true;
4364 private boolean mGotFirstWindow = false;
4365 private boolean mEventDispatching = true;
4366 private long mTimeToSwitch = 0;
4367 /* package */ boolean mWasFrozen = false;
Romain Guy06882f82009-06-10 13:36:04 -07004368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004369 // Target of Motion events
4370 WindowState mMotionTarget;
Romain Guy06882f82009-06-10 13:36:04 -07004371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004372 // Windows above the target who would like to receive an "outside"
4373 // touch event for any down events outside of them.
4374 WindowState mOutsideTouchTargets;
4375
4376 /**
4377 * Wait for the last event dispatch to complete, then find the next
4378 * target that should receive the given event and wait for that one
4379 * to be ready to receive it.
4380 */
4381 Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
4382 MotionEvent nextMotion, boolean isPointerEvent,
4383 boolean failIfTimeout) {
4384 long startTime = SystemClock.uptimeMillis();
4385 long keyDispatchingTimeout = 5 * 1000;
4386 long waitedFor = 0;
4387
4388 while (true) {
4389 // Figure out which window we care about. It is either the
4390 // last window we are waiting to have process the event or,
4391 // if none, then the next window we think the event should go
4392 // to. Note: we retrieve mLastWin outside of the lock, so
4393 // it may change before we lock. Thus we must check it again.
4394 WindowState targetWin = mLastWin;
4395 boolean targetIsNew = targetWin == null;
4396 if (DEBUG_INPUT) Log.v(
4397 TAG, "waitForLastKey: mFinished=" + mFinished +
4398 ", mLastWin=" + mLastWin);
4399 if (targetIsNew) {
4400 Object target = findTargetWindow(nextKey, qev, nextMotion,
4401 isPointerEvent);
4402 if (target == SKIP_TARGET_TOKEN) {
4403 // The user has pressed a special key, and we are
4404 // dropping all pending events before it.
4405 if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey
4406 + " " + nextMotion);
4407 return null;
4408 }
4409 if (target == CONSUMED_EVENT_TOKEN) {
4410 if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
4411 + " " + nextMotion);
4412 return target;
4413 }
4414 targetWin = (WindowState)target;
4415 }
Romain Guy06882f82009-06-10 13:36:04 -07004416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004417 AppWindowToken targetApp = null;
Romain Guy06882f82009-06-10 13:36:04 -07004418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004419 // Now: is it okay to send the next event to this window?
4420 synchronized (this) {
4421 // First: did we come here based on the last window not
4422 // being null, but it changed by the time we got here?
4423 // If so, try again.
4424 if (!targetIsNew && mLastWin == null) {
4425 continue;
4426 }
Romain Guy06882f82009-06-10 13:36:04 -07004427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004428 // We never dispatch events if not finished with the
4429 // last one, or the display is frozen.
4430 if (mFinished && !mDisplayFrozen) {
4431 // If event dispatching is disabled, then we
4432 // just consume the events.
4433 if (!mEventDispatching) {
4434 if (DEBUG_INPUT) Log.v(TAG,
4435 "Skipping event; dispatching disabled: "
4436 + nextKey + " " + nextMotion);
4437 return null;
4438 }
4439 if (targetWin != null) {
4440 // If this is a new target, and that target is not
4441 // paused or unresponsive, then all looks good to
4442 // handle the event.
4443 if (targetIsNew && !targetWin.mToken.paused) {
4444 return targetWin;
4445 }
Romain Guy06882f82009-06-10 13:36:04 -07004446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004447 // If we didn't find a target window, and there is no
4448 // focused app window, then just eat the events.
4449 } else if (mFocusedApp == null) {
4450 if (DEBUG_INPUT) Log.v(TAG,
4451 "Skipping event; no focused app: "
4452 + nextKey + " " + nextMotion);
4453 return null;
4454 }
4455 }
Romain Guy06882f82009-06-10 13:36:04 -07004456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004457 if (DEBUG_INPUT) Log.v(
4458 TAG, "Waiting for last key in " + mLastBinder
4459 + " target=" + targetWin
4460 + " mFinished=" + mFinished
4461 + " mDisplayFrozen=" + mDisplayFrozen
4462 + " targetIsNew=" + targetIsNew
4463 + " paused="
4464 + (targetWin != null ? targetWin.mToken.paused : false)
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004465 + " mFocusedApp=" + mFocusedApp
4466 + " mCurrentFocus=" + mCurrentFocus);
Romain Guy06882f82009-06-10 13:36:04 -07004467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004468 targetApp = targetWin != null
4469 ? targetWin.mAppToken : mFocusedApp;
Romain Guy06882f82009-06-10 13:36:04 -07004470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004471 long curTimeout = keyDispatchingTimeout;
4472 if (mTimeToSwitch != 0) {
4473 long now = SystemClock.uptimeMillis();
4474 if (mTimeToSwitch <= now) {
4475 // If an app switch key has been pressed, and we have
4476 // waited too long for the current app to finish
4477 // processing keys, then wait no more!
4478 doFinishedKeyLocked(true);
4479 continue;
4480 }
4481 long switchTimeout = mTimeToSwitch - now;
4482 if (curTimeout > switchTimeout) {
4483 curTimeout = switchTimeout;
4484 }
4485 }
Romain Guy06882f82009-06-10 13:36:04 -07004486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004487 try {
4488 // after that continue
4489 // processing keys, so we don't get stuck.
4490 if (DEBUG_INPUT) Log.v(
4491 TAG, "Waiting for key dispatch: " + curTimeout);
4492 wait(curTimeout);
4493 if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
4494 + SystemClock.uptimeMillis() + " startTime="
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004495 + startTime + " switchTime=" + mTimeToSwitch
4496 + " target=" + targetWin + " mLW=" + mLastWin
4497 + " mLB=" + mLastBinder + " fin=" + mFinished
4498 + " mCurrentFocus=" + mCurrentFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004499 } catch (InterruptedException e) {
4500 }
4501 }
4502
4503 // If we were frozen during configuration change, restart the
4504 // timeout checks from now; otherwise look at whether we timed
4505 // out before awakening.
4506 if (mWasFrozen) {
4507 waitedFor = 0;
4508 mWasFrozen = false;
4509 } else {
4510 waitedFor = SystemClock.uptimeMillis() - startTime;
4511 }
4512
4513 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
4514 IApplicationToken at = null;
4515 synchronized (this) {
4516 Log.w(TAG, "Key dispatching timed out sending to " +
4517 (targetWin != null ? targetWin.mAttrs.getTitle()
4518 : "<null>"));
4519 // NOSHIP debugging
4520 Log.w(TAG, "Dispatch state: " + mDispatchState);
4521 Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
4522 // END NOSHIP
4523 //dump();
4524 if (targetWin != null) {
4525 at = targetWin.getAppToken();
4526 } else if (targetApp != null) {
4527 at = targetApp.appToken;
4528 }
4529 }
4530
4531 boolean abort = true;
4532 if (at != null) {
4533 try {
4534 long timeout = at.getKeyDispatchingTimeout();
4535 if (timeout > waitedFor) {
4536 // we did not wait the proper amount of time for this application.
4537 // set the timeout to be the real timeout and wait again.
4538 keyDispatchingTimeout = timeout - waitedFor;
4539 continue;
4540 } else {
4541 abort = at.keyDispatchingTimedOut();
4542 }
4543 } catch (RemoteException ex) {
4544 }
4545 }
4546
4547 synchronized (this) {
4548 if (abort && (mLastWin == targetWin || targetWin == null)) {
4549 mFinished = true;
Romain Guy06882f82009-06-10 13:36:04 -07004550 if (mLastWin != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004551 if (DEBUG_INPUT) Log.v(TAG,
4552 "Window " + mLastWin +
4553 " timed out on key input");
4554 if (mLastWin.mToken.paused) {
4555 Log.w(TAG, "Un-pausing dispatching to this window");
4556 mLastWin.mToken.paused = false;
4557 }
4558 }
4559 if (mMotionTarget == targetWin) {
4560 mMotionTarget = null;
4561 }
4562 mLastWin = null;
4563 mLastBinder = null;
4564 if (failIfTimeout || targetWin == null) {
4565 return null;
4566 }
4567 } else {
4568 Log.w(TAG, "Continuing to wait for key to be dispatched");
4569 startTime = SystemClock.uptimeMillis();
4570 }
4571 }
4572 }
4573 }
4574 }
Romain Guy06882f82009-06-10 13:36:04 -07004575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
4577 MotionEvent nextMotion, boolean isPointerEvent) {
4578 mOutsideTouchTargets = null;
Romain Guy06882f82009-06-10 13:36:04 -07004579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004580 if (nextKey != null) {
4581 // Find the target window for a normal key event.
4582 final int keycode = nextKey.getKeyCode();
4583 final int repeatCount = nextKey.getRepeatCount();
4584 final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
4585 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
4586 if (!dispatch) {
4587 mPolicy.interceptKeyTi(null, keycode,
4588 nextKey.getMetaState(), down, repeatCount);
4589 Log.w(TAG, "Event timeout during app switch: dropping "
4590 + nextKey);
4591 return SKIP_TARGET_TOKEN;
4592 }
Romain Guy06882f82009-06-10 13:36:04 -07004593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004594 // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
Romain Guy06882f82009-06-10 13:36:04 -07004595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 WindowState focus = null;
4597 synchronized(mWindowMap) {
4598 focus = getFocusedWindowLocked();
4599 }
Romain Guy06882f82009-06-10 13:36:04 -07004600
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
Romain Guy06882f82009-06-10 13:36:04 -07004602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 if (mPolicy.interceptKeyTi(focus,
4604 keycode, nextKey.getMetaState(), down, repeatCount)) {
4605 return CONSUMED_EVENT_TOKEN;
4606 }
Romain Guy06882f82009-06-10 13:36:04 -07004607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 return focus;
Romain Guy06882f82009-06-10 13:36:04 -07004609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 } else if (!isPointerEvent) {
4611 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
4612 if (!dispatch) {
4613 Log.w(TAG, "Event timeout during app switch: dropping trackball "
4614 + nextMotion);
4615 return SKIP_TARGET_TOKEN;
4616 }
Romain Guy06882f82009-06-10 13:36:04 -07004617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004618 WindowState focus = null;
4619 synchronized(mWindowMap) {
4620 focus = getFocusedWindowLocked();
4621 }
Romain Guy06882f82009-06-10 13:36:04 -07004622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004623 wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
4624 return focus;
4625 }
Romain Guy06882f82009-06-10 13:36:04 -07004626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004627 if (nextMotion == null) {
4628 return SKIP_TARGET_TOKEN;
4629 }
Romain Guy06882f82009-06-10 13:36:04 -07004630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631 boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
4632 KeyEvent.KEYCODE_UNKNOWN);
4633 if (!dispatch) {
4634 Log.w(TAG, "Event timeout during app switch: dropping pointer "
4635 + nextMotion);
4636 return SKIP_TARGET_TOKEN;
4637 }
Romain Guy06882f82009-06-10 13:36:04 -07004638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 // Find the target window for a pointer event.
4640 int action = nextMotion.getAction();
4641 final float xf = nextMotion.getX();
4642 final float yf = nextMotion.getY();
4643 final long eventTime = nextMotion.getEventTime();
Romain Guy06882f82009-06-10 13:36:04 -07004644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004645 final boolean screenWasOff = qev != null
4646 && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
Romain Guy06882f82009-06-10 13:36:04 -07004647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004648 WindowState target = null;
Romain Guy06882f82009-06-10 13:36:04 -07004649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650 synchronized(mWindowMap) {
4651 synchronized (this) {
4652 if (action == MotionEvent.ACTION_DOWN) {
4653 if (mMotionTarget != null) {
4654 // this is weird, we got a pen down, but we thought it was
4655 // already down!
4656 // XXX: We should probably send an ACTION_UP to the current
4657 // target.
4658 Log.w(TAG, "Pointer down received while already down in: "
4659 + mMotionTarget);
4660 mMotionTarget = null;
4661 }
Romain Guy06882f82009-06-10 13:36:04 -07004662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004663 // ACTION_DOWN is special, because we need to lock next events to
4664 // the window we'll land onto.
4665 final int x = (int)xf;
4666 final int y = (int)yf;
Romain Guy06882f82009-06-10 13:36:04 -07004667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004668 final ArrayList windows = mWindows;
4669 final int N = windows.size();
4670 WindowState topErrWindow = null;
4671 final Rect tmpRect = mTempRect;
4672 for (int i=N-1; i>=0; i--) {
4673 WindowState child = (WindowState)windows.get(i);
4674 //Log.i(TAG, "Checking dispatch to: " + child);
4675 final int flags = child.mAttrs.flags;
4676 if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
4677 if (topErrWindow == null) {
4678 topErrWindow = child;
4679 }
4680 }
4681 if (!child.isVisibleLw()) {
4682 //Log.i(TAG, "Not visible!");
4683 continue;
4684 }
4685 if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
4686 //Log.i(TAG, "Not touchable!");
4687 if ((flags & WindowManager.LayoutParams
4688 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4689 child.mNextOutsideTouch = mOutsideTouchTargets;
4690 mOutsideTouchTargets = child;
4691 }
4692 continue;
4693 }
4694 tmpRect.set(child.mFrame);
4695 if (child.mTouchableInsets == ViewTreeObserver
4696 .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
4697 // The touch is inside of the window if it is
4698 // inside the frame, AND the content part of that
4699 // frame that was given by the application.
4700 tmpRect.left += child.mGivenContentInsets.left;
4701 tmpRect.top += child.mGivenContentInsets.top;
4702 tmpRect.right -= child.mGivenContentInsets.right;
4703 tmpRect.bottom -= child.mGivenContentInsets.bottom;
4704 } else if (child.mTouchableInsets == ViewTreeObserver
4705 .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
4706 // The touch is inside of the window if it is
4707 // inside the frame, AND the visible part of that
4708 // frame that was given by the application.
4709 tmpRect.left += child.mGivenVisibleInsets.left;
4710 tmpRect.top += child.mGivenVisibleInsets.top;
4711 tmpRect.right -= child.mGivenVisibleInsets.right;
4712 tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
4713 }
4714 final int touchFlags = flags &
4715 (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
4716 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
4717 if (tmpRect.contains(x, y) || touchFlags == 0) {
4718 //Log.i(TAG, "Using this target!");
4719 if (!screenWasOff || (flags &
4720 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
4721 mMotionTarget = child;
4722 } else {
4723 //Log.i(TAG, "Waking, skip!");
4724 mMotionTarget = null;
4725 }
4726 break;
4727 }
Romain Guy06882f82009-06-10 13:36:04 -07004728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004729 if ((flags & WindowManager.LayoutParams
4730 .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
4731 child.mNextOutsideTouch = mOutsideTouchTargets;
4732 mOutsideTouchTargets = child;
4733 //Log.i(TAG, "Adding to outside target list: " + child);
4734 }
4735 }
4736
4737 // if there's an error window but it's not accepting
4738 // focus (typically because it is not yet visible) just
4739 // wait for it -- any other focused window may in fact
4740 // be in ANR state.
4741 if (topErrWindow != null && mMotionTarget != topErrWindow) {
4742 mMotionTarget = null;
4743 }
4744 }
Romain Guy06882f82009-06-10 13:36:04 -07004745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 target = mMotionTarget;
4747 }
4748 }
Romain Guy06882f82009-06-10 13:36:04 -07004749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004750 wakeupIfNeeded(target, eventType(nextMotion));
Romain Guy06882f82009-06-10 13:36:04 -07004751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 // Pointer events are a little different -- if there isn't a
4753 // target found for any event, then just drop it.
4754 return target != null ? target : SKIP_TARGET_TOKEN;
4755 }
Romain Guy06882f82009-06-10 13:36:04 -07004756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004757 boolean checkShouldDispatchKey(int keycode) {
4758 synchronized (this) {
4759 if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
4760 mTimeToSwitch = 0;
4761 return true;
4762 }
4763 if (mTimeToSwitch != 0
4764 && mTimeToSwitch < SystemClock.uptimeMillis()) {
4765 return false;
4766 }
4767 return true;
4768 }
4769 }
Romain Guy06882f82009-06-10 13:36:04 -07004770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004771 void bindTargetWindowLocked(WindowState win,
4772 int pendingWhat, QueuedEvent pendingMotion) {
4773 synchronized (this) {
4774 bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
4775 }
4776 }
Romain Guy06882f82009-06-10 13:36:04 -07004777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004778 void bindTargetWindowLocked(WindowState win) {
4779 synchronized (this) {
4780 bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
4781 }
4782 }
4783
4784 void bindTargetWindowLockedLocked(WindowState win,
4785 int pendingWhat, QueuedEvent pendingMotion) {
4786 mLastWin = win;
4787 mLastBinder = win.mClient.asBinder();
4788 mFinished = false;
4789 if (pendingMotion != null) {
4790 final Session s = win.mSession;
4791 if (pendingWhat == RETURN_PENDING_POINTER) {
4792 releasePendingPointerLocked(s);
4793 s.mPendingPointerMove = pendingMotion;
4794 s.mPendingPointerWindow = win;
Romain Guy06882f82009-06-10 13:36:04 -07004795 if (DEBUG_INPUT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004796 "bindTargetToWindow " + s.mPendingPointerMove);
4797 } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
4798 releasePendingTrackballLocked(s);
4799 s.mPendingTrackballMove = pendingMotion;
4800 s.mPendingTrackballWindow = win;
4801 }
4802 }
4803 }
Romain Guy06882f82009-06-10 13:36:04 -07004804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 void releasePendingPointerLocked(Session s) {
4806 if (DEBUG_INPUT) Log.v(TAG,
4807 "releasePendingPointer " + s.mPendingPointerMove);
4808 if (s.mPendingPointerMove != null) {
4809 mQueue.recycleEvent(s.mPendingPointerMove);
4810 s.mPendingPointerMove = null;
4811 }
4812 }
Romain Guy06882f82009-06-10 13:36:04 -07004813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 void releasePendingTrackballLocked(Session s) {
4815 if (s.mPendingTrackballMove != null) {
4816 mQueue.recycleEvent(s.mPendingTrackballMove);
4817 s.mPendingTrackballMove = null;
4818 }
4819 }
Romain Guy06882f82009-06-10 13:36:04 -07004820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004821 MotionEvent finishedKey(Session session, IWindow client, boolean force,
4822 int returnWhat) {
4823 if (DEBUG_INPUT) Log.v(
4824 TAG, "finishedKey: client=" + client + ", force=" + force);
4825
4826 if (client == null) {
4827 return null;
4828 }
4829
4830 synchronized (this) {
4831 if (DEBUG_INPUT) Log.v(
4832 TAG, "finishedKey: client=" + client.asBinder()
4833 + ", force=" + force + ", last=" + mLastBinder
4834 + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
4835
4836 QueuedEvent qev = null;
4837 WindowState win = null;
4838 if (returnWhat == RETURN_PENDING_POINTER) {
4839 qev = session.mPendingPointerMove;
4840 win = session.mPendingPointerWindow;
4841 session.mPendingPointerMove = null;
4842 session.mPendingPointerWindow = null;
4843 } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
4844 qev = session.mPendingTrackballMove;
4845 win = session.mPendingTrackballWindow;
4846 session.mPendingTrackballMove = null;
4847 session.mPendingTrackballWindow = null;
4848 }
Romain Guy06882f82009-06-10 13:36:04 -07004849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004850 if (mLastBinder == client.asBinder()) {
4851 if (DEBUG_INPUT) Log.v(
4852 TAG, "finishedKey: last paused="
4853 + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
4854 if (mLastWin != null && (!mLastWin.mToken.paused || force
4855 || !mEventDispatching)) {
4856 doFinishedKeyLocked(false);
4857 } else {
4858 // Make sure to wake up anyone currently waiting to
4859 // dispatch a key, so they can re-evaluate their
4860 // current situation.
4861 mFinished = true;
4862 notifyAll();
4863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 }
Romain Guy06882f82009-06-10 13:36:04 -07004865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004866 if (qev != null) {
4867 MotionEvent res = (MotionEvent)qev.event;
4868 if (DEBUG_INPUT) Log.v(TAG,
4869 "Returning pending motion: " + res);
4870 mQueue.recycleEvent(qev);
4871 if (win != null && returnWhat == RETURN_PENDING_POINTER) {
4872 res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
4873 }
4874 return res;
4875 }
4876 return null;
4877 }
4878 }
4879
4880 void tickle() {
4881 synchronized (this) {
4882 notifyAll();
4883 }
4884 }
Romain Guy06882f82009-06-10 13:36:04 -07004885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004886 void handleNewWindowLocked(WindowState newWindow) {
4887 if (!newWindow.canReceiveKeys()) {
4888 return;
4889 }
4890 synchronized (this) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004891 if (DEBUG_INPUT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004892 TAG, "New key dispatch window: win="
4893 + newWindow.mClient.asBinder()
4894 + ", last=" + mLastBinder
4895 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
4896 + "), finished=" + mFinished + ", paused="
4897 + newWindow.mToken.paused);
4898
4899 // Displaying a window implicitly causes dispatching to
4900 // be unpaused. (This is to protect against bugs if someone
4901 // pauses dispatching but forgets to resume.)
4902 newWindow.mToken.paused = false;
4903
4904 mGotFirstWindow = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004905
4906 if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
4907 if (DEBUG_INPUT) Log.v(TAG,
4908 "New SYSTEM_ERROR window; resetting state");
4909 mLastWin = null;
4910 mLastBinder = null;
4911 mMotionTarget = null;
4912 mFinished = true;
4913 } else if (mLastWin != null) {
4914 // If the new window is above the window we are
4915 // waiting on, then stop waiting and let key dispatching
4916 // start on the new guy.
4917 if (DEBUG_INPUT) Log.v(
4918 TAG, "Last win layer=" + mLastWin.mLayer
4919 + ", new win layer=" + newWindow.mLayer);
4920 if (newWindow.mLayer >= mLastWin.mLayer) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004921 // The new window is above the old; finish pending input to the last
4922 // window and start directing it to the new one.
4923 mLastWin.mToken.paused = false;
4924 doFinishedKeyLocked(true); // does a notifyAll()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004925 }
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004926 // Either the new window is lower, so there is no need to wake key waiters,
4927 // or we just finished key input to the previous window, which implicitly
4928 // notified the key waiters. In both cases, we don't need to issue the
4929 // notification here.
4930 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004931 }
4932
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08004933 // Now that we've put a new window state in place, make the event waiter
4934 // take notice and retarget its attentions.
4935 notifyAll();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004936 }
4937 }
4938
4939 void pauseDispatchingLocked(WindowToken token) {
4940 synchronized (this)
4941 {
4942 if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
4943 token.paused = true;
4944
4945 /*
4946 if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
4947 mPaused = true;
4948 } else {
4949 if (mLastWin == null) {
Dave Bortcfe65242009-04-09 14:51:04 -07004950 Log.i(TAG, "Key dispatching not paused: no last window.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004951 } else if (mFinished) {
Dave Bortcfe65242009-04-09 14:51:04 -07004952 Log.i(TAG, "Key dispatching not paused: finished last key.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004953 } else {
Dave Bortcfe65242009-04-09 14:51:04 -07004954 Log.i(TAG, "Key dispatching not paused: window in higher layer.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004955 }
4956 }
4957 */
4958 }
4959 }
4960
4961 void resumeDispatchingLocked(WindowToken token) {
4962 synchronized (this) {
4963 if (token.paused) {
4964 if (DEBUG_INPUT) Log.v(
4965 TAG, "Resuming WindowToken " + token
4966 + ", last=" + mLastBinder
4967 + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
4968 + "), finished=" + mFinished + ", paused="
4969 + token.paused);
4970 token.paused = false;
4971 if (mLastWin != null && mLastWin.mToken == token && mFinished) {
4972 doFinishedKeyLocked(true);
4973 } else {
4974 notifyAll();
4975 }
4976 }
4977 }
4978 }
4979
4980 void setEventDispatchingLocked(boolean enabled) {
4981 synchronized (this) {
4982 mEventDispatching = enabled;
4983 notifyAll();
4984 }
4985 }
Romain Guy06882f82009-06-10 13:36:04 -07004986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004987 void appSwitchComing() {
4988 synchronized (this) {
4989 // Don't wait for more than .5 seconds for app to finish
4990 // processing the pending events.
4991 long now = SystemClock.uptimeMillis() + 500;
4992 if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now);
4993 if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
4994 mTimeToSwitch = now;
4995 }
4996 notifyAll();
4997 }
4998 }
Romain Guy06882f82009-06-10 13:36:04 -07004999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005000 private final void doFinishedKeyLocked(boolean doRecycle) {
5001 if (mLastWin != null) {
5002 releasePendingPointerLocked(mLastWin.mSession);
5003 releasePendingTrackballLocked(mLastWin.mSession);
5004 }
Romain Guy06882f82009-06-10 13:36:04 -07005005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005006 if (mLastWin == null || !mLastWin.mToken.paused
5007 || !mLastWin.isVisibleLw()) {
5008 // If the current window has been paused, we aren't -really-
5009 // finished... so let the waiters still wait.
5010 mLastWin = null;
5011 mLastBinder = null;
5012 }
5013 mFinished = true;
5014 notifyAll();
5015 }
5016 }
5017
5018 private class KeyQ extends KeyInputQueue
5019 implements KeyInputQueue.FilterCallback {
5020 PowerManager.WakeLock mHoldingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07005021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005022 KeyQ() {
5023 super(mContext);
5024 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
5025 mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
5026 "KEEP_SCREEN_ON_FLAG");
5027 mHoldingScreen.setReferenceCounted(false);
5028 }
5029
5030 @Override
5031 boolean preprocessEvent(InputDevice device, RawInputEvent event) {
5032 if (mPolicy.preprocessInputEventTq(event)) {
5033 return true;
5034 }
Romain Guy06882f82009-06-10 13:36:04 -07005035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005036 switch (event.type) {
5037 case RawInputEvent.EV_KEY: {
5038 // XXX begin hack
5039 if (DEBUG) {
5040 if (event.keycode == KeyEvent.KEYCODE_G) {
5041 if (event.value != 0) {
5042 // G down
5043 mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
5044 }
5045 return false;
5046 }
5047 if (event.keycode == KeyEvent.KEYCODE_D) {
5048 if (event.value != 0) {
5049 //dump();
5050 }
5051 return false;
5052 }
5053 }
5054 // XXX end hack
Romain Guy06882f82009-06-10 13:36:04 -07005055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005056 boolean screenIsOff = !mPowerManager.screenIsOn();
5057 boolean screenIsDim = !mPowerManager.screenIsBright();
5058 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
Romain Guy06882f82009-06-10 13:36:04 -07005059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005060 if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
5061 mPowerManager.goToSleep(event.when);
5062 }
5063
5064 if (screenIsOff) {
5065 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5066 }
5067 if (screenIsDim) {
5068 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5069 }
5070 if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
5071 mPowerManager.userActivity(event.when, false,
Michael Chane96440f2009-05-06 10:27:36 -07005072 LocalPowerManager.BUTTON_EVENT, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005073 }
Romain Guy06882f82009-06-10 13:36:04 -07005074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005075 if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
5076 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
5077 filterQueue(this);
5078 mKeyWaiter.appSwitchComing();
5079 }
5080 return true;
5081 } else {
5082 return false;
5083 }
5084 }
Romain Guy06882f82009-06-10 13:36:04 -07005085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005086 case RawInputEvent.EV_REL: {
5087 boolean screenIsOff = !mPowerManager.screenIsOn();
5088 boolean screenIsDim = !mPowerManager.screenIsBright();
5089 if (screenIsOff) {
5090 if (!mPolicy.isWakeRelMovementTq(event.deviceId,
5091 device.classes, event)) {
5092 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5093 return false;
5094 }
5095 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5096 }
5097 if (screenIsDim) {
5098 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5099 }
5100 return true;
5101 }
Romain Guy06882f82009-06-10 13:36:04 -07005102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005103 case RawInputEvent.EV_ABS: {
5104 boolean screenIsOff = !mPowerManager.screenIsOn();
5105 boolean screenIsDim = !mPowerManager.screenIsBright();
5106 if (screenIsOff) {
5107 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
5108 device.classes, event)) {
5109 //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
5110 return false;
5111 }
5112 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
5113 }
5114 if (screenIsDim) {
5115 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
5116 }
5117 return true;
5118 }
Romain Guy06882f82009-06-10 13:36:04 -07005119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005120 default:
5121 return true;
5122 }
5123 }
5124
5125 public int filterEvent(QueuedEvent ev) {
5126 switch (ev.classType) {
5127 case RawInputEvent.CLASS_KEYBOARD:
5128 KeyEvent ke = (KeyEvent)ev.event;
5129 if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
5130 Log.w(TAG, "Dropping movement key during app switch: "
5131 + ke.getKeyCode() + ", action=" + ke.getAction());
5132 return FILTER_REMOVE;
5133 }
5134 return FILTER_ABORT;
5135 default:
5136 return FILTER_KEEP;
5137 }
5138 }
Romain Guy06882f82009-06-10 13:36:04 -07005139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140 /**
5141 * Must be called with the main window manager lock held.
5142 */
5143 void setHoldScreenLocked(boolean holding) {
5144 boolean state = mHoldingScreen.isHeld();
5145 if (holding != state) {
5146 if (holding) {
5147 mHoldingScreen.acquire();
5148 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005149 mPolicy.screenOnStoppedLw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005150 mHoldingScreen.release();
5151 }
5152 }
5153 }
5154 };
5155
5156 public boolean detectSafeMode() {
5157 mSafeMode = mPolicy.detectSafeMode();
5158 return mSafeMode;
5159 }
Romain Guy06882f82009-06-10 13:36:04 -07005160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005161 public void systemReady() {
5162 mPolicy.systemReady();
5163 }
Romain Guy06882f82009-06-10 13:36:04 -07005164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005165 private final class InputDispatcherThread extends Thread {
5166 // Time to wait when there is nothing to do: 9999 seconds.
5167 static final int LONG_WAIT=9999*1000;
5168
5169 public InputDispatcherThread() {
5170 super("InputDispatcher");
5171 }
Romain Guy06882f82009-06-10 13:36:04 -07005172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005173 @Override
5174 public void run() {
5175 while (true) {
5176 try {
5177 process();
5178 } catch (Exception e) {
5179 Log.e(TAG, "Exception in input dispatcher", e);
5180 }
5181 }
5182 }
Romain Guy06882f82009-06-10 13:36:04 -07005183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005184 private void process() {
5185 android.os.Process.setThreadPriority(
5186 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
Romain Guy06882f82009-06-10 13:36:04 -07005187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005188 // The last key event we saw
5189 KeyEvent lastKey = null;
5190
5191 // Last keydown time for auto-repeating keys
5192 long lastKeyTime = SystemClock.uptimeMillis();
5193 long nextKeyTime = lastKeyTime+LONG_WAIT;
5194
Romain Guy06882f82009-06-10 13:36:04 -07005195 // How many successive repeats we generated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005196 int keyRepeatCount = 0;
5197
5198 // Need to report that configuration has changed?
5199 boolean configChanged = false;
Romain Guy06882f82009-06-10 13:36:04 -07005200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005201 while (true) {
5202 long curTime = SystemClock.uptimeMillis();
5203
5204 if (DEBUG_INPUT) Log.v(
5205 TAG, "Waiting for next key: now=" + curTime
5206 + ", repeat @ " + nextKeyTime);
5207
5208 // Retrieve next event, waiting only as long as the next
5209 // repeat timeout. If the configuration has changed, then
5210 // don't wait at all -- we'll report the change as soon as
5211 // we have processed all events.
5212 QueuedEvent ev = mQueue.getEvent(
5213 (int)((!configChanged && curTime < nextKeyTime)
5214 ? (nextKeyTime-curTime) : 0));
5215
5216 if (DEBUG_INPUT && ev != null) Log.v(
5217 TAG, "Event: type=" + ev.classType + " data=" + ev.event);
5218
5219 try {
5220 if (ev != null) {
5221 curTime = ev.when;
5222 int eventType;
5223 if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
5224 eventType = eventType((MotionEvent)ev.event);
5225 } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
5226 ev.classType == RawInputEvent.CLASS_TRACKBALL) {
5227 eventType = LocalPowerManager.BUTTON_EVENT;
5228 } else {
5229 eventType = LocalPowerManager.OTHER_EVENT;
5230 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005231 try {
Michael Chane96440f2009-05-06 10:27:36 -07005232 long now = SystemClock.uptimeMillis();
5233
5234 if ((now - mLastBatteryStatsCallTime)
5235 >= MIN_TIME_BETWEEN_USERACTIVITIES) {
5236 mLastBatteryStatsCallTime = now;
5237 mBatteryStats.noteInputEvent();
5238 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07005239 } catch (RemoteException e) {
5240 // Ignore
5241 }
Michael Chane96440f2009-05-06 10:27:36 -07005242 mPowerManager.userActivity(curTime, false, eventType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005243 switch (ev.classType) {
5244 case RawInputEvent.CLASS_KEYBOARD:
5245 KeyEvent ke = (KeyEvent)ev.event;
5246 if (ke.isDown()) {
5247 lastKey = ke;
5248 keyRepeatCount = 0;
5249 lastKeyTime = curTime;
5250 nextKeyTime = lastKeyTime
5251 + KEY_REPEAT_FIRST_DELAY;
5252 if (DEBUG_INPUT) Log.v(
5253 TAG, "Received key down: first repeat @ "
5254 + nextKeyTime);
5255 } else {
5256 lastKey = null;
5257 // Arbitrary long timeout.
5258 lastKeyTime = curTime;
5259 nextKeyTime = curTime + LONG_WAIT;
5260 if (DEBUG_INPUT) Log.v(
5261 TAG, "Received key up: ignore repeat @ "
5262 + nextKeyTime);
5263 }
5264 dispatchKey((KeyEvent)ev.event, 0, 0);
5265 mQueue.recycleEvent(ev);
5266 break;
5267 case RawInputEvent.CLASS_TOUCHSCREEN:
5268 //Log.i(TAG, "Read next event " + ev);
5269 dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
5270 break;
5271 case RawInputEvent.CLASS_TRACKBALL:
5272 dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
5273 break;
5274 case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
5275 configChanged = true;
5276 break;
5277 default:
5278 mQueue.recycleEvent(ev);
5279 break;
5280 }
Romain Guy06882f82009-06-10 13:36:04 -07005281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005282 } else if (configChanged) {
5283 configChanged = false;
5284 sendNewConfiguration();
Romain Guy06882f82009-06-10 13:36:04 -07005285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 } else if (lastKey != null) {
5287 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005289 // Timeout occurred while key was down. If it is at or
5290 // past the key repeat time, dispatch the repeat.
5291 if (DEBUG_INPUT) Log.v(
5292 TAG, "Key timeout: repeat=" + nextKeyTime
5293 + ", now=" + curTime);
5294 if (curTime < nextKeyTime) {
5295 continue;
5296 }
Romain Guy06882f82009-06-10 13:36:04 -07005297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005298 lastKeyTime = nextKeyTime;
5299 nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
5300 keyRepeatCount++;
5301 if (DEBUG_INPUT) Log.v(
5302 TAG, "Key repeat: count=" + keyRepeatCount
5303 + ", next @ " + nextKeyTime);
The Android Open Source Project10592532009-03-18 17:39:46 -07005304 dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
Romain Guy06882f82009-06-10 13:36:04 -07005305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005306 } else {
5307 curTime = SystemClock.uptimeMillis();
Romain Guy06882f82009-06-10 13:36:04 -07005308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 lastKeyTime = curTime;
5310 nextKeyTime = curTime + LONG_WAIT;
5311 }
Romain Guy06882f82009-06-10 13:36:04 -07005312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 } catch (Exception e) {
5314 Log.e(TAG,
5315 "Input thread received uncaught exception: " + e, e);
5316 }
5317 }
5318 }
5319 }
5320
5321 // -------------------------------------------------------------
5322 // Client Session State
5323 // -------------------------------------------------------------
5324
5325 private final class Session extends IWindowSession.Stub
5326 implements IBinder.DeathRecipient {
5327 final IInputMethodClient mClient;
5328 final IInputContext mInputContext;
5329 final int mUid;
5330 final int mPid;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005331 final String mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005332 SurfaceSession mSurfaceSession;
5333 int mNumWindow = 0;
5334 boolean mClientDead = false;
Romain Guy06882f82009-06-10 13:36:04 -07005335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005336 /**
5337 * Current pointer move event being dispatched to client window... must
5338 * hold key lock to access.
5339 */
5340 QueuedEvent mPendingPointerMove;
5341 WindowState mPendingPointerWindow;
Romain Guy06882f82009-06-10 13:36:04 -07005342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005343 /**
5344 * Current trackball move event being dispatched to client window... must
5345 * hold key lock to access.
5346 */
5347 QueuedEvent mPendingTrackballMove;
5348 WindowState mPendingTrackballWindow;
5349
5350 public Session(IInputMethodClient client, IInputContext inputContext) {
5351 mClient = client;
5352 mInputContext = inputContext;
5353 mUid = Binder.getCallingUid();
5354 mPid = Binder.getCallingPid();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005355 StringBuilder sb = new StringBuilder();
5356 sb.append("Session{");
5357 sb.append(Integer.toHexString(System.identityHashCode(this)));
5358 sb.append(" uid ");
5359 sb.append(mUid);
5360 sb.append("}");
5361 mStringName = sb.toString();
Romain Guy06882f82009-06-10 13:36:04 -07005362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005363 synchronized (mWindowMap) {
5364 if (mInputMethodManager == null && mHaveInputMethods) {
5365 IBinder b = ServiceManager.getService(
5366 Context.INPUT_METHOD_SERVICE);
5367 mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
5368 }
5369 }
5370 long ident = Binder.clearCallingIdentity();
5371 try {
5372 // Note: it is safe to call in to the input method manager
5373 // here because we are not holding our lock.
5374 if (mInputMethodManager != null) {
5375 mInputMethodManager.addClient(client, inputContext,
5376 mUid, mPid);
5377 } else {
5378 client.setUsingInputMethod(false);
5379 }
5380 client.asBinder().linkToDeath(this, 0);
5381 } catch (RemoteException e) {
5382 // The caller has died, so we can just forget about this.
5383 try {
5384 if (mInputMethodManager != null) {
5385 mInputMethodManager.removeClient(client);
5386 }
5387 } catch (RemoteException ee) {
5388 }
5389 } finally {
5390 Binder.restoreCallingIdentity(ident);
5391 }
5392 }
Romain Guy06882f82009-06-10 13:36:04 -07005393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 @Override
5395 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5396 throws RemoteException {
5397 try {
5398 return super.onTransact(code, data, reply, flags);
5399 } catch (RuntimeException e) {
5400 // Log all 'real' exceptions thrown to the caller
5401 if (!(e instanceof SecurityException)) {
5402 Log.e(TAG, "Window Session Crash", e);
5403 }
5404 throw e;
5405 }
5406 }
5407
5408 public void binderDied() {
5409 // Note: it is safe to call in to the input method manager
5410 // here because we are not holding our lock.
5411 try {
5412 if (mInputMethodManager != null) {
5413 mInputMethodManager.removeClient(mClient);
5414 }
5415 } catch (RemoteException e) {
5416 }
5417 synchronized(mWindowMap) {
5418 mClientDead = true;
5419 killSessionLocked();
5420 }
5421 }
5422
5423 public int add(IWindow window, WindowManager.LayoutParams attrs,
5424 int viewVisibility, Rect outContentInsets) {
5425 return addWindow(this, window, attrs, viewVisibility, outContentInsets);
5426 }
Romain Guy06882f82009-06-10 13:36:04 -07005427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005428 public void remove(IWindow window) {
5429 removeWindow(this, window);
5430 }
Romain Guy06882f82009-06-10 13:36:04 -07005431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005432 public int relayout(IWindow window, WindowManager.LayoutParams attrs,
5433 int requestedWidth, int requestedHeight, int viewFlags,
5434 boolean insetsPending, Rect outFrame, Rect outContentInsets,
5435 Rect outVisibleInsets, Surface outSurface) {
5436 return relayoutWindow(this, window, attrs,
5437 requestedWidth, requestedHeight, viewFlags, insetsPending,
5438 outFrame, outContentInsets, outVisibleInsets, outSurface);
5439 }
Romain Guy06882f82009-06-10 13:36:04 -07005440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005441 public void setTransparentRegion(IWindow window, Region region) {
5442 setTransparentRegionWindow(this, window, region);
5443 }
Romain Guy06882f82009-06-10 13:36:04 -07005444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005445 public void setInsets(IWindow window, int touchableInsets,
5446 Rect contentInsets, Rect visibleInsets) {
5447 setInsetsWindow(this, window, touchableInsets, contentInsets,
5448 visibleInsets);
5449 }
Romain Guy06882f82009-06-10 13:36:04 -07005450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005451 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
5452 getWindowDisplayFrame(this, window, outDisplayFrame);
5453 }
Romain Guy06882f82009-06-10 13:36:04 -07005454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005455 public void finishDrawing(IWindow window) {
5456 if (localLOGV) Log.v(
5457 TAG, "IWindow finishDrawing called for " + window);
5458 finishDrawingWindow(this, window);
5459 }
5460
5461 public void finishKey(IWindow window) {
5462 if (localLOGV) Log.v(
5463 TAG, "IWindow finishKey called for " + window);
5464 mKeyWaiter.finishedKey(this, window, false,
5465 KeyWaiter.RETURN_NOTHING);
5466 }
5467
5468 public MotionEvent getPendingPointerMove(IWindow window) {
5469 if (localLOGV) Log.v(
5470 TAG, "IWindow getPendingMotionEvent called for " + window);
5471 return mKeyWaiter.finishedKey(this, window, false,
5472 KeyWaiter.RETURN_PENDING_POINTER);
5473 }
Romain Guy06882f82009-06-10 13:36:04 -07005474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005475 public MotionEvent getPendingTrackballMove(IWindow window) {
5476 if (localLOGV) Log.v(
5477 TAG, "IWindow getPendingMotionEvent called for " + window);
5478 return mKeyWaiter.finishedKey(this, window, false,
5479 KeyWaiter.RETURN_PENDING_TRACKBALL);
5480 }
5481
5482 public void setInTouchMode(boolean mode) {
5483 synchronized(mWindowMap) {
5484 mInTouchMode = mode;
5485 }
5486 }
5487
5488 public boolean getInTouchMode() {
5489 synchronized(mWindowMap) {
5490 return mInTouchMode;
5491 }
5492 }
5493
5494 public boolean performHapticFeedback(IWindow window, int effectId,
5495 boolean always) {
5496 synchronized(mWindowMap) {
5497 long ident = Binder.clearCallingIdentity();
5498 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07005499 return mPolicy.performHapticFeedbackLw(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005500 windowForClientLocked(this, window), effectId, always);
5501 } finally {
5502 Binder.restoreCallingIdentity(ident);
5503 }
5504 }
5505 }
Romain Guy06882f82009-06-10 13:36:04 -07005506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005507 void windowAddedLocked() {
5508 if (mSurfaceSession == null) {
5509 if (localLOGV) Log.v(
5510 TAG, "First window added to " + this + ", creating SurfaceSession");
5511 mSurfaceSession = new SurfaceSession();
5512 mSessions.add(this);
5513 }
5514 mNumWindow++;
5515 }
5516
5517 void windowRemovedLocked() {
5518 mNumWindow--;
5519 killSessionLocked();
5520 }
Romain Guy06882f82009-06-10 13:36:04 -07005521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005522 void killSessionLocked() {
5523 if (mNumWindow <= 0 && mClientDead) {
5524 mSessions.remove(this);
5525 if (mSurfaceSession != null) {
5526 if (localLOGV) Log.v(
5527 TAG, "Last window removed from " + this
5528 + ", destroying " + mSurfaceSession);
5529 try {
5530 mSurfaceSession.kill();
5531 } catch (Exception e) {
5532 Log.w(TAG, "Exception thrown when killing surface session "
5533 + mSurfaceSession + " in session " + this
5534 + ": " + e.toString());
5535 }
5536 mSurfaceSession = null;
5537 }
5538 }
5539 }
Romain Guy06882f82009-06-10 13:36:04 -07005540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005541 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005542 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
5543 pw.print(" mClientDead="); pw.print(mClientDead);
5544 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
5545 if (mPendingPointerWindow != null || mPendingPointerMove != null) {
5546 pw.print(prefix);
5547 pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
5548 pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
5549 }
5550 if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
5551 pw.print(prefix);
5552 pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
5553 pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
5554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005555 }
5556
5557 @Override
5558 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07005559 return mStringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005560 }
5561 }
5562
5563 // -------------------------------------------------------------
5564 // Client Window State
5565 // -------------------------------------------------------------
5566
5567 private final class WindowState implements WindowManagerPolicy.WindowState {
5568 final Session mSession;
5569 final IWindow mClient;
5570 WindowToken mToken;
The Android Open Source Project10592532009-03-18 17:39:46 -07005571 WindowToken mRootToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005572 AppWindowToken mAppToken;
5573 AppWindowToken mTargetAppToken;
5574 final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
5575 final DeathRecipient mDeathRecipient;
5576 final WindowState mAttachedWindow;
5577 final ArrayList mChildWindows = new ArrayList();
5578 final int mBaseLayer;
5579 final int mSubLayer;
5580 final boolean mLayoutAttached;
5581 final boolean mIsImWindow;
5582 int mViewVisibility;
5583 boolean mPolicyVisibility = true;
5584 boolean mPolicyVisibilityAfterAnim = true;
5585 boolean mAppFreezing;
5586 Surface mSurface;
5587 boolean mAttachedHidden; // is our parent window hidden?
5588 boolean mLastHidden; // was this window last hidden?
5589 int mRequestedWidth;
5590 int mRequestedHeight;
5591 int mLastRequestedWidth;
5592 int mLastRequestedHeight;
5593 int mReqXPos;
5594 int mReqYPos;
5595 int mLayer;
5596 int mAnimLayer;
5597 int mLastLayer;
5598 boolean mHaveFrame;
5599
5600 WindowState mNextOutsideTouch;
Romain Guy06882f82009-06-10 13:36:04 -07005601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005602 // Actual frame shown on-screen (may be modified by animation)
5603 final Rect mShownFrame = new Rect();
5604 final Rect mLastShownFrame = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005606 /**
5607 * Insets that determine the actually visible area
5608 */
5609 final Rect mVisibleInsets = new Rect();
5610 final Rect mLastVisibleInsets = new Rect();
5611 boolean mVisibleInsetsChanged;
5612
5613 /**
5614 * Insets that are covered by system windows
5615 */
5616 final Rect mContentInsets = new Rect();
5617 final Rect mLastContentInsets = new Rect();
5618 boolean mContentInsetsChanged;
5619
5620 /**
5621 * Set to true if we are waiting for this window to receive its
5622 * given internal insets before laying out other windows based on it.
5623 */
5624 boolean mGivenInsetsPending;
Romain Guy06882f82009-06-10 13:36:04 -07005625
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005626 /**
5627 * These are the content insets that were given during layout for
5628 * this window, to be applied to windows behind it.
5629 */
5630 final Rect mGivenContentInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005632 /**
5633 * These are the visible insets that were given during layout for
5634 * this window, to be applied to windows behind it.
5635 */
5636 final Rect mGivenVisibleInsets = new Rect();
Romain Guy06882f82009-06-10 13:36:04 -07005637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005638 /**
5639 * Flag indicating whether the touchable region should be adjusted by
5640 * the visible insets; if false the area outside the visible insets is
5641 * NOT touchable, so we must use those to adjust the frame during hit
5642 * tests.
5643 */
5644 int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
Romain Guy06882f82009-06-10 13:36:04 -07005645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005646 // Current transformation being applied.
5647 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
5648 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
5649 float mHScale=1, mVScale=1;
5650 float mLastHScale=1, mLastVScale=1;
5651 final Matrix mTmpMatrix = new Matrix();
5652
5653 // "Real" frame that the application sees.
5654 final Rect mFrame = new Rect();
5655 final Rect mLastFrame = new Rect();
5656
5657 final Rect mContainingFrame = new Rect();
5658 final Rect mDisplayFrame = new Rect();
5659 final Rect mContentFrame = new Rect();
5660 final Rect mVisibleFrame = new Rect();
5661
5662 float mShownAlpha = 1;
5663 float mAlpha = 1;
5664 float mLastAlpha = 1;
5665
5666 // Set to true if, when the window gets displayed, it should perform
5667 // an enter animation.
5668 boolean mEnterAnimationPending;
5669
5670 // Currently running animation.
5671 boolean mAnimating;
5672 boolean mLocalAnimating;
5673 Animation mAnimation;
5674 boolean mAnimationIsEntrance;
5675 boolean mHasTransformation;
5676 boolean mHasLocalTransformation;
5677 final Transformation mTransformation = new Transformation();
5678
5679 // This is set after IWindowSession.relayout() has been called at
5680 // least once for the window. It allows us to detect the situation
5681 // where we don't yet have a surface, but should have one soon, so
5682 // we can give the window focus before waiting for the relayout.
5683 boolean mRelayoutCalled;
Romain Guy06882f82009-06-10 13:36:04 -07005684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005685 // This is set after the Surface has been created but before the
5686 // window has been drawn. During this time the surface is hidden.
5687 boolean mDrawPending;
5688
5689 // This is set after the window has finished drawing for the first
5690 // time but before its surface is shown. The surface will be
5691 // displayed when the next layout is run.
5692 boolean mCommitDrawPending;
5693
5694 // This is set during the time after the window's drawing has been
5695 // committed, and before its surface is actually shown. It is used
5696 // to delay showing the surface until all windows in a token are ready
5697 // to be shown.
5698 boolean mReadyToShow;
Romain Guy06882f82009-06-10 13:36:04 -07005699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005700 // Set when the window has been shown in the screen the first time.
5701 boolean mHasDrawn;
5702
5703 // Currently running an exit animation?
5704 boolean mExiting;
5705
5706 // Currently on the mDestroySurface list?
5707 boolean mDestroying;
Romain Guy06882f82009-06-10 13:36:04 -07005708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005709 // Completely remove from window manager after exit animation?
5710 boolean mRemoveOnExit;
5711
5712 // Set when the orientation is changing and this window has not yet
5713 // been updated for the new orientation.
5714 boolean mOrientationChanging;
Romain Guy06882f82009-06-10 13:36:04 -07005715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005716 // Is this window now (or just being) removed?
5717 boolean mRemoved;
Romain Guy06882f82009-06-10 13:36:04 -07005718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005719 WindowState(Session s, IWindow c, WindowToken token,
5720 WindowState attachedWindow, WindowManager.LayoutParams a,
5721 int viewVisibility) {
5722 mSession = s;
5723 mClient = c;
5724 mToken = token;
5725 mAttrs.copyFrom(a);
5726 mViewVisibility = viewVisibility;
5727 DeathRecipient deathRecipient = new DeathRecipient();
5728 mAlpha = a.alpha;
5729 if (localLOGV) Log.v(
5730 TAG, "Window " + this + " client=" + c.asBinder()
5731 + " token=" + token + " (" + mAttrs.token + ")");
5732 try {
5733 c.asBinder().linkToDeath(deathRecipient, 0);
5734 } catch (RemoteException e) {
5735 mDeathRecipient = null;
5736 mAttachedWindow = null;
5737 mLayoutAttached = false;
5738 mIsImWindow = false;
5739 mBaseLayer = 0;
5740 mSubLayer = 0;
5741 return;
5742 }
5743 mDeathRecipient = deathRecipient;
Romain Guy06882f82009-06-10 13:36:04 -07005744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005745 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
5746 mAttrs.type <= LAST_SUB_WINDOW)) {
5747 // The multiplier here is to reserve space for multiple
5748 // windows in the same type layer.
5749 mBaseLayer = mPolicy.windowTypeToLayerLw(
5750 attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
5751 + TYPE_LAYER_OFFSET;
5752 mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
5753 mAttachedWindow = attachedWindow;
5754 mAttachedWindow.mChildWindows.add(this);
5755 mLayoutAttached = mAttrs.type !=
5756 WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
5757 mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
5758 || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5759 } else {
5760 // The multiplier here is to reserve space for multiple
5761 // windows in the same type layer.
5762 mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
5763 * TYPE_LAYER_MULTIPLIER
5764 + TYPE_LAYER_OFFSET;
5765 mSubLayer = 0;
5766 mAttachedWindow = null;
5767 mLayoutAttached = false;
5768 mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
5769 || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
5770 }
5771
5772 WindowState appWin = this;
5773 while (appWin.mAttachedWindow != null) {
5774 appWin = mAttachedWindow;
5775 }
5776 WindowToken appToken = appWin.mToken;
5777 while (appToken.appWindowToken == null) {
5778 WindowToken parent = mTokenMap.get(appToken.token);
5779 if (parent == null || appToken == parent) {
5780 break;
5781 }
5782 appToken = parent;
5783 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005784 mRootToken = appToken;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005785 mAppToken = appToken.appWindowToken;
5786
5787 mSurface = null;
5788 mRequestedWidth = 0;
5789 mRequestedHeight = 0;
5790 mLastRequestedWidth = 0;
5791 mLastRequestedHeight = 0;
5792 mReqXPos = 0;
5793 mReqYPos = 0;
5794 mLayer = 0;
5795 mAnimLayer = 0;
5796 mLastLayer = 0;
5797 }
5798
5799 void attach() {
5800 if (localLOGV) Log.v(
5801 TAG, "Attaching " + this + " token=" + mToken
5802 + ", list=" + mToken.windows);
5803 mSession.windowAddedLocked();
5804 }
5805
5806 public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
5807 mHaveFrame = true;
5808
5809 final int pw = pf.right-pf.left;
5810 final int ph = pf.bottom-pf.top;
5811
5812 int w,h;
5813 if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
5814 w = mAttrs.width < 0 ? pw : mAttrs.width;
5815 h = mAttrs.height< 0 ? ph : mAttrs.height;
5816 } else {
5817 w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
5818 h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
5819 }
Romain Guy06882f82009-06-10 13:36:04 -07005820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005821 final Rect container = mContainingFrame;
5822 container.set(pf);
5823
5824 final Rect display = mDisplayFrame;
5825 display.set(df);
5826
5827 final Rect content = mContentFrame;
5828 content.set(cf);
Romain Guy06882f82009-06-10 13:36:04 -07005829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005830 final Rect visible = mVisibleFrame;
5831 visible.set(vf);
Romain Guy06882f82009-06-10 13:36:04 -07005832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005833 final Rect frame = mFrame;
Romain Guy06882f82009-06-10 13:36:04 -07005834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005835 //System.out.println("In: w=" + w + " h=" + h + " container=" +
5836 // container + " x=" + mAttrs.x + " y=" + mAttrs.y);
5837
5838 Gravity.apply(mAttrs.gravity, w, h, container,
5839 (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
5840 (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
5841
5842 //System.out.println("Out: " + mFrame);
5843
5844 // Now make sure the window fits in the overall display.
5845 Gravity.applyDisplay(mAttrs.gravity, df, frame);
Romain Guy06882f82009-06-10 13:36:04 -07005846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005847 // Make sure the content and visible frames are inside of the
5848 // final window frame.
5849 if (content.left < frame.left) content.left = frame.left;
5850 if (content.top < frame.top) content.top = frame.top;
5851 if (content.right > frame.right) content.right = frame.right;
5852 if (content.bottom > frame.bottom) content.bottom = frame.bottom;
5853 if (visible.left < frame.left) visible.left = frame.left;
5854 if (visible.top < frame.top) visible.top = frame.top;
5855 if (visible.right > frame.right) visible.right = frame.right;
5856 if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005858 final Rect contentInsets = mContentInsets;
5859 contentInsets.left = content.left-frame.left;
5860 contentInsets.top = content.top-frame.top;
5861 contentInsets.right = frame.right-content.right;
5862 contentInsets.bottom = frame.bottom-content.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005864 final Rect visibleInsets = mVisibleInsets;
5865 visibleInsets.left = visible.left-frame.left;
5866 visibleInsets.top = visible.top-frame.top;
5867 visibleInsets.right = frame.right-visible.right;
5868 visibleInsets.bottom = frame.bottom-visible.bottom;
Romain Guy06882f82009-06-10 13:36:04 -07005869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005870 if (localLOGV) {
5871 //if ("com.google.android.youtube".equals(mAttrs.packageName)
5872 // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
5873 Log.v(TAG, "Resolving (mRequestedWidth="
5874 + mRequestedWidth + ", mRequestedheight="
5875 + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
5876 + "): frame=" + mFrame.toShortString()
5877 + " ci=" + contentInsets.toShortString()
5878 + " vi=" + visibleInsets.toShortString());
5879 //}
5880 }
5881 }
Romain Guy06882f82009-06-10 13:36:04 -07005882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005883 public Rect getFrameLw() {
5884 return mFrame;
5885 }
5886
5887 public Rect getShownFrameLw() {
5888 return mShownFrame;
5889 }
5890
5891 public Rect getDisplayFrameLw() {
5892 return mDisplayFrame;
5893 }
5894
5895 public Rect getContentFrameLw() {
5896 return mContentFrame;
5897 }
5898
5899 public Rect getVisibleFrameLw() {
5900 return mVisibleFrame;
5901 }
5902
5903 public boolean getGivenInsetsPendingLw() {
5904 return mGivenInsetsPending;
5905 }
5906
5907 public Rect getGivenContentInsetsLw() {
5908 return mGivenContentInsets;
5909 }
Romain Guy06882f82009-06-10 13:36:04 -07005910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005911 public Rect getGivenVisibleInsetsLw() {
5912 return mGivenVisibleInsets;
5913 }
Romain Guy06882f82009-06-10 13:36:04 -07005914
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005915 public WindowManager.LayoutParams getAttrs() {
5916 return mAttrs;
5917 }
5918
5919 public int getSurfaceLayer() {
5920 return mLayer;
5921 }
Romain Guy06882f82009-06-10 13:36:04 -07005922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005923 public IApplicationToken getAppToken() {
5924 return mAppToken != null ? mAppToken.appToken : null;
5925 }
5926
5927 public boolean hasAppShownWindows() {
5928 return mAppToken != null ? mAppToken.firstWindowDrawn : false;
5929 }
5930
5931 public boolean hasAppStartingIcon() {
5932 return mAppToken != null ? (mAppToken.startingData != null) : false;
5933 }
5934
5935 public WindowManagerPolicy.WindowState getAppStartingWindow() {
5936 return mAppToken != null ? mAppToken.startingWindow : null;
5937 }
5938
5939 public void setAnimation(Animation anim) {
5940 if (localLOGV) Log.v(
5941 TAG, "Setting animation in " + this + ": " + anim);
5942 mAnimating = false;
5943 mLocalAnimating = false;
5944 mAnimation = anim;
5945 mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
5946 mAnimation.scaleCurrentDuration(mWindowAnimationScale);
5947 }
5948
5949 public void clearAnimation() {
5950 if (mAnimation != null) {
5951 mAnimating = true;
5952 mLocalAnimating = false;
5953 mAnimation = null;
5954 }
5955 }
Romain Guy06882f82009-06-10 13:36:04 -07005956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005957 Surface createSurfaceLocked() {
5958 if (mSurface == null) {
5959 mDrawPending = true;
5960 mCommitDrawPending = false;
5961 mReadyToShow = false;
5962 if (mAppToken != null) {
5963 mAppToken.allDrawn = false;
5964 }
5965
5966 int flags = 0;
5967 if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
5968 flags |= Surface.HARDWARE;
5969 } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
5970 flags |= Surface.GPU;
5971 } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
5972 flags |= Surface.PUSH_BUFFERS;
5973 }
5974
5975 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
5976 flags |= Surface.SECURE;
5977 }
5978 if (DEBUG_VISIBILITY) Log.v(
5979 TAG, "Creating surface in session "
5980 + mSession.mSurfaceSession + " window " + this
5981 + " w=" + mFrame.width()
5982 + " h=" + mFrame.height() + " format="
5983 + mAttrs.format + " flags=" + flags);
5984
5985 int w = mFrame.width();
5986 int h = mFrame.height();
5987 if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
5988 // for a scaled surface, we always want the requested
5989 // size.
5990 w = mRequestedWidth;
5991 h = mRequestedHeight;
5992 }
5993
5994 try {
5995 mSurface = new Surface(
Romain Guy06882f82009-06-10 13:36:04 -07005996 mSession.mSurfaceSession, mSession.mPid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005997 0, w, h, mAttrs.format, flags);
5998 } catch (Surface.OutOfResourcesException e) {
5999 Log.w(TAG, "OutOfResourcesException creating surface");
6000 reclaimSomeSurfaceMemoryLocked(this, "create");
6001 return null;
6002 } catch (Exception e) {
6003 Log.e(TAG, "Exception creating surface", e);
6004 return null;
6005 }
Romain Guy06882f82009-06-10 13:36:04 -07006006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006007 if (localLOGV) Log.v(
6008 TAG, "Got surface: " + mSurface
6009 + ", set left=" + mFrame.left + " top=" + mFrame.top
6010 + ", animLayer=" + mAnimLayer);
6011 if (SHOW_TRANSACTIONS) {
6012 Log.i(TAG, ">>> OPEN TRANSACTION");
6013 Log.i(TAG, " SURFACE " + mSurface + ": CREATE ("
6014 + mAttrs.getTitle() + ") pos=(" +
6015 mFrame.left + "," + mFrame.top + ") (" +
6016 mFrame.width() + "x" + mFrame.height() + "), layer=" +
6017 mAnimLayer + " HIDE");
6018 }
6019 Surface.openTransaction();
6020 try {
6021 try {
6022 mSurface.setPosition(mFrame.left, mFrame.top);
6023 mSurface.setLayer(mAnimLayer);
6024 mSurface.hide();
6025 if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
6026 mSurface.setFlags(Surface.SURFACE_DITHER,
6027 Surface.SURFACE_DITHER);
6028 }
6029 } catch (RuntimeException e) {
6030 Log.w(TAG, "Error creating surface in " + w, e);
6031 reclaimSomeSurfaceMemoryLocked(this, "create-init");
6032 }
6033 mLastHidden = true;
6034 } finally {
6035 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
6036 Surface.closeTransaction();
6037 }
6038 if (localLOGV) Log.v(
6039 TAG, "Created surface " + this);
6040 }
6041 return mSurface;
6042 }
Romain Guy06882f82009-06-10 13:36:04 -07006043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006044 void destroySurfaceLocked() {
6045 // Window is no longer on-screen, so can no longer receive
6046 // key events... if we were waiting for it to finish
6047 // handling a key event, the wait is over!
6048 mKeyWaiter.finishedKey(mSession, mClient, true,
6049 KeyWaiter.RETURN_NOTHING);
6050 mKeyWaiter.releasePendingPointerLocked(mSession);
6051 mKeyWaiter.releasePendingTrackballLocked(mSession);
6052
6053 if (mAppToken != null && this == mAppToken.startingWindow) {
6054 mAppToken.startingDisplayed = false;
6055 }
Romain Guy06882f82009-06-10 13:36:04 -07006056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006057 if (localLOGV) Log.v(
6058 TAG, "Window " + this
6059 + " destroying surface " + mSurface + ", session " + mSession);
6060 if (mSurface != null) {
6061 try {
6062 if (SHOW_TRANSACTIONS) {
6063 RuntimeException ex = new RuntimeException();
6064 ex.fillInStackTrace();
6065 Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
6066 + mAttrs.getTitle() + ")", ex);
6067 }
6068 mSurface.clear();
6069 } catch (RuntimeException e) {
6070 Log.w(TAG, "Exception thrown when destroying Window " + this
6071 + " surface " + mSurface + " session " + mSession
6072 + ": " + e.toString());
6073 }
6074 mSurface = null;
6075 mDrawPending = false;
6076 mCommitDrawPending = false;
6077 mReadyToShow = false;
6078
6079 int i = mChildWindows.size();
6080 while (i > 0) {
6081 i--;
6082 WindowState c = (WindowState)mChildWindows.get(i);
6083 c.mAttachedHidden = true;
6084 }
6085 }
6086 }
6087
6088 boolean finishDrawingLocked() {
6089 if (mDrawPending) {
6090 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
6091 TAG, "finishDrawingLocked: " + mSurface);
6092 mCommitDrawPending = true;
6093 mDrawPending = false;
6094 return true;
6095 }
6096 return false;
6097 }
6098
6099 // This must be called while inside a transaction.
6100 void commitFinishDrawingLocked(long currentTime) {
6101 //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
6102 if (!mCommitDrawPending) {
6103 return;
6104 }
6105 mCommitDrawPending = false;
6106 mReadyToShow = true;
6107 final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING;
6108 final AppWindowToken atoken = mAppToken;
6109 if (atoken == null || atoken.allDrawn || starting) {
6110 performShowLocked();
6111 }
6112 }
6113
6114 // This must be called while inside a transaction.
6115 boolean performShowLocked() {
6116 if (DEBUG_VISIBILITY) {
6117 RuntimeException e = new RuntimeException();
6118 e.fillInStackTrace();
6119 Log.v(TAG, "performShow on " + this
6120 + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
6121 + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
6122 }
6123 if (mReadyToShow && isReadyForDisplay()) {
6124 if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i(
6125 TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)");
6126 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this
6127 + " during animation: policyVis=" + mPolicyVisibility
6128 + " attHidden=" + mAttachedHidden
6129 + " tok.hiddenRequested="
6130 + (mAppToken != null ? mAppToken.hiddenRequested : false)
6131 + " tok.idden="
6132 + (mAppToken != null ? mAppToken.hidden : false)
6133 + " animating=" + mAnimating
6134 + " tok animating="
6135 + (mAppToken != null ? mAppToken.animating : false));
6136 if (!showSurfaceRobustlyLocked(this)) {
6137 return false;
6138 }
6139 mLastAlpha = -1;
6140 mHasDrawn = true;
6141 mLastHidden = false;
6142 mReadyToShow = false;
6143 enableScreenIfNeededLocked();
6144
6145 applyEnterAnimationLocked(this);
Romain Guy06882f82009-06-10 13:36:04 -07006146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006147 int i = mChildWindows.size();
6148 while (i > 0) {
6149 i--;
6150 WindowState c = (WindowState)mChildWindows.get(i);
6151 if (c.mSurface != null && c.mAttachedHidden) {
6152 c.mAttachedHidden = false;
6153 c.performShowLocked();
6154 }
6155 }
Romain Guy06882f82009-06-10 13:36:04 -07006156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006157 if (mAttrs.type != TYPE_APPLICATION_STARTING
6158 && mAppToken != null) {
6159 mAppToken.firstWindowDrawn = true;
6160 if (mAnimation == null && mAppToken.startingData != null) {
6161 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6162 + mToken
6163 + ": first real window is shown, no animation");
6164 mFinishedStarting.add(mAppToken);
6165 mH.sendEmptyMessage(H.FINISHED_STARTING);
6166 }
6167 mAppToken.updateReportedVisibilityLocked();
6168 }
6169 }
6170 return true;
6171 }
Romain Guy06882f82009-06-10 13:36:04 -07006172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006173 // This must be called while inside a transaction. Returns true if
6174 // there is more animation to run.
6175 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6176 if (!mDisplayFrozen) {
6177 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07006178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006179 if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
6180 mHasTransformation = true;
6181 mHasLocalTransformation = true;
6182 if (!mLocalAnimating) {
6183 if (DEBUG_ANIM) Log.v(
6184 TAG, "Starting animation in " + this +
6185 " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
6186 " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
6187 mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
6188 mAnimation.setStartTime(currentTime);
6189 mLocalAnimating = true;
6190 mAnimating = true;
6191 }
6192 mTransformation.clear();
6193 final boolean more = mAnimation.getTransformation(
6194 currentTime, mTransformation);
6195 if (DEBUG_ANIM) Log.v(
6196 TAG, "Stepped animation in " + this +
6197 ": more=" + more + ", xform=" + mTransformation);
6198 if (more) {
6199 // we're not done!
6200 return true;
6201 }
6202 if (DEBUG_ANIM) Log.v(
6203 TAG, "Finished animation in " + this +
6204 " @ " + currentTime);
6205 mAnimation = null;
6206 //WindowManagerService.this.dump();
6207 }
6208 mHasLocalTransformation = false;
6209 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
6210 && mAppToken.hasTransformation) {
6211 // When our app token is animating, we kind-of pretend like
6212 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
6213 // part of this check means that we will only do this if
6214 // our window is not currently exiting, or it is not
6215 // locally animating itself. The idea being that one that
6216 // is exiting and doing a local animation should be removed
6217 // once that animation is done.
6218 mAnimating = true;
6219 mHasTransformation = true;
6220 mTransformation.clear();
6221 return false;
6222 } else if (mHasTransformation) {
6223 // Little trick to get through the path below to act like
6224 // we have finished an animation.
6225 mAnimating = true;
6226 } else if (isAnimating()) {
6227 mAnimating = true;
6228 }
6229 } else if (mAnimation != null) {
6230 // If the display is frozen, and there is a pending animation,
6231 // clear it and make sure we run the cleanup code.
6232 mAnimating = true;
6233 mLocalAnimating = true;
6234 mAnimation = null;
6235 }
Romain Guy06882f82009-06-10 13:36:04 -07006236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006237 if (!mAnimating && !mLocalAnimating) {
6238 return false;
6239 }
6240
6241 if (DEBUG_ANIM) Log.v(
6242 TAG, "Animation done in " + this + ": exiting=" + mExiting
6243 + ", reportedVisible="
6244 + (mAppToken != null ? mAppToken.reportedVisible : false));
Romain Guy06882f82009-06-10 13:36:04 -07006245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006246 mAnimating = false;
6247 mLocalAnimating = false;
6248 mAnimation = null;
6249 mAnimLayer = mLayer;
6250 if (mIsImWindow) {
6251 mAnimLayer += mInputMethodAnimLayerAdjustment;
6252 }
6253 if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
6254 + " anim layer: " + mAnimLayer);
6255 mHasTransformation = false;
6256 mHasLocalTransformation = false;
6257 mPolicyVisibility = mPolicyVisibilityAfterAnim;
6258 mTransformation.clear();
6259 if (mHasDrawn
6260 && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
6261 && mAppToken != null
6262 && mAppToken.firstWindowDrawn
6263 && mAppToken.startingData != null) {
6264 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
6265 + mToken + ": first real window done animating");
6266 mFinishedStarting.add(mAppToken);
6267 mH.sendEmptyMessage(H.FINISHED_STARTING);
6268 }
Romain Guy06882f82009-06-10 13:36:04 -07006269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006270 finishExit();
6271
6272 if (mAppToken != null) {
6273 mAppToken.updateReportedVisibilityLocked();
6274 }
6275
6276 return false;
6277 }
6278
6279 void finishExit() {
6280 if (DEBUG_ANIM) Log.v(
6281 TAG, "finishExit in " + this
6282 + ": exiting=" + mExiting
6283 + " remove=" + mRemoveOnExit
6284 + " windowAnimating=" + isWindowAnimating());
Romain Guy06882f82009-06-10 13:36:04 -07006285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006286 final int N = mChildWindows.size();
6287 for (int i=0; i<N; i++) {
6288 ((WindowState)mChildWindows.get(i)).finishExit();
6289 }
Romain Guy06882f82009-06-10 13:36:04 -07006290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006291 if (!mExiting) {
6292 return;
6293 }
Romain Guy06882f82009-06-10 13:36:04 -07006294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006295 if (isWindowAnimating()) {
6296 return;
6297 }
6298
6299 if (localLOGV) Log.v(
6300 TAG, "Exit animation finished in " + this
6301 + ": remove=" + mRemoveOnExit);
6302 if (mSurface != null) {
6303 mDestroySurface.add(this);
6304 mDestroying = true;
6305 if (SHOW_TRANSACTIONS) Log.i(
6306 TAG, " SURFACE " + mSurface + ": HIDE (finishExit)");
6307 try {
6308 mSurface.hide();
6309 } catch (RuntimeException e) {
6310 Log.w(TAG, "Error hiding surface in " + this, e);
6311 }
6312 mLastHidden = true;
6313 mKeyWaiter.releasePendingPointerLocked(mSession);
6314 }
6315 mExiting = false;
6316 if (mRemoveOnExit) {
6317 mPendingRemove.add(this);
6318 mRemoveOnExit = false;
6319 }
6320 }
Romain Guy06882f82009-06-10 13:36:04 -07006321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006322 boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
6323 if (dsdx < .99999f || dsdx > 1.00001f) return false;
6324 if (dtdy < .99999f || dtdy > 1.00001f) return false;
6325 if (dtdx < -.000001f || dtdx > .000001f) return false;
6326 if (dsdy < -.000001f || dsdy > .000001f) return false;
6327 return true;
6328 }
Romain Guy06882f82009-06-10 13:36:04 -07006329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006330 void computeShownFrameLocked() {
6331 final boolean selfTransformation = mHasLocalTransformation;
6332 Transformation attachedTransformation =
6333 (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
6334 ? mAttachedWindow.mTransformation : null;
6335 Transformation appTransformation =
6336 (mAppToken != null && mAppToken.hasTransformation)
6337 ? mAppToken.transformation : null;
6338 if (selfTransformation || attachedTransformation != null
6339 || appTransformation != null) {
Romain Guy06882f82009-06-10 13:36:04 -07006340 // cache often used attributes locally
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006341 final Rect frame = mFrame;
6342 final float tmpFloats[] = mTmpFloats;
6343 final Matrix tmpMatrix = mTmpMatrix;
6344
6345 // Compute the desired transformation.
6346 tmpMatrix.setTranslate(frame.left, frame.top);
6347 if (selfTransformation) {
6348 tmpMatrix.preConcat(mTransformation.getMatrix());
6349 }
6350 if (attachedTransformation != null) {
6351 tmpMatrix.preConcat(attachedTransformation.getMatrix());
6352 }
6353 if (appTransformation != null) {
6354 tmpMatrix.preConcat(appTransformation.getMatrix());
6355 }
6356
6357 // "convert" it into SurfaceFlinger's format
6358 // (a 2x2 matrix + an offset)
6359 // Here we must not transform the position of the surface
6360 // since it is already included in the transformation.
6361 //Log.i(TAG, "Transform: " + matrix);
Romain Guy06882f82009-06-10 13:36:04 -07006362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006363 tmpMatrix.getValues(tmpFloats);
6364 mDsDx = tmpFloats[Matrix.MSCALE_X];
6365 mDtDx = tmpFloats[Matrix.MSKEW_X];
6366 mDsDy = tmpFloats[Matrix.MSKEW_Y];
6367 mDtDy = tmpFloats[Matrix.MSCALE_Y];
6368 int x = (int)tmpFloats[Matrix.MTRANS_X];
6369 int y = (int)tmpFloats[Matrix.MTRANS_Y];
6370 int w = frame.width();
6371 int h = frame.height();
6372 mShownFrame.set(x, y, x+w, y+h);
6373
6374 // Now set the alpha... but because our current hardware
6375 // can't do alpha transformation on a non-opaque surface,
6376 // turn it off if we are running an animation that is also
6377 // transforming since it is more important to have that
6378 // animation be smooth.
6379 mShownAlpha = mAlpha;
6380 if (!mLimitedAlphaCompositing
6381 || (!PixelFormat.formatHasAlpha(mAttrs.format)
6382 || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
6383 && x == frame.left && y == frame.top))) {
6384 //Log.i(TAG, "Applying alpha transform");
6385 if (selfTransformation) {
6386 mShownAlpha *= mTransformation.getAlpha();
6387 }
6388 if (attachedTransformation != null) {
6389 mShownAlpha *= attachedTransformation.getAlpha();
6390 }
6391 if (appTransformation != null) {
6392 mShownAlpha *= appTransformation.getAlpha();
6393 }
6394 } else {
6395 //Log.i(TAG, "Not applying alpha transform");
6396 }
Romain Guy06882f82009-06-10 13:36:04 -07006397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006398 if (localLOGV) Log.v(
6399 TAG, "Continuing animation in " + this +
6400 ": " + mShownFrame +
6401 ", alpha=" + mTransformation.getAlpha());
6402 return;
6403 }
Romain Guy06882f82009-06-10 13:36:04 -07006404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006405 mShownFrame.set(mFrame);
6406 mShownAlpha = mAlpha;
6407 mDsDx = 1;
6408 mDtDx = 0;
6409 mDsDy = 0;
6410 mDtDy = 1;
6411 }
Romain Guy06882f82009-06-10 13:36:04 -07006412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006413 /**
6414 * Is this window visible? It is not visible if there is no
6415 * surface, or we are in the process of running an exit animation
6416 * that will remove the surface, or its app token has been hidden.
6417 */
6418 public boolean isVisibleLw() {
6419 final AppWindowToken atoken = mAppToken;
6420 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6421 && (atoken == null || !atoken.hiddenRequested)
6422 && !mExiting && !mDestroying;
6423 }
6424
6425 /**
6426 * Is this window visible, ignoring its app token? It is not visible
6427 * if there is no surface, or we are in the process of running an exit animation
6428 * that will remove the surface.
6429 */
6430 public boolean isWinVisibleLw() {
6431 final AppWindowToken atoken = mAppToken;
6432 return mSurface != null && mPolicyVisibility && !mAttachedHidden
6433 && (atoken == null || !atoken.hiddenRequested || atoken.animating)
6434 && !mExiting && !mDestroying;
6435 }
6436
6437 /**
6438 * The same as isVisible(), but follows the current hidden state of
6439 * the associated app token, not the pending requested hidden state.
6440 */
6441 boolean isVisibleNow() {
6442 return mSurface != null && mPolicyVisibility && !mAttachedHidden
The Android Open Source Project10592532009-03-18 17:39:46 -07006443 && !mRootToken.hidden && !mExiting && !mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006444 }
6445
6446 /**
6447 * Same as isVisible(), but we also count it as visible between the
6448 * call to IWindowSession.add() and the first relayout().
6449 */
6450 boolean isVisibleOrAdding() {
6451 final AppWindowToken atoken = mAppToken;
6452 return (mSurface != null
6453 || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
6454 && mPolicyVisibility && !mAttachedHidden
6455 && (atoken == null || !atoken.hiddenRequested)
6456 && !mExiting && !mDestroying;
6457 }
6458
6459 /**
6460 * Is this window currently on-screen? It is on-screen either if it
6461 * is visible or it is currently running an animation before no longer
6462 * being visible.
6463 */
6464 boolean isOnScreen() {
6465 final AppWindowToken atoken = mAppToken;
6466 if (atoken != null) {
6467 return mSurface != null && mPolicyVisibility && !mDestroying
6468 && ((!mAttachedHidden && !atoken.hiddenRequested)
6469 || mAnimating || atoken.animating);
6470 } else {
6471 return mSurface != null && mPolicyVisibility && !mDestroying
6472 && (!mAttachedHidden || mAnimating);
6473 }
6474 }
Romain Guy06882f82009-06-10 13:36:04 -07006475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006476 /**
6477 * Like isOnScreen(), but we don't return true if the window is part
6478 * of a transition that has not yet been started.
6479 */
6480 boolean isReadyForDisplay() {
6481 final AppWindowToken atoken = mAppToken;
6482 final boolean animating = atoken != null ? atoken.animating : false;
6483 return mSurface != null && mPolicyVisibility && !mDestroying
The Android Open Source Project10592532009-03-18 17:39:46 -07006484 && ((!mAttachedHidden && !mRootToken.hidden)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006485 || mAnimating || animating);
6486 }
6487
6488 /** Is the window or its container currently animating? */
6489 boolean isAnimating() {
6490 final WindowState attached = mAttachedWindow;
6491 final AppWindowToken atoken = mAppToken;
6492 return mAnimation != null
6493 || (attached != null && attached.mAnimation != null)
Romain Guy06882f82009-06-10 13:36:04 -07006494 || (atoken != null &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495 (atoken.animation != null
6496 || atoken.inPendingTransaction));
6497 }
6498
6499 /** Is this window currently animating? */
6500 boolean isWindowAnimating() {
6501 return mAnimation != null;
6502 }
6503
6504 /**
6505 * Like isOnScreen, but returns false if the surface hasn't yet
6506 * been drawn.
6507 */
6508 public boolean isDisplayedLw() {
6509 final AppWindowToken atoken = mAppToken;
6510 return mSurface != null && mPolicyVisibility && !mDestroying
6511 && !mDrawPending && !mCommitDrawPending
6512 && ((!mAttachedHidden &&
6513 (atoken == null || !atoken.hiddenRequested))
6514 || mAnimating);
6515 }
6516
6517 public boolean fillsScreenLw(int screenWidth, int screenHeight,
6518 boolean shownFrame, boolean onlyOpaque) {
6519 if (mSurface == null) {
6520 return false;
6521 }
6522 if (mAppToken != null && !mAppToken.appFullscreen) {
6523 return false;
6524 }
6525 if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
6526 return false;
6527 }
6528 final Rect frame = shownFrame ? mShownFrame : mFrame;
6529 if (frame.left <= 0 && frame.top <= 0
6530 && frame.right >= screenWidth
6531 && frame.bottom >= screenHeight) {
6532 return true;
6533 }
6534 return false;
6535 }
Romain Guy06882f82009-06-10 13:36:04 -07006536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006537 boolean isFullscreenOpaque(int screenWidth, int screenHeight) {
6538 if (mAttrs.format != PixelFormat.OPAQUE || mSurface == null
6539 || mAnimation != null || mDrawPending || mCommitDrawPending) {
6540 return false;
6541 }
6542 if (mFrame.left <= 0 && mFrame.top <= 0 &&
6543 mFrame.right >= screenWidth && mFrame.bottom >= screenHeight) {
6544 return true;
6545 }
6546 return false;
6547 }
6548
6549 void removeLocked() {
6550 if (mAttachedWindow != null) {
6551 mAttachedWindow.mChildWindows.remove(this);
6552 }
6553 destroySurfaceLocked();
6554 mSession.windowRemovedLocked();
6555 try {
6556 mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
6557 } catch (RuntimeException e) {
6558 // Ignore if it has already been removed (usually because
6559 // we are doing this as part of processing a death note.)
6560 }
6561 }
6562
6563 private class DeathRecipient implements IBinder.DeathRecipient {
6564 public void binderDied() {
6565 try {
6566 synchronized(mWindowMap) {
6567 WindowState win = windowForClientLocked(mSession, mClient);
6568 Log.i(TAG, "WIN DEATH: " + win);
6569 if (win != null) {
6570 removeWindowLocked(mSession, win);
6571 }
6572 }
6573 } catch (IllegalArgumentException ex) {
6574 // This will happen if the window has already been
6575 // removed.
6576 }
6577 }
6578 }
6579
6580 /** Returns true if this window desires key events. */
6581 public final boolean canReceiveKeys() {
6582 return isVisibleOrAdding()
6583 && (mViewVisibility == View.VISIBLE)
6584 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
6585 }
6586
6587 public boolean hasDrawnLw() {
6588 return mHasDrawn;
6589 }
6590
6591 public boolean showLw(boolean doAnimation) {
6592 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
6593 mPolicyVisibility = true;
6594 mPolicyVisibilityAfterAnim = true;
6595 if (doAnimation) {
6596 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
6597 }
6598 requestAnimationLocked(0);
6599 return true;
6600 }
6601 return false;
6602 }
6603
6604 public boolean hideLw(boolean doAnimation) {
6605 boolean current = doAnimation ? mPolicyVisibilityAfterAnim
6606 : mPolicyVisibility;
6607 if (current) {
6608 if (doAnimation) {
6609 applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
6610 if (mAnimation == null) {
6611 doAnimation = false;
6612 }
6613 }
6614 if (doAnimation) {
6615 mPolicyVisibilityAfterAnim = false;
6616 } else {
6617 mPolicyVisibilityAfterAnim = false;
6618 mPolicyVisibility = false;
6619 }
6620 requestAnimationLocked(0);
6621 return true;
6622 }
6623 return false;
6624 }
6625
6626 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006627 StringBuilder sb = new StringBuilder(64);
Romain Guy06882f82009-06-10 13:36:04 -07006628
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006629 pw.print(prefix); pw.print("mSession="); pw.print(mSession);
6630 pw.print(" mClient="); pw.println(mClient.asBinder());
6631 pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
6632 if (mAttachedWindow != null || mLayoutAttached) {
6633 pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
6634 pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
6635 }
6636 if (mIsImWindow) {
6637 pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
6638 }
6639 pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
6640 pw.print(" mSubLayer="); pw.print(mSubLayer);
6641 pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
6642 pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
6643 : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)));
6644 pw.print("="); pw.print(mAnimLayer);
6645 pw.print(" mLastLayer="); pw.println(mLastLayer);
6646 if (mSurface != null) {
6647 pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
6648 }
6649 pw.print(prefix); pw.print("mToken="); pw.println(mToken);
6650 pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
6651 if (mAppToken != null) {
6652 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
6653 }
6654 if (mTargetAppToken != null) {
6655 pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken);
6656 }
6657 pw.print(prefix); pw.print("mViewVisibility=0x");
6658 pw.print(Integer.toHexString(mViewVisibility));
6659 pw.print(" mLastHidden="); pw.print(mLastHidden);
6660 pw.print(" mHaveFrame="); pw.println(mHaveFrame);
6661 if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
6662 pw.print(prefix); pw.print("mPolicyVisibility=");
6663 pw.print(mPolicyVisibility);
6664 pw.print(" mPolicyVisibilityAfterAnim=");
6665 pw.print(mPolicyVisibilityAfterAnim);
6666 pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
6667 }
6668 pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
6669 pw.print(" h="); pw.print(mRequestedHeight);
6670 pw.print(" x="); pw.print(mReqXPos);
6671 pw.print(" y="); pw.println(mReqYPos);
6672 pw.print(prefix); pw.print("mGivenContentInsets=");
6673 mGivenContentInsets.printShortString(pw);
6674 pw.print(" mGivenVisibleInsets=");
6675 mGivenVisibleInsets.printShortString(pw);
6676 pw.println();
6677 if (mTouchableInsets != 0 || mGivenInsetsPending) {
6678 pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
6679 pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
6680 }
6681 pw.print(prefix); pw.print("mShownFrame=");
6682 mShownFrame.printShortString(pw);
6683 pw.print(" last="); mLastShownFrame.printShortString(pw);
6684 pw.println();
6685 pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
6686 pw.print(" last="); mLastFrame.printShortString(pw);
6687 pw.println();
6688 pw.print(prefix); pw.print("mContainingFrame=");
6689 mContainingFrame.printShortString(pw);
6690 pw.print(" mDisplayFrame=");
6691 mDisplayFrame.printShortString(pw);
6692 pw.println();
6693 pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw);
6694 pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw);
6695 pw.println();
6696 pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw);
6697 pw.print(" last="); mLastContentInsets.printShortString(pw);
6698 pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw);
6699 pw.print(" last="); mLastVisibleInsets.printShortString(pw);
6700 pw.println();
6701 if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
6702 pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
6703 pw.print(" mAlpha="); pw.print(mAlpha);
6704 pw.print(" mLastAlpha="); pw.println(mLastAlpha);
6705 }
6706 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
6707 || mAnimation != null) {
6708 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
6709 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
6710 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
6711 pw.print(" mAnimation="); pw.println(mAnimation);
6712 }
6713 if (mHasTransformation || mHasLocalTransformation) {
6714 pw.print(prefix); pw.print("XForm: has=");
6715 pw.print(mHasTransformation);
6716 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
6717 pw.print(" "); mTransformation.printShortString(pw);
6718 pw.println();
6719 }
6720 pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending);
6721 pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending);
6722 pw.print(" mReadyToShow="); pw.print(mReadyToShow);
6723 pw.print(" mHasDrawn="); pw.println(mHasDrawn);
6724 if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
6725 pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
6726 pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
6727 pw.print(" mDestroying="); pw.print(mDestroying);
6728 pw.print(" mRemoved="); pw.println(mRemoved);
6729 }
6730 if (mOrientationChanging || mAppFreezing) {
6731 pw.print(prefix); pw.print("mOrientationChanging=");
6732 pw.print(mOrientationChanging);
6733 pw.print(" mAppFreezing="); pw.println(mAppFreezing);
6734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006735 }
6736
6737 @Override
6738 public String toString() {
6739 return "Window{"
6740 + Integer.toHexString(System.identityHashCode(this))
6741 + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
6742 }
6743 }
Romain Guy06882f82009-06-10 13:36:04 -07006744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006745 // -------------------------------------------------------------
6746 // Window Token State
6747 // -------------------------------------------------------------
6748
6749 class WindowToken {
6750 // The actual token.
6751 final IBinder token;
6752
6753 // The type of window this token is for, as per WindowManager.LayoutParams.
6754 final int windowType;
Romain Guy06882f82009-06-10 13:36:04 -07006755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006756 // Set if this token was explicitly added by a client, so should
6757 // not be removed when all windows are removed.
6758 final boolean explicit;
Romain Guy06882f82009-06-10 13:36:04 -07006759
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006760 // For printing.
6761 String stringName;
Romain Guy06882f82009-06-10 13:36:04 -07006762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006763 // If this is an AppWindowToken, this is non-null.
6764 AppWindowToken appWindowToken;
Romain Guy06882f82009-06-10 13:36:04 -07006765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006766 // All of the windows associated with this token.
6767 final ArrayList<WindowState> windows = new ArrayList<WindowState>();
6768
6769 // Is key dispatching paused for this token?
6770 boolean paused = false;
6771
6772 // Should this token's windows be hidden?
6773 boolean hidden;
6774
6775 // Temporary for finding which tokens no longer have visible windows.
6776 boolean hasVisible;
6777
6778 WindowToken(IBinder _token, int type, boolean _explicit) {
6779 token = _token;
6780 windowType = type;
6781 explicit = _explicit;
6782 }
6783
6784 void dump(PrintWriter pw, String prefix) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006785 pw.print(prefix); pw.print("token="); pw.println(token);
6786 pw.print(prefix); pw.print("windows="); pw.println(windows);
6787 pw.print(prefix); pw.print("windowType="); pw.print(windowType);
6788 pw.print(" hidden="); pw.print(hidden);
6789 pw.print(" hasVisible="); pw.println(hasVisible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006790 }
6791
6792 @Override
6793 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07006794 if (stringName == null) {
6795 StringBuilder sb = new StringBuilder();
6796 sb.append("WindowToken{");
6797 sb.append(Integer.toHexString(System.identityHashCode(this)));
6798 sb.append(" token="); sb.append(token); sb.append('}');
6799 stringName = sb.toString();
6800 }
6801 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006802 }
6803 };
6804
6805 class AppWindowToken extends WindowToken {
6806 // Non-null only for application tokens.
6807 final IApplicationToken appToken;
6808
6809 // All of the windows and child windows that are included in this
6810 // application token. Note this list is NOT sorted!
6811 final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
6812
6813 int groupId = -1;
6814 boolean appFullscreen;
6815 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Romain Guy06882f82009-06-10 13:36:04 -07006816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006817 // These are used for determining when all windows associated with
6818 // an activity have been drawn, so they can be made visible together
6819 // at the same time.
6820 int lastTransactionSequence = mTransactionSequence-1;
6821 int numInterestingWindows;
6822 int numDrawnWindows;
6823 boolean inPendingTransaction;
6824 boolean allDrawn;
Romain Guy06882f82009-06-10 13:36:04 -07006825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006826 // Is this token going to be hidden in a little while? If so, it
6827 // won't be taken into account for setting the screen orientation.
6828 boolean willBeHidden;
Romain Guy06882f82009-06-10 13:36:04 -07006829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006830 // Is this window's surface needed? This is almost like hidden, except
6831 // it will sometimes be true a little earlier: when the token has
6832 // been shown, but is still waiting for its app transition to execute
6833 // before making its windows shown.
6834 boolean hiddenRequested;
Romain Guy06882f82009-06-10 13:36:04 -07006835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006836 // Have we told the window clients to hide themselves?
6837 boolean clientHidden;
Romain Guy06882f82009-06-10 13:36:04 -07006838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006839 // Last visibility state we reported to the app token.
6840 boolean reportedVisible;
6841
6842 // Set to true when the token has been removed from the window mgr.
6843 boolean removed;
6844
6845 // Have we been asked to have this token keep the screen frozen?
6846 boolean freezingScreen;
Romain Guy06882f82009-06-10 13:36:04 -07006847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006848 boolean animating;
6849 Animation animation;
6850 boolean hasTransformation;
6851 final Transformation transformation = new Transformation();
Romain Guy06882f82009-06-10 13:36:04 -07006852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006853 // Offset to the window of all layers in the token, for use by
6854 // AppWindowToken animations.
6855 int animLayerAdjustment;
Romain Guy06882f82009-06-10 13:36:04 -07006856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006857 // Information about an application starting window if displayed.
6858 StartingData startingData;
6859 WindowState startingWindow;
6860 View startingView;
6861 boolean startingDisplayed;
6862 boolean startingMoved;
6863 boolean firstWindowDrawn;
6864
6865 AppWindowToken(IApplicationToken _token) {
6866 super(_token.asBinder(),
6867 WindowManager.LayoutParams.TYPE_APPLICATION, true);
6868 appWindowToken = this;
6869 appToken = _token;
6870 }
Romain Guy06882f82009-06-10 13:36:04 -07006871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006872 public void setAnimation(Animation anim) {
6873 if (localLOGV) Log.v(
6874 TAG, "Setting animation in " + this + ": " + anim);
6875 animation = anim;
6876 animating = false;
6877 anim.restrictDuration(MAX_ANIMATION_DURATION);
6878 anim.scaleCurrentDuration(mTransitionAnimationScale);
6879 int zorder = anim.getZAdjustment();
6880 int adj = 0;
6881 if (zorder == Animation.ZORDER_TOP) {
6882 adj = TYPE_LAYER_OFFSET;
6883 } else if (zorder == Animation.ZORDER_BOTTOM) {
6884 adj = -TYPE_LAYER_OFFSET;
6885 }
Romain Guy06882f82009-06-10 13:36:04 -07006886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006887 if (animLayerAdjustment != adj) {
6888 animLayerAdjustment = adj;
6889 updateLayers();
6890 }
6891 }
Romain Guy06882f82009-06-10 13:36:04 -07006892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006893 public void setDummyAnimation() {
6894 if (animation == null) {
6895 if (localLOGV) Log.v(
6896 TAG, "Setting dummy animation in " + this);
6897 animation = sDummyAnimation;
6898 }
6899 }
6900
6901 public void clearAnimation() {
6902 if (animation != null) {
6903 animation = null;
6904 animating = true;
6905 }
6906 }
Romain Guy06882f82009-06-10 13:36:04 -07006907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006908 void updateLayers() {
6909 final int N = allAppWindows.size();
6910 final int adj = animLayerAdjustment;
6911 for (int i=0; i<N; i++) {
6912 WindowState w = allAppWindows.get(i);
6913 w.mAnimLayer = w.mLayer + adj;
6914 if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
6915 + w.mAnimLayer);
6916 if (w == mInputMethodTarget) {
6917 setInputMethodAnimLayerAdjustment(adj);
6918 }
6919 }
6920 }
Romain Guy06882f82009-06-10 13:36:04 -07006921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006922 void sendAppVisibilityToClients() {
6923 final int N = allAppWindows.size();
6924 for (int i=0; i<N; i++) {
6925 WindowState win = allAppWindows.get(i);
6926 if (win == startingWindow && clientHidden) {
6927 // Don't hide the starting window.
6928 continue;
6929 }
6930 try {
6931 if (DEBUG_VISIBILITY) Log.v(TAG,
6932 "Setting visibility of " + win + ": " + (!clientHidden));
6933 win.mClient.dispatchAppVisibility(!clientHidden);
6934 } catch (RemoteException e) {
6935 }
6936 }
6937 }
Romain Guy06882f82009-06-10 13:36:04 -07006938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006939 void showAllWindowsLocked() {
6940 final int NW = allAppWindows.size();
6941 for (int i=0; i<NW; i++) {
6942 WindowState w = allAppWindows.get(i);
6943 if (DEBUG_VISIBILITY) Log.v(TAG,
6944 "performing show on: " + w);
6945 w.performShowLocked();
6946 }
6947 }
Romain Guy06882f82009-06-10 13:36:04 -07006948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006949 // This must be called while inside a transaction.
6950 boolean stepAnimationLocked(long currentTime, int dw, int dh) {
6951 if (!mDisplayFrozen) {
6952 // We will run animations as long as the display isn't frozen.
Romain Guy06882f82009-06-10 13:36:04 -07006953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006954 if (animation == sDummyAnimation) {
6955 // This guy is going to animate, but not yet. For now count
6956 // it is not animating for purposes of scheduling transactions;
6957 // when it is really time to animate, this will be set to
6958 // a real animation and the next call will execute normally.
6959 return false;
6960 }
Romain Guy06882f82009-06-10 13:36:04 -07006961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006962 if ((allDrawn || animating || startingDisplayed) && animation != null) {
6963 if (!animating) {
6964 if (DEBUG_ANIM) Log.v(
6965 TAG, "Starting animation in " + this +
6966 " @ " + currentTime + ": dw=" + dw + " dh=" + dh
6967 + " scale=" + mTransitionAnimationScale
6968 + " allDrawn=" + allDrawn + " animating=" + animating);
6969 animation.initialize(dw, dh, dw, dh);
6970 animation.setStartTime(currentTime);
6971 animating = true;
6972 }
6973 transformation.clear();
6974 final boolean more = animation.getTransformation(
6975 currentTime, transformation);
6976 if (DEBUG_ANIM) Log.v(
6977 TAG, "Stepped animation in " + this +
6978 ": more=" + more + ", xform=" + transformation);
6979 if (more) {
6980 // we're done!
6981 hasTransformation = true;
6982 return true;
6983 }
6984 if (DEBUG_ANIM) Log.v(
6985 TAG, "Finished animation in " + this +
6986 " @ " + currentTime);
6987 animation = null;
6988 }
6989 } else if (animation != null) {
6990 // If the display is frozen, and there is a pending animation,
6991 // clear it and make sure we run the cleanup code.
6992 animating = true;
6993 animation = null;
6994 }
6995
6996 hasTransformation = false;
Romain Guy06882f82009-06-10 13:36:04 -07006997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006998 if (!animating) {
6999 return false;
7000 }
7001
7002 clearAnimation();
7003 animating = false;
7004 if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
7005 moveInputMethodWindowsIfNeededLocked(true);
7006 }
Romain Guy06882f82009-06-10 13:36:04 -07007007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007008 if (DEBUG_ANIM) Log.v(
7009 TAG, "Animation done in " + this
7010 + ": reportedVisible=" + reportedVisible);
7011
7012 transformation.clear();
7013 if (animLayerAdjustment != 0) {
7014 animLayerAdjustment = 0;
7015 updateLayers();
7016 }
Romain Guy06882f82009-06-10 13:36:04 -07007017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007018 final int N = windows.size();
7019 for (int i=0; i<N; i++) {
7020 ((WindowState)windows.get(i)).finishExit();
7021 }
7022 updateReportedVisibilityLocked();
Romain Guy06882f82009-06-10 13:36:04 -07007023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007024 return false;
7025 }
7026
7027 void updateReportedVisibilityLocked() {
7028 if (appToken == null) {
7029 return;
7030 }
Romain Guy06882f82009-06-10 13:36:04 -07007031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007032 int numInteresting = 0;
7033 int numVisible = 0;
7034 boolean nowGone = true;
Romain Guy06882f82009-06-10 13:36:04 -07007035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007036 if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
7037 final int N = allAppWindows.size();
7038 for (int i=0; i<N; i++) {
7039 WindowState win = allAppWindows.get(i);
7040 if (win == startingWindow || win.mAppFreezing) {
7041 continue;
7042 }
7043 if (DEBUG_VISIBILITY) {
7044 Log.v(TAG, "Win " + win + ": isDisplayed="
7045 + win.isDisplayedLw()
7046 + ", isAnimating=" + win.isAnimating());
7047 if (!win.isDisplayedLw()) {
7048 Log.v(TAG, "Not displayed: s=" + win.mSurface
7049 + " pv=" + win.mPolicyVisibility
7050 + " dp=" + win.mDrawPending
7051 + " cdp=" + win.mCommitDrawPending
7052 + " ah=" + win.mAttachedHidden
7053 + " th="
7054 + (win.mAppToken != null
7055 ? win.mAppToken.hiddenRequested : false)
7056 + " a=" + win.mAnimating);
7057 }
7058 }
7059 numInteresting++;
7060 if (win.isDisplayedLw()) {
7061 if (!win.isAnimating()) {
7062 numVisible++;
7063 }
7064 nowGone = false;
7065 } else if (win.isAnimating()) {
7066 nowGone = false;
7067 }
7068 }
Romain Guy06882f82009-06-10 13:36:04 -07007069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007070 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
7071 if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
7072 + numInteresting + " visible=" + numVisible);
7073 if (nowVisible != reportedVisible) {
7074 if (DEBUG_VISIBILITY) Log.v(
7075 TAG, "Visibility changed in " + this
7076 + ": vis=" + nowVisible);
7077 reportedVisible = nowVisible;
7078 Message m = mH.obtainMessage(
7079 H.REPORT_APPLICATION_TOKEN_WINDOWS,
7080 nowVisible ? 1 : 0,
7081 nowGone ? 1 : 0,
7082 this);
7083 mH.sendMessage(m);
7084 }
7085 }
Romain Guy06882f82009-06-10 13:36:04 -07007086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007087 void dump(PrintWriter pw, String prefix) {
7088 super.dump(pw, prefix);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007089 if (appToken != null) {
7090 pw.print(prefix); pw.println("app=true");
7091 }
7092 if (allAppWindows.size() > 0) {
7093 pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
7094 }
7095 pw.print(prefix); pw.print("groupId="); pw.print(groupId);
7096 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
7097 pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
7098 pw.print(" clientHidden="); pw.print(clientHidden);
7099 pw.print(" willBeHidden="); pw.print(willBeHidden);
7100 pw.print(" reportedVisible="); pw.println(reportedVisible);
7101 if (paused || freezingScreen) {
7102 pw.print(prefix); pw.print("paused="); pw.print(paused);
7103 pw.print(" freezingScreen="); pw.println(freezingScreen);
7104 }
7105 if (numInterestingWindows != 0 || numDrawnWindows != 0
7106 || inPendingTransaction || allDrawn) {
7107 pw.print(prefix); pw.print("numInterestingWindows=");
7108 pw.print(numInterestingWindows);
7109 pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
7110 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
7111 pw.print(" allDrawn="); pw.println(allDrawn);
7112 }
7113 if (animating || animation != null) {
7114 pw.print(prefix); pw.print("animating="); pw.print(animating);
7115 pw.print(" animation="); pw.println(animation);
7116 }
7117 if (animLayerAdjustment != 0) {
7118 pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
7119 }
7120 if (hasTransformation) {
7121 pw.print(prefix); pw.print("hasTransformation="); pw.print(hasTransformation);
7122 pw.print(" transformation="); transformation.printShortString(pw);
7123 pw.println();
7124 }
7125 if (startingData != null || removed || firstWindowDrawn) {
7126 pw.print(prefix); pw.print("startingData="); pw.print(startingData);
7127 pw.print(" removed="); pw.print(removed);
7128 pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
7129 }
7130 if (startingWindow != null || startingView != null
7131 || startingDisplayed || startingMoved) {
7132 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
7133 pw.print(" startingView="); pw.print(startingView);
7134 pw.print(" startingDisplayed="); pw.print(startingDisplayed);
7135 pw.print(" startingMoved"); pw.println(startingMoved);
7136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007137 }
7138
7139 @Override
7140 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07007141 if (stringName == null) {
7142 StringBuilder sb = new StringBuilder();
7143 sb.append("AppWindowToken{");
7144 sb.append(Integer.toHexString(System.identityHashCode(this)));
7145 sb.append(" token="); sb.append(token); sb.append('}');
7146 stringName = sb.toString();
7147 }
7148 return stringName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007149 }
7150 }
Romain Guy06882f82009-06-10 13:36:04 -07007151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007152 public static WindowManager.LayoutParams findAnimations(
7153 ArrayList<AppWindowToken> order,
7154 ArrayList<AppWindowToken> tokenList1,
7155 ArrayList<AppWindowToken> tokenList2) {
7156 // We need to figure out which animation to use...
7157 WindowManager.LayoutParams animParams = null;
7158 int animSrc = 0;
Romain Guy06882f82009-06-10 13:36:04 -07007159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007160 //Log.i(TAG, "Looking for animations...");
7161 for (int i=order.size()-1; i>=0; i--) {
7162 AppWindowToken wtoken = order.get(i);
7163 //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
7164 if (tokenList1.contains(wtoken) || tokenList2.contains(wtoken)) {
7165 int j = wtoken.windows.size();
7166 while (j > 0) {
7167 j--;
7168 WindowState win = wtoken.windows.get(j);
7169 //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
7170 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
7171 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
7172 //Log.i(TAG, "Found base or application window, done!");
7173 if (wtoken.appFullscreen) {
7174 return win.mAttrs;
7175 }
7176 if (animSrc < 2) {
7177 animParams = win.mAttrs;
7178 animSrc = 2;
7179 }
7180 } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
7181 //Log.i(TAG, "Found normal window, we may use this...");
7182 animParams = win.mAttrs;
7183 animSrc = 1;
7184 }
7185 }
7186 }
7187 }
Romain Guy06882f82009-06-10 13:36:04 -07007188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007189 return animParams;
7190 }
Romain Guy06882f82009-06-10 13:36:04 -07007191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007192 // -------------------------------------------------------------
7193 // DummyAnimation
7194 // -------------------------------------------------------------
7195
7196 // This is an animation that does nothing: it just immediately finishes
7197 // itself every time it is called. It is used as a stub animation in cases
7198 // where we want to synchronize multiple things that may be animating.
7199 static final class DummyAnimation extends Animation {
7200 public boolean getTransformation(long currentTime, Transformation outTransformation) {
7201 return false;
7202 }
7203 }
7204 static final Animation sDummyAnimation = new DummyAnimation();
Romain Guy06882f82009-06-10 13:36:04 -07007205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007206 // -------------------------------------------------------------
7207 // Async Handler
7208 // -------------------------------------------------------------
7209
7210 static final class StartingData {
7211 final String pkg;
7212 final int theme;
7213 final CharSequence nonLocalizedLabel;
7214 final int labelRes;
7215 final int icon;
Romain Guy06882f82009-06-10 13:36:04 -07007216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007217 StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
7218 int _labelRes, int _icon) {
7219 pkg = _pkg;
7220 theme = _theme;
7221 nonLocalizedLabel = _nonLocalizedLabel;
7222 labelRes = _labelRes;
7223 icon = _icon;
7224 }
7225 }
7226
7227 private final class H extends Handler {
7228 public static final int REPORT_FOCUS_CHANGE = 2;
7229 public static final int REPORT_LOSING_FOCUS = 3;
7230 public static final int ANIMATE = 4;
7231 public static final int ADD_STARTING = 5;
7232 public static final int REMOVE_STARTING = 6;
7233 public static final int FINISHED_STARTING = 7;
7234 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007235 public static final int WINDOW_FREEZE_TIMEOUT = 11;
7236 public static final int HOLD_SCREEN_CHANGED = 12;
7237 public static final int APP_TRANSITION_TIMEOUT = 13;
7238 public static final int PERSIST_ANIMATION_SCALE = 14;
7239 public static final int FORCE_GC = 15;
7240 public static final int ENABLE_SCREEN = 16;
7241 public static final int APP_FREEZE_TIMEOUT = 17;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007242 public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
Romain Guy06882f82009-06-10 13:36:04 -07007243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007244 private Session mLastReportedHold;
Romain Guy06882f82009-06-10 13:36:04 -07007245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007246 public H() {
7247 }
Romain Guy06882f82009-06-10 13:36:04 -07007248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007249 @Override
7250 public void handleMessage(Message msg) {
7251 switch (msg.what) {
7252 case REPORT_FOCUS_CHANGE: {
7253 WindowState lastFocus;
7254 WindowState newFocus;
Romain Guy06882f82009-06-10 13:36:04 -07007255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 synchronized(mWindowMap) {
7257 lastFocus = mLastFocus;
7258 newFocus = mCurrentFocus;
7259 if (lastFocus == newFocus) {
7260 // Focus is not changing, so nothing to do.
7261 return;
7262 }
7263 mLastFocus = newFocus;
7264 //Log.i(TAG, "Focus moving from " + lastFocus
7265 // + " to " + newFocus);
7266 if (newFocus != null && lastFocus != null
7267 && !newFocus.isDisplayedLw()) {
7268 //Log.i(TAG, "Delaying loss of focus...");
7269 mLosingFocus.add(lastFocus);
7270 lastFocus = null;
7271 }
7272 }
7273
7274 if (lastFocus != newFocus) {
7275 //System.out.println("Changing focus from " + lastFocus
7276 // + " to " + newFocus);
7277 if (newFocus != null) {
7278 try {
7279 //Log.i(TAG, "Gaining focus: " + newFocus);
7280 newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7281 } catch (RemoteException e) {
7282 // Ignore if process has died.
7283 }
7284 }
7285
7286 if (lastFocus != null) {
7287 try {
7288 //Log.i(TAG, "Losing focus: " + lastFocus);
7289 lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7290 } catch (RemoteException e) {
7291 // Ignore if process has died.
7292 }
7293 }
7294 }
7295 } break;
7296
7297 case REPORT_LOSING_FOCUS: {
7298 ArrayList<WindowState> losers;
Romain Guy06882f82009-06-10 13:36:04 -07007299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007300 synchronized(mWindowMap) {
7301 losers = mLosingFocus;
7302 mLosingFocus = new ArrayList<WindowState>();
7303 }
7304
7305 final int N = losers.size();
7306 for (int i=0; i<N; i++) {
7307 try {
7308 //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
7309 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7310 } catch (RemoteException e) {
7311 // Ignore if process has died.
7312 }
7313 }
7314 } break;
7315
7316 case ANIMATE: {
7317 synchronized(mWindowMap) {
7318 mAnimationPending = false;
7319 performLayoutAndPlaceSurfacesLocked();
7320 }
7321 } break;
7322
7323 case ADD_STARTING: {
7324 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7325 final StartingData sd = wtoken.startingData;
7326
7327 if (sd == null) {
7328 // Animation has been canceled... do nothing.
7329 return;
7330 }
Romain Guy06882f82009-06-10 13:36:04 -07007331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007332 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
7333 + wtoken + ": pkg=" + sd.pkg);
Romain Guy06882f82009-06-10 13:36:04 -07007334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007335 View view = null;
7336 try {
7337 view = mPolicy.addStartingWindow(
7338 wtoken.token, sd.pkg,
7339 sd.theme, sd.nonLocalizedLabel, sd.labelRes,
7340 sd.icon);
7341 } catch (Exception e) {
7342 Log.w(TAG, "Exception when adding starting window", e);
7343 }
7344
7345 if (view != null) {
7346 boolean abort = false;
7347
7348 synchronized(mWindowMap) {
7349 if (wtoken.removed || wtoken.startingData == null) {
7350 // If the window was successfully added, then
7351 // we need to remove it.
7352 if (wtoken.startingWindow != null) {
7353 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7354 "Aborted starting " + wtoken
7355 + ": removed=" + wtoken.removed
7356 + " startingData=" + wtoken.startingData);
7357 wtoken.startingWindow = null;
7358 wtoken.startingData = null;
7359 abort = true;
7360 }
7361 } else {
7362 wtoken.startingView = view;
7363 }
7364 if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
7365 "Added starting " + wtoken
7366 + ": startingWindow="
7367 + wtoken.startingWindow + " startingView="
7368 + wtoken.startingView);
7369 }
7370
7371 if (abort) {
7372 try {
7373 mPolicy.removeStartingWindow(wtoken.token, view);
7374 } catch (Exception e) {
7375 Log.w(TAG, "Exception when removing starting window", e);
7376 }
7377 }
7378 }
7379 } break;
7380
7381 case REMOVE_STARTING: {
7382 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7383 IBinder token = null;
7384 View view = null;
7385 synchronized (mWindowMap) {
7386 if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
7387 + wtoken + ": startingWindow="
7388 + wtoken.startingWindow + " startingView="
7389 + wtoken.startingView);
7390 if (wtoken.startingWindow != null) {
7391 view = wtoken.startingView;
7392 token = wtoken.token;
7393 wtoken.startingData = null;
7394 wtoken.startingView = null;
7395 wtoken.startingWindow = null;
7396 }
7397 }
7398 if (view != null) {
7399 try {
7400 mPolicy.removeStartingWindow(token, view);
7401 } catch (Exception e) {
7402 Log.w(TAG, "Exception when removing starting window", e);
7403 }
7404 }
7405 } break;
7406
7407 case FINISHED_STARTING: {
7408 IBinder token = null;
7409 View view = null;
7410 while (true) {
7411 synchronized (mWindowMap) {
7412 final int N = mFinishedStarting.size();
7413 if (N <= 0) {
7414 break;
7415 }
7416 AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7417
7418 if (DEBUG_STARTING_WINDOW) Log.v(TAG,
7419 "Finished starting " + wtoken
7420 + ": startingWindow=" + wtoken.startingWindow
7421 + " startingView=" + wtoken.startingView);
7422
7423 if (wtoken.startingWindow == null) {
7424 continue;
7425 }
7426
7427 view = wtoken.startingView;
7428 token = wtoken.token;
7429 wtoken.startingData = null;
7430 wtoken.startingView = null;
7431 wtoken.startingWindow = null;
7432 }
7433
7434 try {
7435 mPolicy.removeStartingWindow(token, view);
7436 } catch (Exception e) {
7437 Log.w(TAG, "Exception when removing starting window", e);
7438 }
7439 }
7440 } break;
7441
7442 case REPORT_APPLICATION_TOKEN_WINDOWS: {
7443 final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7444
7445 boolean nowVisible = msg.arg1 != 0;
7446 boolean nowGone = msg.arg2 != 0;
7447
7448 try {
7449 if (DEBUG_VISIBILITY) Log.v(
7450 TAG, "Reporting visible in " + wtoken
7451 + " visible=" + nowVisible
7452 + " gone=" + nowGone);
7453 if (nowVisible) {
7454 wtoken.appToken.windowsVisible();
7455 } else {
7456 wtoken.appToken.windowsGone();
7457 }
7458 } catch (RemoteException ex) {
7459 }
7460 } break;
Romain Guy06882f82009-06-10 13:36:04 -07007461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007462 case WINDOW_FREEZE_TIMEOUT: {
7463 synchronized (mWindowMap) {
7464 Log.w(TAG, "Window freeze timeout expired.");
7465 int i = mWindows.size();
7466 while (i > 0) {
7467 i--;
7468 WindowState w = (WindowState)mWindows.get(i);
7469 if (w.mOrientationChanging) {
7470 w.mOrientationChanging = false;
7471 Log.w(TAG, "Force clearing orientation change: " + w);
7472 }
7473 }
7474 performLayoutAndPlaceSurfacesLocked();
7475 }
7476 break;
7477 }
Romain Guy06882f82009-06-10 13:36:04 -07007478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007479 case HOLD_SCREEN_CHANGED: {
7480 Session oldHold;
7481 Session newHold;
7482 synchronized (mWindowMap) {
7483 oldHold = mLastReportedHold;
7484 newHold = (Session)msg.obj;
7485 mLastReportedHold = newHold;
7486 }
Romain Guy06882f82009-06-10 13:36:04 -07007487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007488 if (oldHold != newHold) {
7489 try {
7490 if (oldHold != null) {
7491 mBatteryStats.noteStopWakelock(oldHold.mUid,
7492 "window",
7493 BatteryStats.WAKE_TYPE_WINDOW);
7494 }
7495 if (newHold != null) {
7496 mBatteryStats.noteStartWakelock(newHold.mUid,
7497 "window",
7498 BatteryStats.WAKE_TYPE_WINDOW);
7499 }
7500 } catch (RemoteException e) {
7501 }
7502 }
7503 break;
7504 }
Romain Guy06882f82009-06-10 13:36:04 -07007505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007506 case APP_TRANSITION_TIMEOUT: {
7507 synchronized (mWindowMap) {
7508 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
7509 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7510 "*** APP TRANSITION TIMEOUT");
7511 mAppTransitionReady = true;
7512 mAppTransitionTimeout = true;
7513 performLayoutAndPlaceSurfacesLocked();
7514 }
7515 }
7516 break;
7517 }
Romain Guy06882f82009-06-10 13:36:04 -07007518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007519 case PERSIST_ANIMATION_SCALE: {
7520 Settings.System.putFloat(mContext.getContentResolver(),
7521 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7522 Settings.System.putFloat(mContext.getContentResolver(),
7523 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7524 break;
7525 }
Romain Guy06882f82009-06-10 13:36:04 -07007526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007527 case FORCE_GC: {
7528 synchronized(mWindowMap) {
7529 if (mAnimationPending) {
7530 // If we are animating, don't do the gc now but
7531 // delay a bit so we don't interrupt the animation.
7532 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7533 2000);
7534 return;
7535 }
7536 // If we are currently rotating the display, it will
7537 // schedule a new message when done.
7538 if (mDisplayFrozen) {
7539 return;
7540 }
7541 mFreezeGcPending = 0;
7542 }
7543 Runtime.getRuntime().gc();
7544 break;
7545 }
Romain Guy06882f82009-06-10 13:36:04 -07007546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007547 case ENABLE_SCREEN: {
7548 performEnableScreen();
7549 break;
7550 }
Romain Guy06882f82009-06-10 13:36:04 -07007551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007552 case APP_FREEZE_TIMEOUT: {
7553 synchronized (mWindowMap) {
7554 Log.w(TAG, "App freeze timeout expired.");
7555 int i = mAppTokens.size();
7556 while (i > 0) {
7557 i--;
7558 AppWindowToken tok = mAppTokens.get(i);
7559 if (tok.freezingScreen) {
7560 Log.w(TAG, "Force clearing freeze: " + tok);
7561 unsetAppFreezingScreenLocked(tok, true, true);
7562 }
7563 }
7564 }
7565 break;
7566 }
Romain Guy06882f82009-06-10 13:36:04 -07007567
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007568 case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
Dianne Hackborncfaef692009-06-15 14:24:44 -07007569 if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07007570 sendNewConfiguration();
7571 }
7572 break;
7573 }
Romain Guy06882f82009-06-10 13:36:04 -07007574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007575 }
7576 }
7577 }
7578
7579 // -------------------------------------------------------------
7580 // IWindowManager API
7581 // -------------------------------------------------------------
7582
7583 public IWindowSession openSession(IInputMethodClient client,
7584 IInputContext inputContext) {
7585 if (client == null) throw new IllegalArgumentException("null client");
7586 if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7587 return new Session(client, inputContext);
7588 }
7589
7590 public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7591 synchronized (mWindowMap) {
7592 // The focus for the client is the window immediately below
7593 // where we would place the input method window.
7594 int idx = findDesiredInputMethodWindowIndexLocked(false);
7595 WindowState imFocus;
7596 if (idx > 0) {
7597 imFocus = (WindowState)mWindows.get(idx-1);
7598 if (imFocus != null) {
7599 if (imFocus.mSession.mClient != null &&
7600 imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7601 return true;
7602 }
7603 }
7604 }
7605 }
7606 return false;
7607 }
Romain Guy06882f82009-06-10 13:36:04 -07007608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007609 // -------------------------------------------------------------
7610 // Internals
7611 // -------------------------------------------------------------
7612
7613 final WindowState windowForClientLocked(Session session, IWindow client) {
7614 return windowForClientLocked(session, client.asBinder());
7615 }
Romain Guy06882f82009-06-10 13:36:04 -07007616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007617 final WindowState windowForClientLocked(Session session, IBinder client) {
7618 WindowState win = mWindowMap.get(client);
7619 if (localLOGV) Log.v(
7620 TAG, "Looking up client " + client + ": " + win);
7621 if (win == null) {
7622 RuntimeException ex = new RuntimeException();
7623 Log.w(TAG, "Requested window " + client + " does not exist", ex);
7624 return null;
7625 }
7626 if (session != null && win.mSession != session) {
7627 RuntimeException ex = new RuntimeException();
7628 Log.w(TAG, "Requested window " + client + " is in session " +
7629 win.mSession + ", not " + session, ex);
7630 return null;
7631 }
7632
7633 return win;
7634 }
7635
7636 private final void assignLayersLocked() {
7637 int N = mWindows.size();
7638 int curBaseLayer = 0;
7639 int curLayer = 0;
7640 int i;
Romain Guy06882f82009-06-10 13:36:04 -07007641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007642 for (i=0; i<N; i++) {
7643 WindowState w = (WindowState)mWindows.get(i);
7644 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
7645 curLayer += WINDOW_LAYER_MULTIPLIER;
7646 w.mLayer = curLayer;
7647 } else {
7648 curBaseLayer = curLayer = w.mBaseLayer;
7649 w.mLayer = curLayer;
7650 }
7651 if (w.mTargetAppToken != null) {
7652 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
7653 } else if (w.mAppToken != null) {
7654 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
7655 } else {
7656 w.mAnimLayer = w.mLayer;
7657 }
7658 if (w.mIsImWindow) {
7659 w.mAnimLayer += mInputMethodAnimLayerAdjustment;
7660 }
7661 if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
7662 + w.mAnimLayer);
7663 //System.out.println(
7664 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7665 }
7666 }
7667
7668 private boolean mInLayout = false;
7669 private final void performLayoutAndPlaceSurfacesLocked() {
7670 if (mInLayout) {
Dave Bortcfe65242009-04-09 14:51:04 -07007671 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007672 throw new RuntimeException("Recursive call!");
7673 }
7674 Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7675 return;
7676 }
7677
7678 boolean recoveringMemory = false;
7679 if (mForceRemoves != null) {
7680 recoveringMemory = true;
7681 // Wait a little it for things to settle down, and off we go.
7682 for (int i=0; i<mForceRemoves.size(); i++) {
7683 WindowState ws = mForceRemoves.get(i);
7684 Log.i(TAG, "Force removing: " + ws);
7685 removeWindowInnerLocked(ws.mSession, ws);
7686 }
7687 mForceRemoves = null;
7688 Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
7689 Object tmp = new Object();
7690 synchronized (tmp) {
7691 try {
7692 tmp.wait(250);
7693 } catch (InterruptedException e) {
7694 }
7695 }
7696 }
Romain Guy06882f82009-06-10 13:36:04 -07007697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007698 mInLayout = true;
7699 try {
7700 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
Romain Guy06882f82009-06-10 13:36:04 -07007701
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007702 int i = mPendingRemove.size()-1;
7703 if (i >= 0) {
7704 while (i >= 0) {
7705 WindowState w = mPendingRemove.get(i);
7706 removeWindowInnerLocked(w.mSession, w);
7707 i--;
7708 }
7709 mPendingRemove.clear();
7710
7711 mInLayout = false;
7712 assignLayersLocked();
7713 mLayoutNeeded = true;
7714 performLayoutAndPlaceSurfacesLocked();
7715
7716 } else {
7717 mInLayout = false;
7718 if (mLayoutNeeded) {
7719 requestAnimationLocked(0);
7720 }
7721 }
7722 } catch (RuntimeException e) {
7723 mInLayout = false;
7724 Log.e(TAG, "Unhandled exception while layout out windows", e);
7725 }
7726 }
7727
7728 private final void performLayoutLockedInner() {
7729 final int dw = mDisplay.getWidth();
7730 final int dh = mDisplay.getHeight();
7731
7732 final int N = mWindows.size();
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007733 int repeats = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007734 int i;
7735
7736 // FIRST LOOP: Perform a layout, if needed.
Romain Guy06882f82009-06-10 13:36:04 -07007737
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007738 while (mLayoutNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007739 mPolicy.beginLayoutLw(dw, dh);
7740
7741 // First perform layout of any root windows (not attached
7742 // to another window).
7743 int topAttached = -1;
7744 for (i = N-1; i >= 0; i--) {
7745 WindowState win = (WindowState) mWindows.get(i);
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007746
7747 // Don't do layout of a window if it is not visible, or
7748 // soon won't be visible, to avoid wasting time and funky
7749 // changes while a window is animating away.
7750 final AppWindowToken atoken = win.mAppToken;
7751 final boolean gone = win.mViewVisibility == View.GONE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007752 || !win.mRelayoutCalled
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007753 || win.mRootToken.hidden
7754 || (atoken != null && atoken.hiddenRequested)
7755 || !win.mPolicyVisibility
7756 || win.mAttachedHidden
7757 || win.mExiting || win.mDestroying;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007758
7759 // If this view is GONE, then skip it -- keep the current
7760 // frame, and let the caller know so they can ignore it
7761 // if they want. (We do the normal layout for INVISIBLE
7762 // windows, since that means "perform layout as normal,
7763 // just don't display").
7764 if (!gone || !win.mHaveFrame) {
7765 if (!win.mLayoutAttached) {
7766 mPolicy.layoutWindowLw(win, win.mAttrs, null);
7767 } else {
7768 if (topAttached < 0) topAttached = i;
7769 }
7770 }
7771 }
Romain Guy06882f82009-06-10 13:36:04 -07007772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007773 // Now perform layout of attached windows, which usually
7774 // depend on the position of the window they are attached to.
7775 // XXX does not deal with windows that are attached to windows
7776 // that are themselves attached.
7777 for (i = topAttached; i >= 0; i--) {
7778 WindowState win = (WindowState) mWindows.get(i);
7779
7780 // If this view is GONE, then skip it -- keep the current
7781 // frame, and let the caller know so they can ignore it
7782 // if they want. (We do the normal layout for INVISIBLE
7783 // windows, since that means "perform layout as normal,
7784 // just don't display").
7785 if (win.mLayoutAttached) {
7786 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7787 || !win.mHaveFrame) {
7788 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7789 }
7790 }
7791 }
7792
Dianne Hackborn958b9ad2009-03-31 18:00:36 -07007793 if (!mPolicy.finishLayoutLw()) {
7794 mLayoutNeeded = false;
7795 } else if (repeats > 2) {
7796 Log.w(TAG, "Layout repeat aborted after too many iterations");
7797 mLayoutNeeded = false;
7798 } else {
7799 repeats++;
7800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007801 }
7802 }
Romain Guy06882f82009-06-10 13:36:04 -07007803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007804 private final void performLayoutAndPlaceSurfacesLockedInner(
7805 boolean recoveringMemory) {
7806 final long currentTime = SystemClock.uptimeMillis();
7807 final int dw = mDisplay.getWidth();
7808 final int dh = mDisplay.getHeight();
7809
7810 final int N = mWindows.size();
7811 int i;
7812
7813 // FIRST LOOP: Perform a layout, if needed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007814 performLayoutLockedInner();
Romain Guy06882f82009-06-10 13:36:04 -07007815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007816 if (mFxSession == null) {
7817 mFxSession = new SurfaceSession();
7818 }
Romain Guy06882f82009-06-10 13:36:04 -07007819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007820 if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
7821
7822 // Initialize state of exiting tokens.
7823 for (i=mExitingTokens.size()-1; i>=0; i--) {
7824 mExitingTokens.get(i).hasVisible = false;
7825 }
7826
7827 // Initialize state of exiting applications.
7828 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7829 mExitingAppTokens.get(i).hasVisible = false;
7830 }
7831
7832 // SECOND LOOP: Execute animations and update visibility of windows.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007833 boolean orientationChangeComplete = true;
7834 Session holdScreen = null;
7835 float screenBrightness = -1;
7836 boolean focusDisplayed = false;
7837 boolean animating = false;
7838
7839 Surface.openTransaction();
7840 try {
7841 boolean restart;
7842
7843 do {
7844 final int transactionSequence = ++mTransactionSequence;
7845
7846 // Update animations of all applications, including those
7847 // associated with exiting/removed apps
7848 boolean tokensAnimating = false;
7849 final int NAT = mAppTokens.size();
7850 for (i=0; i<NAT; i++) {
7851 if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7852 tokensAnimating = true;
7853 }
7854 }
7855 final int NEAT = mExitingAppTokens.size();
7856 for (i=0; i<NEAT; i++) {
7857 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
7858 tokensAnimating = true;
7859 }
7860 }
7861
7862 animating = tokensAnimating;
7863 restart = false;
7864
7865 boolean tokenMayBeDrawn = false;
7866
7867 mPolicy.beginAnimationLw(dw, dh);
7868
7869 for (i=N-1; i>=0; i--) {
7870 WindowState w = (WindowState)mWindows.get(i);
7871
7872 final WindowManager.LayoutParams attrs = w.mAttrs;
7873
7874 if (w.mSurface != null) {
7875 // Execute animation.
7876 w.commitFinishDrawingLocked(currentTime);
7877 if (w.stepAnimationLocked(currentTime, dw, dh)) {
7878 animating = true;
7879 //w.dump(" ");
7880 }
7881
7882 mPolicy.animatingWindowLw(w, attrs);
7883 }
7884
7885 final AppWindowToken atoken = w.mAppToken;
7886 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7887 if (atoken.lastTransactionSequence != transactionSequence) {
7888 atoken.lastTransactionSequence = transactionSequence;
7889 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7890 atoken.startingDisplayed = false;
7891 }
7892 if ((w.isOnScreen() || w.mAttrs.type
7893 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7894 && !w.mExiting && !w.mDestroying) {
7895 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7896 Log.v(TAG, "Eval win " + w + ": isDisplayed="
7897 + w.isDisplayedLw()
7898 + ", isAnimating=" + w.isAnimating());
7899 if (!w.isDisplayedLw()) {
7900 Log.v(TAG, "Not displayed: s=" + w.mSurface
7901 + " pv=" + w.mPolicyVisibility
7902 + " dp=" + w.mDrawPending
7903 + " cdp=" + w.mCommitDrawPending
7904 + " ah=" + w.mAttachedHidden
7905 + " th=" + atoken.hiddenRequested
7906 + " a=" + w.mAnimating);
7907 }
7908 }
7909 if (w != atoken.startingWindow) {
7910 if (!atoken.freezingScreen || !w.mAppFreezing) {
7911 atoken.numInterestingWindows++;
7912 if (w.isDisplayedLw()) {
7913 atoken.numDrawnWindows++;
7914 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
7915 "tokenMayBeDrawn: " + atoken
7916 + " freezingScreen=" + atoken.freezingScreen
7917 + " mAppFreezing=" + w.mAppFreezing);
7918 tokenMayBeDrawn = true;
7919 }
7920 }
7921 } else if (w.isDisplayedLw()) {
7922 atoken.startingDisplayed = true;
7923 }
7924 }
7925 } else if (w.mReadyToShow) {
7926 w.performShowLocked();
7927 }
7928 }
7929
7930 if (mPolicy.finishAnimationLw()) {
7931 restart = true;
7932 }
7933
7934 if (tokenMayBeDrawn) {
7935 // See if any windows have been drawn, so they (and others
7936 // associated with them) can now be shown.
7937 final int NT = mTokenList.size();
7938 for (i=0; i<NT; i++) {
7939 AppWindowToken wtoken = mTokenList.get(i).appWindowToken;
7940 if (wtoken == null) {
7941 continue;
7942 }
7943 if (wtoken.freezingScreen) {
7944 int numInteresting = wtoken.numInterestingWindows;
7945 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7946 if (DEBUG_VISIBILITY) Log.v(TAG,
7947 "allDrawn: " + wtoken
7948 + " interesting=" + numInteresting
7949 + " drawn=" + wtoken.numDrawnWindows);
7950 wtoken.showAllWindowsLocked();
7951 unsetAppFreezingScreenLocked(wtoken, false, true);
7952 orientationChangeComplete = true;
7953 }
7954 } else if (!wtoken.allDrawn) {
7955 int numInteresting = wtoken.numInterestingWindows;
7956 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7957 if (DEBUG_VISIBILITY) Log.v(TAG,
7958 "allDrawn: " + wtoken
7959 + " interesting=" + numInteresting
7960 + " drawn=" + wtoken.numDrawnWindows);
7961 wtoken.allDrawn = true;
7962 restart = true;
7963
7964 // We can now show all of the drawn windows!
7965 if (!mOpeningApps.contains(wtoken)) {
7966 wtoken.showAllWindowsLocked();
7967 }
7968 }
7969 }
7970 }
7971 }
7972
7973 // If we are ready to perform an app transition, check through
7974 // all of the app tokens to be shown and see if they are ready
7975 // to go.
7976 if (mAppTransitionReady) {
7977 int NN = mOpeningApps.size();
7978 boolean goodToGo = true;
7979 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7980 "Checking " + NN + " opening apps (frozen="
7981 + mDisplayFrozen + " timeout="
7982 + mAppTransitionTimeout + ")...");
7983 if (!mDisplayFrozen && !mAppTransitionTimeout) {
7984 // If the display isn't frozen, wait to do anything until
7985 // all of the apps are ready. Otherwise just go because
7986 // we'll unfreeze the display when everyone is ready.
7987 for (i=0; i<NN && goodToGo; i++) {
7988 AppWindowToken wtoken = mOpeningApps.get(i);
7989 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
7990 "Check opening app" + wtoken + ": allDrawn="
7991 + wtoken.allDrawn + " startingDisplayed="
7992 + wtoken.startingDisplayed);
7993 if (!wtoken.allDrawn && !wtoken.startingDisplayed
7994 && !wtoken.startingMoved) {
7995 goodToGo = false;
7996 }
7997 }
7998 }
7999 if (goodToGo) {
8000 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
8001 int transit = mNextAppTransition;
8002 if (mSkipAppTransitionAnimation) {
8003 transit = WindowManagerPolicy.TRANSIT_NONE;
8004 }
8005 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8006 mAppTransitionReady = false;
8007 mAppTransitionTimeout = false;
8008 mStartingIconInTransition = false;
8009 mSkipAppTransitionAnimation = false;
8010
8011 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8012
8013 // We need to figure out which animation to use...
8014 WindowManager.LayoutParams lp = findAnimations(mAppTokens,
8015 mOpeningApps, mClosingApps);
8016
8017 NN = mOpeningApps.size();
8018 for (i=0; i<NN; i++) {
8019 AppWindowToken wtoken = mOpeningApps.get(i);
8020 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8021 "Now opening app" + wtoken);
8022 wtoken.reportedVisible = false;
8023 wtoken.inPendingTransaction = false;
8024 setTokenVisibilityLocked(wtoken, lp, true, transit, false);
8025 wtoken.updateReportedVisibilityLocked();
8026 wtoken.showAllWindowsLocked();
8027 }
8028 NN = mClosingApps.size();
8029 for (i=0; i<NN; i++) {
8030 AppWindowToken wtoken = mClosingApps.get(i);
8031 if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
8032 "Now closing app" + wtoken);
8033 wtoken.inPendingTransaction = false;
8034 setTokenVisibilityLocked(wtoken, lp, false, transit, false);
8035 wtoken.updateReportedVisibilityLocked();
8036 // Force the allDrawn flag, because we want to start
8037 // this guy's animations regardless of whether it's
8038 // gotten drawn.
8039 wtoken.allDrawn = true;
8040 }
8041
8042 mOpeningApps.clear();
8043 mClosingApps.clear();
8044
8045 // This has changed the visibility of windows, so perform
8046 // a new layout to get them all up-to-date.
8047 mLayoutNeeded = true;
8048 moveInputMethodWindowsIfNeededLocked(true);
8049 performLayoutLockedInner();
8050 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
8051
8052 restart = true;
8053 }
8054 }
8055 } while (restart);
8056
8057 // THIRD LOOP: Update the surfaces of all windows.
8058
8059 final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8060
8061 boolean obscured = false;
8062 boolean blurring = false;
8063 boolean dimming = false;
8064 boolean covered = false;
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008065 boolean syswin = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008066
8067 for (i=N-1; i>=0; i--) {
8068 WindowState w = (WindowState)mWindows.get(i);
8069
8070 boolean displayed = false;
8071 final WindowManager.LayoutParams attrs = w.mAttrs;
8072 final int attrFlags = attrs.flags;
8073
8074 if (w.mSurface != null) {
8075 w.computeShownFrameLocked();
8076 if (localLOGV) Log.v(
8077 TAG, "Placing surface #" + i + " " + w.mSurface
8078 + ": new=" + w.mShownFrame + ", old="
8079 + w.mLastShownFrame);
8080
8081 boolean resize;
8082 int width, height;
8083 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8084 resize = w.mLastRequestedWidth != w.mRequestedWidth ||
8085 w.mLastRequestedHeight != w.mRequestedHeight;
8086 // for a scaled surface, we just want to use
8087 // the requested size.
8088 width = w.mRequestedWidth;
8089 height = w.mRequestedHeight;
8090 w.mLastRequestedWidth = width;
8091 w.mLastRequestedHeight = height;
8092 w.mLastShownFrame.set(w.mShownFrame);
8093 try {
8094 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8095 } catch (RuntimeException e) {
8096 Log.w(TAG, "Error positioning surface in " + w, e);
8097 if (!recoveringMemory) {
8098 reclaimSomeSurfaceMemoryLocked(w, "position");
8099 }
8100 }
8101 } else {
8102 resize = !w.mLastShownFrame.equals(w.mShownFrame);
8103 width = w.mShownFrame.width();
8104 height = w.mShownFrame.height();
8105 w.mLastShownFrame.set(w.mShownFrame);
8106 if (resize) {
8107 if (SHOW_TRANSACTIONS) Log.i(
8108 TAG, " SURFACE " + w.mSurface + ": ("
8109 + w.mShownFrame.left + ","
8110 + w.mShownFrame.top + ") ("
8111 + w.mShownFrame.width() + "x"
8112 + w.mShownFrame.height() + ")");
8113 }
8114 }
8115
8116 if (resize) {
8117 if (width < 1) width = 1;
8118 if (height < 1) height = 1;
8119 if (w.mSurface != null) {
8120 try {
8121 w.mSurface.setSize(width, height);
8122 w.mSurface.setPosition(w.mShownFrame.left,
8123 w.mShownFrame.top);
8124 } catch (RuntimeException e) {
8125 // If something goes wrong with the surface (such
8126 // as running out of memory), don't take down the
8127 // entire system.
8128 Log.e(TAG, "Failure updating surface of " + w
8129 + "size=(" + width + "x" + height
8130 + "), pos=(" + w.mShownFrame.left
8131 + "," + w.mShownFrame.top + ")", e);
8132 if (!recoveringMemory) {
8133 reclaimSomeSurfaceMemoryLocked(w, "size");
8134 }
8135 }
8136 }
8137 }
8138 if (!w.mAppFreezing) {
8139 w.mContentInsetsChanged =
8140 !w.mLastContentInsets.equals(w.mContentInsets);
8141 w.mVisibleInsetsChanged =
8142 !w.mLastVisibleInsets.equals(w.mVisibleInsets);
Romain Guy06882f82009-06-10 13:36:04 -07008143 if (!w.mLastFrame.equals(w.mFrame)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008144 || w.mContentInsetsChanged
8145 || w.mVisibleInsetsChanged) {
8146 w.mLastFrame.set(w.mFrame);
8147 w.mLastContentInsets.set(w.mContentInsets);
8148 w.mLastVisibleInsets.set(w.mVisibleInsets);
8149 // If the orientation is changing, then we need to
8150 // hold off on unfreezing the display until this
8151 // window has been redrawn; to do that, we need
8152 // to go through the process of getting informed
8153 // by the application when it has finished drawing.
8154 if (w.mOrientationChanging) {
8155 if (DEBUG_ORIENTATION) Log.v(TAG,
8156 "Orientation start waiting for draw in "
8157 + w + ", surface " + w.mSurface);
8158 w.mDrawPending = true;
8159 w.mCommitDrawPending = false;
8160 w.mReadyToShow = false;
8161 if (w.mAppToken != null) {
8162 w.mAppToken.allDrawn = false;
8163 }
8164 }
Romain Guy06882f82009-06-10 13:36:04 -07008165 if (DEBUG_ORIENTATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008166 "Resizing window " + w + " to " + w.mFrame);
8167 mResizingWindows.add(w);
8168 } else if (w.mOrientationChanging) {
8169 if (!w.mDrawPending && !w.mCommitDrawPending) {
8170 if (DEBUG_ORIENTATION) Log.v(TAG,
8171 "Orientation not waiting for draw in "
8172 + w + ", surface " + w.mSurface);
8173 w.mOrientationChanging = false;
8174 }
8175 }
8176 }
8177
8178 if (w.mAttachedHidden) {
8179 if (!w.mLastHidden) {
8180 //dump();
8181 w.mLastHidden = true;
8182 if (SHOW_TRANSACTIONS) Log.i(
8183 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)");
8184 if (w.mSurface != null) {
8185 try {
8186 w.mSurface.hide();
8187 } catch (RuntimeException e) {
8188 Log.w(TAG, "Exception hiding surface in " + w);
8189 }
8190 }
8191 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8192 }
8193 // If we are waiting for this window to handle an
8194 // orientation change, well, it is hidden, so
8195 // doesn't really matter. Note that this does
8196 // introduce a potential glitch if the window
8197 // becomes unhidden before it has drawn for the
8198 // new orientation.
8199 if (w.mOrientationChanging) {
8200 w.mOrientationChanging = false;
8201 if (DEBUG_ORIENTATION) Log.v(TAG,
8202 "Orientation change skips hidden " + w);
8203 }
8204 } else if (!w.isReadyForDisplay()) {
8205 if (!w.mLastHidden) {
8206 //dump();
8207 w.mLastHidden = true;
8208 if (SHOW_TRANSACTIONS) Log.i(
8209 TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)");
8210 if (w.mSurface != null) {
8211 try {
8212 w.mSurface.hide();
8213 } catch (RuntimeException e) {
8214 Log.w(TAG, "Exception exception hiding surface in " + w);
8215 }
8216 }
8217 mKeyWaiter.releasePendingPointerLocked(w.mSession);
8218 }
8219 // If we are waiting for this window to handle an
8220 // orientation change, well, it is hidden, so
8221 // doesn't really matter. Note that this does
8222 // introduce a potential glitch if the window
8223 // becomes unhidden before it has drawn for the
8224 // new orientation.
8225 if (w.mOrientationChanging) {
8226 w.mOrientationChanging = false;
8227 if (DEBUG_ORIENTATION) Log.v(TAG,
8228 "Orientation change skips hidden " + w);
8229 }
8230 } else if (w.mLastLayer != w.mAnimLayer
8231 || w.mLastAlpha != w.mShownAlpha
8232 || w.mLastDsDx != w.mDsDx
8233 || w.mLastDtDx != w.mDtDx
8234 || w.mLastDsDy != w.mDsDy
8235 || w.mLastDtDy != w.mDtDy
8236 || w.mLastHScale != w.mHScale
8237 || w.mLastVScale != w.mVScale
8238 || w.mLastHidden) {
8239 displayed = true;
8240 w.mLastAlpha = w.mShownAlpha;
8241 w.mLastLayer = w.mAnimLayer;
8242 w.mLastDsDx = w.mDsDx;
8243 w.mLastDtDx = w.mDtDx;
8244 w.mLastDsDy = w.mDsDy;
8245 w.mLastDtDy = w.mDtDy;
8246 w.mLastHScale = w.mHScale;
8247 w.mLastVScale = w.mVScale;
8248 if (SHOW_TRANSACTIONS) Log.i(
8249 TAG, " SURFACE " + w.mSurface + ": alpha="
8250 + w.mShownAlpha + " layer=" + w.mAnimLayer);
8251 if (w.mSurface != null) {
8252 try {
8253 w.mSurface.setAlpha(w.mShownAlpha);
8254 w.mSurface.setLayer(w.mAnimLayer);
8255 w.mSurface.setMatrix(
8256 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8257 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8258 } catch (RuntimeException e) {
8259 Log.w(TAG, "Error updating surface in " + w, e);
8260 if (!recoveringMemory) {
8261 reclaimSomeSurfaceMemoryLocked(w, "update");
8262 }
8263 }
8264 }
8265
8266 if (w.mLastHidden && !w.mDrawPending
8267 && !w.mCommitDrawPending
8268 && !w.mReadyToShow) {
8269 if (SHOW_TRANSACTIONS) Log.i(
8270 TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)");
8271 if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w
8272 + " during relayout");
8273 if (showSurfaceRobustlyLocked(w)) {
8274 w.mHasDrawn = true;
8275 w.mLastHidden = false;
8276 } else {
8277 w.mOrientationChanging = false;
8278 }
8279 }
8280 if (w.mSurface != null) {
8281 w.mToken.hasVisible = true;
8282 }
8283 } else {
8284 displayed = true;
8285 }
8286
8287 if (displayed) {
8288 if (!covered) {
8289 if (attrs.width == LayoutParams.FILL_PARENT
8290 && attrs.height == LayoutParams.FILL_PARENT) {
8291 covered = true;
8292 }
8293 }
8294 if (w.mOrientationChanging) {
8295 if (w.mDrawPending || w.mCommitDrawPending) {
8296 orientationChangeComplete = false;
8297 if (DEBUG_ORIENTATION) Log.v(TAG,
8298 "Orientation continue waiting for draw in " + w);
8299 } else {
8300 w.mOrientationChanging = false;
8301 if (DEBUG_ORIENTATION) Log.v(TAG,
8302 "Orientation change complete in " + w);
8303 }
8304 }
8305 w.mToken.hasVisible = true;
8306 }
8307 } else if (w.mOrientationChanging) {
8308 if (DEBUG_ORIENTATION) Log.v(TAG,
8309 "Orientation change skips hidden " + w);
8310 w.mOrientationChanging = false;
8311 }
8312
8313 final boolean canBeSeen = w.isDisplayedLw();
8314
8315 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8316 focusDisplayed = true;
8317 }
8318
8319 // Update effect.
8320 if (!obscured) {
8321 if (w.mSurface != null) {
8322 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8323 holdScreen = w.mSession;
8324 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008325 if (!syswin && w.mAttrs.screenBrightness >= 0
8326 && screenBrightness < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008327 screenBrightness = w.mAttrs.screenBrightness;
8328 }
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07008329 if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8330 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8331 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
8332 syswin = true;
8333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008334 }
8335 if (w.isFullscreenOpaque(dw, dh)) {
8336 // This window completely covers everything behind it,
8337 // so we want to leave all of them as unblurred (for
8338 // performance reasons).
8339 obscured = true;
8340 } else if (canBeSeen && !obscured &&
8341 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8342 if (localLOGV) Log.v(TAG, "Win " + w
8343 + ": blurring=" + blurring
8344 + " obscured=" + obscured
8345 + " displayed=" + displayed);
8346 if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8347 if (!dimming) {
8348 //Log.i(TAG, "DIM BEHIND: " + w);
8349 dimming = true;
8350 mDimShown = true;
8351 if (mDimSurface == null) {
8352 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8353 + mDimSurface + ": CREATE");
8354 try {
Romain Guy06882f82009-06-10 13:36:04 -07008355 mDimSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008356 -1, 16, 16,
8357 PixelFormat.OPAQUE,
8358 Surface.FX_SURFACE_DIM);
8359 } catch (Exception e) {
8360 Log.e(TAG, "Exception creating Dim surface", e);
8361 }
8362 }
8363 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8364 + mDimSurface + ": SHOW pos=(0,0) (" +
8365 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8366 if (mDimSurface != null) {
8367 try {
8368 mDimSurface.setPosition(0, 0);
8369 mDimSurface.setSize(dw, dh);
8370 mDimSurface.show();
8371 } catch (RuntimeException e) {
8372 Log.w(TAG, "Failure showing dim surface", e);
8373 }
8374 }
8375 }
8376 mDimSurface.setLayer(w.mAnimLayer-1);
8377 final float target = w.mExiting ? 0 : attrs.dimAmount;
8378 if (mDimTargetAlpha != target) {
8379 // If the desired dim level has changed, then
8380 // start an animation to it.
8381 mLastDimAnimTime = currentTime;
8382 long duration = (w.mAnimating && w.mAnimation != null)
8383 ? w.mAnimation.computeDurationHint()
8384 : DEFAULT_DIM_DURATION;
8385 if (target > mDimTargetAlpha) {
8386 // This is happening behind the activity UI,
8387 // so we can make it run a little longer to
8388 // give a stronger impression without disrupting
8389 // the user.
8390 duration *= DIM_DURATION_MULTIPLIER;
8391 }
8392 if (duration < 1) {
8393 // Don't divide by zero
8394 duration = 1;
8395 }
8396 mDimTargetAlpha = target;
8397 mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha)
8398 / duration;
8399 }
8400 }
8401 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8402 if (!blurring) {
8403 //Log.i(TAG, "BLUR BEHIND: " + w);
8404 blurring = true;
8405 mBlurShown = true;
8406 if (mBlurSurface == null) {
8407 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8408 + mBlurSurface + ": CREATE");
8409 try {
Romain Guy06882f82009-06-10 13:36:04 -07008410 mBlurSurface = new Surface(mFxSession, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008411 -1, 16, 16,
8412 PixelFormat.OPAQUE,
8413 Surface.FX_SURFACE_BLUR);
8414 } catch (Exception e) {
8415 Log.e(TAG, "Exception creating Blur surface", e);
8416 }
8417 }
8418 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
8419 + mBlurSurface + ": SHOW pos=(0,0) (" +
8420 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8421 if (mBlurSurface != null) {
8422 mBlurSurface.setPosition(0, 0);
8423 mBlurSurface.setSize(dw, dh);
8424 try {
8425 mBlurSurface.show();
8426 } catch (RuntimeException e) {
8427 Log.w(TAG, "Failure showing blur surface", e);
8428 }
8429 }
8430 }
8431 mBlurSurface.setLayer(w.mAnimLayer-2);
8432 }
8433 }
8434 }
8435 }
8436
8437 if (!dimming && mDimShown) {
8438 // Time to hide the dim surface... start fading.
8439 if (mDimTargetAlpha != 0) {
8440 mLastDimAnimTime = currentTime;
8441 mDimTargetAlpha = 0;
8442 mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
8443 }
8444 }
8445
8446 if (mDimShown && mLastDimAnimTime != 0) {
8447 mDimCurrentAlpha += mDimDeltaPerMs
8448 * (currentTime-mLastDimAnimTime);
8449 boolean more = true;
8450 if (mDisplayFrozen) {
8451 // If the display is frozen, there is no reason to animate.
8452 more = false;
8453 } else if (mDimDeltaPerMs > 0) {
8454 if (mDimCurrentAlpha > mDimTargetAlpha) {
8455 more = false;
8456 }
8457 } else if (mDimDeltaPerMs < 0) {
8458 if (mDimCurrentAlpha < mDimTargetAlpha) {
8459 more = false;
8460 }
8461 } else {
8462 more = false;
8463 }
Romain Guy06882f82009-06-10 13:36:04 -07008464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008465 // Do we need to continue animating?
8466 if (more) {
8467 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8468 + mDimSurface + ": alpha=" + mDimCurrentAlpha);
8469 mLastDimAnimTime = currentTime;
8470 mDimSurface.setAlpha(mDimCurrentAlpha);
8471 animating = true;
8472 } else {
8473 mDimCurrentAlpha = mDimTargetAlpha;
8474 mLastDimAnimTime = 0;
8475 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
8476 + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
8477 mDimSurface.setAlpha(mDimCurrentAlpha);
8478 if (!dimming) {
8479 if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
8480 + ": HIDE");
8481 try {
8482 mDimSurface.hide();
8483 } catch (RuntimeException e) {
8484 Log.w(TAG, "Illegal argument exception hiding dim surface");
8485 }
8486 mDimShown = false;
8487 }
8488 }
8489 }
Romain Guy06882f82009-06-10 13:36:04 -07008490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008491 if (!blurring && mBlurShown) {
8492 if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
8493 + ": HIDE");
8494 try {
8495 mBlurSurface.hide();
8496 } catch (IllegalArgumentException e) {
8497 Log.w(TAG, "Illegal argument exception hiding blur surface");
8498 }
8499 mBlurShown = false;
8500 }
8501
8502 if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
8503 } catch (RuntimeException e) {
8504 Log.e(TAG, "Unhandled exception in Window Manager", e);
8505 }
8506
8507 Surface.closeTransaction();
Romain Guy06882f82009-06-10 13:36:04 -07008508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
8510 "With display frozen, orientationChangeComplete="
8511 + orientationChangeComplete);
8512 if (orientationChangeComplete) {
8513 if (mWindowsFreezingScreen) {
8514 mWindowsFreezingScreen = false;
8515 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8516 }
8517 if (mAppsFreezingScreen == 0) {
8518 stopFreezingDisplayLocked();
8519 }
8520 }
Romain Guy06882f82009-06-10 13:36:04 -07008521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008522 i = mResizingWindows.size();
8523 if (i > 0) {
8524 do {
8525 i--;
8526 WindowState win = mResizingWindows.get(i);
8527 try {
8528 win.mClient.resized(win.mFrame.width(),
8529 win.mFrame.height(), win.mLastContentInsets,
8530 win.mLastVisibleInsets, win.mDrawPending);
8531 win.mContentInsetsChanged = false;
8532 win.mVisibleInsetsChanged = false;
8533 } catch (RemoteException e) {
8534 win.mOrientationChanging = false;
8535 }
8536 } while (i > 0);
8537 mResizingWindows.clear();
8538 }
Romain Guy06882f82009-06-10 13:36:04 -07008539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008540 // Destroy the surface of any windows that are no longer visible.
8541 i = mDestroySurface.size();
8542 if (i > 0) {
8543 do {
8544 i--;
8545 WindowState win = mDestroySurface.get(i);
8546 win.mDestroying = false;
8547 if (mInputMethodWindow == win) {
8548 mInputMethodWindow = null;
8549 }
8550 win.destroySurfaceLocked();
8551 } while (i > 0);
8552 mDestroySurface.clear();
8553 }
8554
8555 // Time to remove any exiting tokens?
8556 for (i=mExitingTokens.size()-1; i>=0; i--) {
8557 WindowToken token = mExitingTokens.get(i);
8558 if (!token.hasVisible) {
8559 mExitingTokens.remove(i);
8560 }
8561 }
8562
8563 // Time to remove any exiting applications?
8564 for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8565 AppWindowToken token = mExitingAppTokens.get(i);
8566 if (!token.hasVisible && !mClosingApps.contains(token)) {
8567 mAppTokens.remove(token);
8568 mExitingAppTokens.remove(i);
8569 }
8570 }
8571
8572 if (focusDisplayed) {
8573 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8574 }
8575 if (animating) {
8576 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8577 }
8578 mQueue.setHoldScreenLocked(holdScreen != null);
8579 if (screenBrightness < 0 || screenBrightness > 1.0f) {
8580 mPowerManager.setScreenBrightnessOverride(-1);
8581 } else {
8582 mPowerManager.setScreenBrightnessOverride((int)
8583 (screenBrightness * Power.BRIGHTNESS_ON));
8584 }
8585 if (holdScreen != mHoldingScreenOn) {
8586 mHoldingScreenOn = holdScreen;
8587 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8588 mH.sendMessage(m);
8589 }
8590 }
8591
8592 void requestAnimationLocked(long delay) {
8593 if (!mAnimationPending) {
8594 mAnimationPending = true;
8595 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8596 }
8597 }
Romain Guy06882f82009-06-10 13:36:04 -07008598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008599 /**
8600 * Have the surface flinger show a surface, robustly dealing with
8601 * error conditions. In particular, if there is not enough memory
8602 * to show the surface, then we will try to get rid of other surfaces
8603 * in order to succeed.
Romain Guy06882f82009-06-10 13:36:04 -07008604 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605 * @return Returns true if the surface was successfully shown.
8606 */
8607 boolean showSurfaceRobustlyLocked(WindowState win) {
8608 try {
8609 if (win.mSurface != null) {
8610 win.mSurface.show();
8611 }
8612 return true;
8613 } catch (RuntimeException e) {
8614 Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
8615 }
Romain Guy06882f82009-06-10 13:36:04 -07008616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 reclaimSomeSurfaceMemoryLocked(win, "show");
Romain Guy06882f82009-06-10 13:36:04 -07008618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008619 return false;
8620 }
Romain Guy06882f82009-06-10 13:36:04 -07008621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008622 void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
8623 final Surface surface = win.mSurface;
Romain Guy06882f82009-06-10 13:36:04 -07008624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008625 EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
8626 win.mSession.mPid, operation);
Romain Guy06882f82009-06-10 13:36:04 -07008627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008628 if (mForceRemoves == null) {
8629 mForceRemoves = new ArrayList<WindowState>();
8630 }
Romain Guy06882f82009-06-10 13:36:04 -07008631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008632 long callingIdentity = Binder.clearCallingIdentity();
8633 try {
8634 // There was some problem... first, do a sanity check of the
8635 // window list to make sure we haven't left any dangling surfaces
8636 // around.
8637 int N = mWindows.size();
8638 boolean leakedSurface = false;
8639 Log.i(TAG, "Out of memory for surface! Looking for leaks...");
8640 for (int i=0; i<N; i++) {
8641 WindowState ws = (WindowState)mWindows.get(i);
8642 if (ws.mSurface != null) {
8643 if (!mSessions.contains(ws.mSession)) {
8644 Log.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8645 + ws + " surface=" + ws.mSurface
8646 + " token=" + win.mToken
8647 + " pid=" + ws.mSession.mPid
8648 + " uid=" + ws.mSession.mUid);
8649 ws.mSurface.clear();
8650 ws.mSurface = null;
8651 mForceRemoves.add(ws);
8652 i--;
8653 N--;
8654 leakedSurface = true;
8655 } else if (win.mAppToken != null && win.mAppToken.clientHidden) {
8656 Log.w(TAG, "LEAKED SURFACE (app token hidden): "
8657 + ws + " surface=" + ws.mSurface
8658 + " token=" + win.mAppToken);
8659 ws.mSurface.clear();
8660 ws.mSurface = null;
8661 leakedSurface = true;
8662 }
8663 }
8664 }
Romain Guy06882f82009-06-10 13:36:04 -07008665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008666 boolean killedApps = false;
8667 if (!leakedSurface) {
8668 Log.w(TAG, "No leaked surfaces; killing applicatons!");
8669 SparseIntArray pidCandidates = new SparseIntArray();
8670 for (int i=0; i<N; i++) {
8671 WindowState ws = (WindowState)mWindows.get(i);
8672 if (ws.mSurface != null) {
8673 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8674 }
8675 }
8676 if (pidCandidates.size() > 0) {
8677 int[] pids = new int[pidCandidates.size()];
8678 for (int i=0; i<pids.length; i++) {
8679 pids[i] = pidCandidates.keyAt(i);
8680 }
8681 try {
8682 if (mActivityManager.killPidsForMemory(pids)) {
8683 killedApps = true;
8684 }
8685 } catch (RemoteException e) {
8686 }
8687 }
8688 }
Romain Guy06882f82009-06-10 13:36:04 -07008689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008690 if (leakedSurface || killedApps) {
8691 // We managed to reclaim some memory, so get rid of the trouble
8692 // surface and ask the app to request another one.
8693 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8694 if (surface != null) {
8695 surface.clear();
8696 win.mSurface = null;
8697 }
Romain Guy06882f82009-06-10 13:36:04 -07008698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008699 try {
8700 win.mClient.dispatchGetNewSurface();
8701 } catch (RemoteException e) {
8702 }
8703 }
8704 } finally {
8705 Binder.restoreCallingIdentity(callingIdentity);
8706 }
8707 }
Romain Guy06882f82009-06-10 13:36:04 -07008708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008709 private boolean updateFocusedWindowLocked(int mode) {
8710 WindowState newFocus = computeFocusedWindowLocked();
8711 if (mCurrentFocus != newFocus) {
8712 // This check makes sure that we don't already have the focus
8713 // change message pending.
8714 mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8715 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8716 if (localLOGV) Log.v(
8717 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8718 final WindowState oldFocus = mCurrentFocus;
8719 mCurrentFocus = newFocus;
8720 mLosingFocus.remove(newFocus);
Romain Guy06882f82009-06-10 13:36:04 -07008721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008722 final WindowState imWindow = mInputMethodWindow;
8723 if (newFocus != imWindow && oldFocus != imWindow) {
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008724 if (moveInputMethodWindowsIfNeededLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008725 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008726 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8727 mLayoutNeeded = true;
8728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008729 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8730 performLayoutLockedInner();
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008731 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8732 // Client will do the layout, but we need to assign layers
8733 // for handleNewWindowLocked() below.
8734 assignLayersLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008735 }
8736 }
Romain Guy06882f82009-06-10 13:36:04 -07008737
The Android Open Source Projectc474dec2009-03-04 09:49:09 -08008738 if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8739 mKeyWaiter.handleNewWindowLocked(newFocus);
8740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008741 return true;
8742 }
8743 return false;
8744 }
8745
8746 private WindowState computeFocusedWindowLocked() {
8747 WindowState result = null;
8748 WindowState win;
8749
8750 int i = mWindows.size() - 1;
8751 int nextAppIndex = mAppTokens.size()-1;
8752 WindowToken nextApp = nextAppIndex >= 0
8753 ? mAppTokens.get(nextAppIndex) : null;
8754
8755 while (i >= 0) {
8756 win = (WindowState)mWindows.get(i);
8757
8758 if (localLOGV || DEBUG_FOCUS) Log.v(
8759 TAG, "Looking for focus: " + i
8760 + " = " + win
8761 + ", flags=" + win.mAttrs.flags
8762 + ", canReceive=" + win.canReceiveKeys());
8763
8764 AppWindowToken thisApp = win.mAppToken;
Romain Guy06882f82009-06-10 13:36:04 -07008765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008766 // If this window's application has been removed, just skip it.
8767 if (thisApp != null && thisApp.removed) {
8768 i--;
8769 continue;
8770 }
Romain Guy06882f82009-06-10 13:36:04 -07008771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 // If there is a focused app, don't allow focus to go to any
8773 // windows below it. If this is an application window, step
8774 // through the app tokens until we find its app.
8775 if (thisApp != null && nextApp != null && thisApp != nextApp
8776 && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8777 int origAppIndex = nextAppIndex;
8778 while (nextAppIndex > 0) {
8779 if (nextApp == mFocusedApp) {
8780 // Whoops, we are below the focused app... no focus
8781 // for you!
8782 if (localLOGV || DEBUG_FOCUS) Log.v(
8783 TAG, "Reached focused app: " + mFocusedApp);
8784 return null;
8785 }
8786 nextAppIndex--;
8787 nextApp = mAppTokens.get(nextAppIndex);
8788 if (nextApp == thisApp) {
8789 break;
8790 }
8791 }
8792 if (thisApp != nextApp) {
8793 // Uh oh, the app token doesn't exist! This shouldn't
8794 // happen, but if it does we can get totally hosed...
8795 // so restart at the original app.
8796 nextAppIndex = origAppIndex;
8797 nextApp = mAppTokens.get(nextAppIndex);
8798 }
8799 }
8800
8801 // Dispatch to this window if it is wants key events.
8802 if (win.canReceiveKeys()) {
8803 if (DEBUG_FOCUS) Log.v(
8804 TAG, "Found focus @ " + i + " = " + win);
8805 result = win;
8806 break;
8807 }
8808
8809 i--;
8810 }
8811
8812 return result;
8813 }
8814
8815 private void startFreezingDisplayLocked() {
8816 if (mDisplayFrozen) {
Chris Tate2ad63a92009-03-25 17:36:48 -07008817 // Freezing the display also suspends key event delivery, to
8818 // keep events from going astray while the display is reconfigured.
8819 // If someone has changed orientation again while the screen is
8820 // still frozen, the events will continue to be blocked while the
8821 // successive orientation change is processed. To prevent spurious
8822 // ANRs, we reset the event dispatch timeout in this case.
8823 synchronized (mKeyWaiter) {
8824 mKeyWaiter.mWasFrozen = true;
8825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008826 return;
8827 }
Romain Guy06882f82009-06-10 13:36:04 -07008828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008829 mScreenFrozenLock.acquire();
Romain Guy06882f82009-06-10 13:36:04 -07008830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008831 long now = SystemClock.uptimeMillis();
8832 //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8833 if (mFreezeGcPending != 0) {
8834 if (now > (mFreezeGcPending+1000)) {
8835 //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
8836 mH.removeMessages(H.FORCE_GC);
8837 Runtime.getRuntime().gc();
8838 mFreezeGcPending = now;
8839 }
8840 } else {
8841 mFreezeGcPending = now;
8842 }
Romain Guy06882f82009-06-10 13:36:04 -07008843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008844 mDisplayFrozen = true;
8845 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
8846 mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
8847 mAppTransitionReady = true;
8848 }
Romain Guy06882f82009-06-10 13:36:04 -07008849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008850 if (PROFILE_ORIENTATION) {
8851 File file = new File("/data/system/frozen");
8852 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8853 }
8854 Surface.freezeDisplay(0);
8855 }
Romain Guy06882f82009-06-10 13:36:04 -07008856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008857 private void stopFreezingDisplayLocked() {
8858 if (!mDisplayFrozen) {
8859 return;
8860 }
Romain Guy06882f82009-06-10 13:36:04 -07008861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008862 mDisplayFrozen = false;
8863 mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8864 if (PROFILE_ORIENTATION) {
8865 Debug.stopMethodTracing();
8866 }
8867 Surface.unfreezeDisplay(0);
Romain Guy06882f82009-06-10 13:36:04 -07008868
Chris Tate2ad63a92009-03-25 17:36:48 -07008869 // Reset the key delivery timeout on unfreeze, too. We force a wakeup here
8870 // too because regular key delivery processing should resume immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008871 synchronized (mKeyWaiter) {
8872 mKeyWaiter.mWasFrozen = true;
8873 mKeyWaiter.notifyAll();
8874 }
8875
8876 // A little kludge: a lot could have happened while the
8877 // display was frozen, so now that we are coming back we
8878 // do a gc so that any remote references the system
8879 // processes holds on others can be released if they are
8880 // no longer needed.
8881 mH.removeMessages(H.FORCE_GC);
8882 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8883 2000);
Romain Guy06882f82009-06-10 13:36:04 -07008884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008885 mScreenFrozenLock.release();
8886 }
Romain Guy06882f82009-06-10 13:36:04 -07008887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008888 @Override
8889 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8890 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
8891 != PackageManager.PERMISSION_GRANTED) {
8892 pw.println("Permission Denial: can't dump WindowManager from from pid="
8893 + Binder.getCallingPid()
8894 + ", uid=" + Binder.getCallingUid());
8895 return;
8896 }
Romain Guy06882f82009-06-10 13:36:04 -07008897
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008898 synchronized(mWindowMap) {
8899 pw.println("Current Window Manager state:");
8900 for (int i=mWindows.size()-1; i>=0; i--) {
8901 WindowState w = (WindowState)mWindows.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008902 pw.print(" Window #"); pw.print(i); pw.print(' ');
8903 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008904 w.dump(pw, " ");
8905 }
8906 if (mInputMethodDialogs.size() > 0) {
8907 pw.println(" ");
8908 pw.println(" Input method dialogs:");
8909 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
8910 WindowState w = mInputMethodDialogs.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008911 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008912 }
8913 }
8914 if (mPendingRemove.size() > 0) {
8915 pw.println(" ");
8916 pw.println(" Remove pending for:");
8917 for (int i=mPendingRemove.size()-1; i>=0; i--) {
8918 WindowState w = mPendingRemove.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008919 pw.print(" Remove #"); pw.print(i); pw.print(' ');
8920 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008921 w.dump(pw, " ");
8922 }
8923 }
8924 if (mForceRemoves != null && mForceRemoves.size() > 0) {
8925 pw.println(" ");
8926 pw.println(" Windows force removing:");
8927 for (int i=mForceRemoves.size()-1; i>=0; i--) {
8928 WindowState w = mForceRemoves.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008929 pw.print(" Removing #"); pw.print(i); pw.print(' ');
8930 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 w.dump(pw, " ");
8932 }
8933 }
8934 if (mDestroySurface.size() > 0) {
8935 pw.println(" ");
8936 pw.println(" Windows waiting to destroy their surface:");
8937 for (int i=mDestroySurface.size()-1; i>=0; i--) {
8938 WindowState w = mDestroySurface.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008939 pw.print(" Destroy #"); pw.print(i); pw.print(' ');
8940 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008941 w.dump(pw, " ");
8942 }
8943 }
8944 if (mLosingFocus.size() > 0) {
8945 pw.println(" ");
8946 pw.println(" Windows losing focus:");
8947 for (int i=mLosingFocus.size()-1; i>=0; i--) {
8948 WindowState w = mLosingFocus.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008949 pw.print(" Losing #"); pw.print(i); pw.print(' ');
8950 pw.print(w); pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 w.dump(pw, " ");
8952 }
8953 }
8954 if (mSessions.size() > 0) {
8955 pw.println(" ");
8956 pw.println(" All active sessions:");
8957 Iterator<Session> it = mSessions.iterator();
8958 while (it.hasNext()) {
8959 Session s = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008960 pw.print(" Session "); pw.print(s); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008961 s.dump(pw, " ");
8962 }
8963 }
8964 if (mTokenMap.size() > 0) {
8965 pw.println(" ");
8966 pw.println(" All tokens:");
8967 Iterator<WindowToken> it = mTokenMap.values().iterator();
8968 while (it.hasNext()) {
8969 WindowToken token = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008970 pw.print(" Token "); pw.print(token.token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008971 token.dump(pw, " ");
8972 }
8973 }
8974 if (mTokenList.size() > 0) {
8975 pw.println(" ");
8976 pw.println(" Window token list:");
8977 for (int i=0; i<mTokenList.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008978 pw.print(" #"); pw.print(i); pw.print(": ");
8979 pw.println(mTokenList.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008980 }
8981 }
8982 if (mAppTokens.size() > 0) {
8983 pw.println(" ");
8984 pw.println(" Application tokens in Z order:");
8985 for (int i=mAppTokens.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008986 pw.print(" App #"); pw.print(i); pw.print(": ");
8987 pw.println(mAppTokens.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 }
8989 }
8990 if (mFinishedStarting.size() > 0) {
8991 pw.println(" ");
8992 pw.println(" Finishing start of application tokens:");
8993 for (int i=mFinishedStarting.size()-1; i>=0; i--) {
8994 WindowToken token = mFinishedStarting.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008995 pw.print(" Finished Starting #"); pw.print(i);
8996 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008997 token.dump(pw, " ");
8998 }
8999 }
9000 if (mExitingTokens.size() > 0) {
9001 pw.println(" ");
9002 pw.println(" Exiting tokens:");
9003 for (int i=mExitingTokens.size()-1; i>=0; i--) {
9004 WindowToken token = mExitingTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009005 pw.print(" Exiting #"); pw.print(i);
9006 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 token.dump(pw, " ");
9008 }
9009 }
9010 if (mExitingAppTokens.size() > 0) {
9011 pw.println(" ");
9012 pw.println(" Exiting application tokens:");
9013 for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9014 WindowToken token = mExitingAppTokens.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009015 pw.print(" Exiting App #"); pw.print(i);
9016 pw.print(' '); pw.print(token); pw.println(':');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009017 token.dump(pw, " ");
9018 }
9019 }
9020 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009021 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
9022 pw.print(" mLastFocus="); pw.println(mLastFocus);
9023 pw.print(" mFocusedApp="); pw.println(mFocusedApp);
9024 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
9025 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
9026 pw.print(" mInTouchMode="); pw.println(mInTouchMode);
9027 pw.print(" mSystemBooted="); pw.print(mSystemBooted);
9028 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9029 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
9030 pw.print(" mBlurShown="); pw.println(mBlurShown);
9031 pw.print(" mDimShown="); pw.print(mDimShown);
9032 pw.print(" current="); pw.print(mDimCurrentAlpha);
9033 pw.print(" target="); pw.print(mDimTargetAlpha);
9034 pw.print(" delta="); pw.print(mDimDeltaPerMs);
9035 pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
9036 pw.print(" mInputMethodAnimLayerAdjustment=");
9037 pw.println(mInputMethodAnimLayerAdjustment);
9038 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
9039 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9040 pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
9041 pw.print(" mRotation="); pw.print(mRotation);
9042 pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
9043 pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
9044 pw.print(" mAnimationPending="); pw.print(mAnimationPending);
9045 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9046 pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9047 pw.print(" mNextAppTransition=0x");
9048 pw.print(Integer.toHexString(mNextAppTransition));
9049 pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
9050 pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9051 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9052 pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9053 if (mOpeningApps.size() > 0) {
9054 pw.print(" mOpeningApps="); pw.println(mOpeningApps);
9055 }
9056 if (mClosingApps.size() > 0) {
9057 pw.print(" mClosingApps="); pw.println(mClosingApps);
9058 }
9059 pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth());
9060 pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 pw.println(" KeyWaiter state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 pw.print(" mLastWin="); pw.print(mKeyWaiter.mLastWin);
9063 pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
9064 pw.print(" mFinished="); pw.print(mKeyWaiter.mFinished);
9065 pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
9066 pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
9067 pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 }
9069 }
9070
9071 public void monitor() {
9072 synchronized (mWindowMap) { }
9073 synchronized (mKeyguardDisabled) { }
9074 synchronized (mKeyWaiter) { }
9075 }
9076}