in com/android/server/wm/WindowManagerService.java [4907:5370]
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: entry what=" + msg.what);
}
switch (msg.what) {
case REPORT_FOCUS_CHANGE: {
WindowState lastFocus;
WindowState newFocus;
AccessibilityController accessibilityController = null;
synchronized(mWindowMap) {
// TODO(multidisplay): Accessibility supported only of default desiplay.
if (mAccessibilityController != null && getDefaultDisplayContentLocked()
.getDisplayId() == DEFAULT_DISPLAY) {
accessibilityController = mAccessibilityController;
}
lastFocus = mLastFocus;
newFocus = mCurrentFocus;
if (lastFocus == newFocus) {
// Focus is not changing, so nothing to do.
return;
}
mLastFocus = newFocus;
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Focus moving from " + lastFocus +
" to " + newFocus);
if (newFocus != null && lastFocus != null
&& !newFocus.isDisplayedLw()) {
//Slog.i(TAG_WM, "Delaying loss of focus...");
mLosingFocus.add(lastFocus);
lastFocus = null;
}
}
// First notify the accessibility manager for the change so it has
// the windows before the newly focused one starts firing eventgs.
if (accessibilityController != null) {
accessibilityController.onWindowFocusChangedNotLocked();
}
//System.out.println("Changing focus from " + lastFocus
// + " to " + newFocus);
if (newFocus != null) {
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Gaining focus: " + newFocus);
newFocus.reportFocusChangedSerialized(true, mInTouchMode);
notifyFocusChanged();
}
if (lastFocus != null) {
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing focus: " + lastFocus);
lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
case REPORT_LOSING_FOCUS: {
ArrayList<WindowState> losers;
synchronized(mWindowMap) {
losers = mLosingFocus;
mLosingFocus = new ArrayList<WindowState>();
}
final int N = losers.size();
for (int i=0; i<N; i++) {
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing delayed focus: " +
losers.get(i));
losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
case WINDOW_FREEZE_TIMEOUT: {
// TODO(multidisplay): Can non-default displays rotate?
synchronized (mWindowMap) {
getDefaultDisplayContentLocked().onWindowFreezeTimeout();
}
break;
}
case APP_TRANSITION_TIMEOUT: {
synchronized (mWindowMap) {
if (mAppTransition.isTransitionSet() || !mOpeningApps.isEmpty()
|| !mClosingApps.isEmpty()) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "*** APP TRANSITION TIMEOUT."
+ " isTransitionSet()=" + mAppTransition.isTransitionSet()
+ " mOpeningApps.size()=" + mOpeningApps.size()
+ " mClosingApps.size()=" + mClosingApps.size());
mAppTransition.setTimeout();
mWindowPlacerLocked.performSurfacePlacement();
}
}
break;
}
case PERSIST_ANIMATION_SCALE: {
Settings.Global.putFloat(mContext.getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
Settings.Global.putFloat(mContext.getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE,
mTransitionAnimationScaleSetting);
Settings.Global.putFloat(mContext.getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting);
break;
}
case UPDATE_ANIMATION_SCALE: {
@UpdateAnimationScaleMode
final int mode = msg.arg1;
switch (mode) {
case WINDOW_ANIMATION_SCALE: {
mWindowAnimationScaleSetting = Settings.Global.getFloat(
mContext.getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE,
mWindowAnimationScaleSetting);
break;
}
case TRANSITION_ANIMATION_SCALE: {
mTransitionAnimationScaleSetting = Settings.Global.getFloat(
mContext.getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE,
mTransitionAnimationScaleSetting);
break;
}
case ANIMATION_DURATION_SCALE: {
mAnimatorDurationScaleSetting = Settings.Global.getFloat(
mContext.getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE,
mAnimatorDurationScaleSetting);
dispatchNewAnimatorScaleLocked(null);
break;
}
}
break;
}
case FORCE_GC: {
synchronized (mWindowMap) {
// Since we're holding both mWindowMap and mAnimator we don't need to
// hold mAnimator.mLayoutToAnim.
if (mAnimator.isAnimating() || mAnimator.isAnimationScheduled()) {
// If we are animating, don't do the gc now but
// delay a bit so we don't interrupt the animation.
sendEmptyMessageDelayed(H.FORCE_GC, 2000);
return;
}
// If we are currently rotating the display, it will
// schedule a new message when done.
if (mDisplayFrozen) {
return;
}
}
Runtime.getRuntime().gc();
break;
}
case ENABLE_SCREEN: {
performEnableScreen();
break;
}
case APP_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
Slog.w(TAG_WM, "App freeze timeout expired.");
mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
for (int i = mAppFreezeListeners.size() - 1; i >=0 ; --i) {
mAppFreezeListeners.get(i).onAppFreezeTimeout();
}
}
break;
}
case CLIENT_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
if (mClientFreezingScreen) {
mClientFreezingScreen = false;
mLastFinishedFreezeSource = "client-timeout";
stopFreezingDisplayLocked();
}
}
break;
}
case SEND_NEW_CONFIGURATION: {
removeMessages(SEND_NEW_CONFIGURATION, msg.obj);
final int displayId = (Integer) msg.obj;
if (mRoot.getDisplayContent(displayId) != null) {
sendNewConfiguration(displayId);
} else {
// Message could come after display has already been removed.
if (DEBUG_CONFIGURATION) {
Slog.w(TAG, "Trying to send configuration to non-existing displayId="
+ displayId);
}
}
break;
}
case REPORT_WINDOWS_CHANGE: {
if (mWindowsChanged) {
synchronized (mWindowMap) {
mWindowsChanged = false;
}
notifyWindowsChanged();
}
break;
}
case DRAG_START_TIMEOUT: {
IBinder win = (IBinder)msg.obj;
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout starting drag by win " + win);
}
synchronized (mWindowMap) {
// !!! TODO: ANR the app that has failed to start the drag in time
if (mDragState != null) {
mDragState.unregister();
mDragState.reset();
mDragState = null;
}
}
break;
}
case DRAG_END_TIMEOUT: {
IBinder win = (IBinder)msg.obj;
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout ending drag to win " + win);
}
synchronized (mWindowMap) {
// !!! TODO: ANR the drag-receiving app
if (mDragState != null) {
mDragState.mDragResult = false;
mDragState.endDragLw();
}
}
break;
}
case TEAR_DOWN_DRAG_AND_DROP_INPUT: {
if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag ending; tearing down input channel");
DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
if (interceptor != null) {
synchronized (mWindowMap) {
interceptor.tearDown();
}
}
}
break;
case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
notifyHardKeyboardStatusChange();
break;
}
case BOOT_TIMEOUT: {
performBootTimeout();
break;
}
case WAITING_FOR_DRAWN_TIMEOUT: {
Runnable callback = null;
synchronized (mWindowMap) {
Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);
mWaitingForDrawn.clear();
callback = mWaitingForDrawnCallback;
mWaitingForDrawnCallback = null;
}
if (callback != null) {
callback.run();
}
break;
}
case SHOW_STRICT_MODE_VIOLATION: {
showStrictModeViolation(msg.arg1, msg.arg2);
break;
}
case SHOW_CIRCULAR_DISPLAY_MASK: {
showCircularMask(msg.arg1 == 1);
break;
}
case SHOW_EMULATOR_DISPLAY_OVERLAY: {
showEmulatorDisplayOverlay();
break;
}
case DO_ANIMATION_CALLBACK: {
try {
((IRemoteCallback)msg.obj).sendResult(null);
} catch (RemoteException e) {
}
break;
}
case TAP_OUTSIDE_TASK: {
handleTapOutsideTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
}
break;
case FINISH_TASK_POSITIONING: {
finishPositioning();
}
break;
case NOTIFY_ACTIVITY_DRAWN:
try {
mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
} catch (RemoteException e) {
}
break;
case ALL_WINDOWS_DRAWN: {
Runnable callback;
synchronized (mWindowMap) {
callback = mWaitingForDrawnCallback;
mWaitingForDrawnCallback = null;
}
if (callback != null) {
callback.run();
}
break;
}
case NEW_ANIMATOR_SCALE: {
float scale = getCurrentAnimatorScale();
ValueAnimator.setDurationScale(scale);
Session session = (Session)msg.obj;
if (session != null) {
try {
session.mCallback.onAnimatorScaleChanged(scale);
} catch (RemoteException e) {
}
} else {
ArrayList<IWindowSessionCallback> callbacks
= new ArrayList<IWindowSessionCallback>();
synchronized (mWindowMap) {
for (int i=0; i<mSessions.size(); i++) {
callbacks.add(mSessions.valueAt(i).mCallback);
}
}
for (int i=0; i<callbacks.size(); i++) {
try {
callbacks.get(i).onAnimatorScaleChanged(scale);
} catch (RemoteException e) {
}
}
}
}
break;
case CHECK_IF_BOOT_ANIMATION_FINISHED: {
final boolean bootAnimationComplete;
synchronized (mWindowMap) {
if (DEBUG_BOOT) Slog.i(TAG_WM, "CHECK_IF_BOOT_ANIMATION_FINISHED:");
bootAnimationComplete = checkBootAnimationCompleteLocked();
}
if (bootAnimationComplete) {
performEnableScreen();
}
}
break;
case RESET_ANR_MESSAGE: {
synchronized (mWindowMap) {
mLastANRState = null;
}
mAmInternal.clearSavedANRState();
}
break;
case WALLPAPER_DRAW_PENDING_TIMEOUT: {
synchronized (mWindowMap) {
if (mRoot.mWallpaperController.processWallpaperDrawPendingTimeout()) {
mWindowPlacerLocked.performSurfacePlacement();
}
}
}
break;
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
displayContent.getDockedDividerController().reevaluateVisibility(false);
displayContent.adjustForImeIfNeeded();
}
}
break;
case WINDOW_REPLACEMENT_TIMEOUT: {
synchronized (mWindowMap) {
for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
final AppWindowToken token = mWindowReplacementTimeouts.get(i);
token.onWindowReplacementTimeout();
}
mWindowReplacementTimeouts.clear();
}
}
break;
case NOTIFY_APP_TRANSITION_STARTING: {
mAmInternal.notifyAppTransitionStarting((SparseIntArray) msg.obj,
msg.getWhen());
}
break;
case NOTIFY_APP_TRANSITION_CANCELLED: {
mAmInternal.notifyAppTransitionCancelled();
}
break;
case NOTIFY_APP_TRANSITION_FINISHED: {
mAmInternal.notifyAppTransitionFinished();
}
break;
case WINDOW_HIDE_TIMEOUT: {
final WindowState window = (WindowState) msg.obj;
synchronized(mWindowMap) {
// TODO: This is all about fixing b/21693547
// where partially initialized Toasts get stuck
// around and keep the screen on. We'd like
// to just remove the toast...but this can cause clients
// who miss the timeout due to normal circumstances (e.g.
// running under debugger) to crash (b/29105388). The windows will
// eventually be removed when the client process finishes.
// The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
// and prevent the symptoms of b/21693547. Since apps don't
// support windows being removed under them we hide the window
// and it will be removed when the app dies.
window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
window.hidePermanentlyLw();
window.setDisplayLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement();
}
}
break;
case NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED: {
mAmInternal.notifyDockedStackMinimizedChanged(msg.arg1 == 1);
}
break;
case RESTORE_POINTER_ICON: {
synchronized (mWindowMap) {
restorePointerIconLocked((DisplayContent)msg.obj, msg.arg1, msg.arg2);
}
}
break;
case SEAMLESS_ROTATION_TIMEOUT: {
// Rotation only supported on primary display.
// TODO(multi-display)
synchronized(mWindowMap) {
final DisplayContent dc = getDefaultDisplayContentLocked();
dc.onSeamlessRotationTimeout();
}
}
break;
case NOTIFY_KEYGUARD_FLAGS_CHANGED: {
mAmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj);
}
break;
case NOTIFY_KEYGUARD_TRUSTED_CHANGED: {
mAmInternal.notifyKeyguardTrustedChanged();
}
break;
case SET_HAS_OVERLAY_UI: {
mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
}
break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
}
}