summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2009-09-01 19:01:50 -0700
committerDianne Hackborn <hackbod@google.com>2009-09-02 17:20:25 -0700
commita8f6018d6c2d28313f9550fa8fcb39c2f607e09c (patch)
treea64e1d3e4b63e2792ab93ee69d913b415925d814
parent14de0880dd7b716f39b822917e874ca5e579ff37 (diff)
downloadframeworks_base-a8f6018d6c2d28313f9550fa8fcb39c2f607e09c.zip
frameworks_base-a8f6018d6c2d28313f9550fa8fcb39c2f607e09c.tar.gz
frameworks_base-a8f6018d6c2d28313f9550fa8fcb39c2f607e09c.tar.bz2
Work on issue #2079167: Flickering issue across multiple UI
This addresses a few parts of the bug: - There was a small issue in the window manager where we could show a window too early before the transition animation starts, which was introduced by the recent wallpaper work. This was the cause of the flicker when starting the dialer for the first time. - There was a much larger problem that has existing forever where moving an application token to the front or back was not synchronized with the application animation transaction. This was the cause of the flicker when hanging up (now that the in-call screen moves to the back instead of closing and we always have a wallpaper visible). The approach to solving this is to have the window manager go ahead and move the app tokens (it must in order to keep in sync with the activity manager), but to delay the actual window movement: perform the movement to front when the animation starts, and to back when it ends. Actually, when the animation ends, we just go and completely rebuild the window list to ensure it is correct, because there can be ways people can add windows while in this intermediate state where they could end up at the wrong place once we do the delayed movement to the front or back. And it is simply reasuring to know that every time we finish a full app transition, we re-evaluate the world and put everything in its proper place. Also included in this change are a few little tweaks to the input system, to perform better logging, and completely ignore input devices that do not have any of our input classes. There is also a little cleanup of evaluating configuration changes to not do more work than needed when an input devices appears or disappears, and to only log a config change message when the config is truly changing. Change-Id: Ifb2db77f8867435121722a6abeb946ec7c3ea9d3
-rw-r--r--libs/ui/EventHub.cpp17
-rw-r--r--services/java/com/android/server/KeyInputQueue.java92
-rw-r--r--services/java/com/android/server/WindowManagerService.java226
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java1
4 files changed, 276 insertions, 60 deletions
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 60c177b..e39a357 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -781,12 +781,21 @@ int EventHub::close_device(const char *deviceName)
if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
//LOGD("remove device %d: %s\n", i, deviceName);
device_t* device = mDevices[i];
- int count = mFDCount - i - 1;
+
+ LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ device->path.string(), device->name.string(), device->id,
+ mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
+
+ // Clear this device's entry.
int index = (device->id&ID_MASK);
mDevicesById[index].device = NULL;
+
+ // Close the file descriptor and compact the fd array.
close(mFDs[i].fd);
+ int count = mFDCount - i - 1;
memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
+ mFDCount--;
#ifdef EV_SW
for (int j=0; j<EV_SW; j++) {
@@ -799,8 +808,6 @@ int EventHub::close_device(const char *deviceName)
device->next = mClosingDevices;
mClosingDevices = device;
- mFDCount--;
-
uint32_t publicID;
if (device->id == mFirstKeyboardId) {
LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
@@ -817,7 +824,7 @@ int EventHub::close_device(const char *deviceName)
return 0;
}
}
- LOGE("remote device: %s not found\n", deviceName);
+ LOGE("remove device: %s not found\n", deviceName);
return -1;
}
@@ -832,7 +839,7 @@ int EventHub::read_notify(int nfd)
int event_pos = 0;
struct inotify_event *event;
-LOGD("EventHub::read_notify nfd: %d\n", nfd);
+ LOGV("EventHub::read_notify nfd: %d\n", nfd);
res = read(nfd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 7ca12f2..244e136 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -54,6 +54,7 @@ public abstract class KeyInputQueue {
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ final SparseArray<InputDevice> mIgnoredDevices = new SparseArray<InputDevice>();
final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
final HapticFeedbackCallback mHapticFeedbackCallback;
@@ -391,26 +392,50 @@ public abstract class KeyInputQueue {
if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
synchronized (mFirst) {
di = newInputDevice(ev.deviceId);
- mDevices.put(ev.deviceId, di);
- if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
- readVirtualKeys(di.name);
+ if (di.classes != 0) {
+ // If this device is some kind of input class,
+ // we care about it.
+ mDevices.put(ev.deviceId, di);
+ if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ readVirtualKeys(di.name);
+ }
+ // The configuration may have changed because
+ // of this device.
+ configChanged = true;
+ } else {
+ // We won't do anything with this device.
+ mIgnoredDevices.put(ev.deviceId, di);
+ Log.i(TAG, "Ignoring non-input device: id=0x"
+ + Integer.toHexString(di.id)
+ + ", name=" + di.name);
}
- configChanged = true;
}
} else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
synchronized (mFirst) {
- Log.i(TAG, "Device removed: id=0x"
- + Integer.toHexString(ev.deviceId));
+ if (false) {
+ Log.i(TAG, "Device removed: id=0x"
+ + Integer.toHexString(ev.deviceId));
+ }
di = mDevices.get(ev.deviceId);
if (di != null) {
mDevices.delete(ev.deviceId);
+ // The configuration may have changed because
+ // of this device.
configChanged = true;
+ } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
+ mIgnoredDevices.remove(ev.deviceId);
} else {
- Log.w(TAG, "Bad device id: " + ev.deviceId);
+ Log.w(TAG, "Removing bad device id: "
+ + Integer.toHexString(ev.deviceId));
+ continue;
}
}
} else {
di = getInputDevice(ev.deviceId);
+ if (di == null) {
+ // This may be some junk from an ignored device.
+ continue;
+ }
// first crack at it
send = preprocessEvent(di, ev);
@@ -422,10 +447,6 @@ public abstract class KeyInputQueue {
}
}
- if (di == null) {
- continue;
- }
-
if (configChanged) {
synchronized (mFirst) {
addLocked(di, System.nanoTime(), 0,
@@ -1056,28 +1077,33 @@ public abstract class KeyInputQueue {
private InputDevice newInputDevice(int deviceId) {
int classes = getDeviceClasses(deviceId);
String name = getDeviceName(deviceId);
- Log.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
- + ", name=" + name
- + ", classes=" + Integer.toHexString(classes));
- InputDevice.AbsoluteInfo absX;
- InputDevice.AbsoluteInfo absY;
- InputDevice.AbsoluteInfo absPressure;
- InputDevice.AbsoluteInfo absSize;
- if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
- absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X");
- absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y");
- absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
- absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
- } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
- absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X");
- absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y");
- absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure");
- absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_TOOL_WIDTH, "Size");
- } else {
- absX = null;
- absY = null;
- absPressure = null;
- absSize = null;
+ InputDevice.AbsoluteInfo absX = null;
+ InputDevice.AbsoluteInfo absY = null;
+ InputDevice.AbsoluteInfo absPressure = null;
+ InputDevice.AbsoluteInfo absSize = null;
+ if (classes != 0) {
+ Log.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
+ + ", name=" + name
+ + ", classes=" + Integer.toHexString(classes));
+ if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
+ absX = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_MT_POSITION_X, "X");
+ absY = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_MT_POSITION_Y, "Y");
+ absPressure = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
+ absSize = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
+ } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ absX = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_X, "X");
+ absY = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_Y, "Y");
+ absPressure = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_PRESSURE, "Pressure");
+ absSize = loadAbsoluteInfo(deviceId,
+ RawInputEvent.ABS_TOOL_WIDTH, "Size");
+ }
}
return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 81e0136..c7c748f 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -375,11 +375,14 @@ public class WindowManagerService extends IWindowManager.Stub
// made visible or hidden at the next transition.
int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
boolean mAppTransitionReady = false;
+ boolean mAppTransitionRunning = false;
boolean mAppTransitionTimeout = false;
boolean mStartingIconInTransition = false;
boolean mSkipAppTransitionAnimation = false;
final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
+ final ArrayList<AppWindowToken> mToTopApps = new ArrayList<AppWindowToken>();
+ final ArrayList<AppWindowToken> mToBottomApps = new ArrayList<AppWindowToken>();
//flag to detect fat touch events
boolean mFatTouch = false;
@@ -690,7 +693,11 @@ public class WindowManagerService extends IWindowManager.Stub
i--;
break;
}
- if (t.windows.size() > 0) {
+
+ // We haven't reached the token yet; if this token
+ // is not going to the bottom and has windows, we can
+ // use it as an anchor for when we do reach the token.
+ if (!t.sendingToBottom && t.windows.size() > 0) {
pos = t.windows.get(0);
}
}
@@ -712,6 +719,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
placeWindowBefore(pos, win);
} else {
+ // Continue looking down until we find the first
+ // token that has windows.
while (i >= 0) {
AppWindowToken t = mAppTokens.get(i);
final int NW = t.windows.size();
@@ -2760,7 +2769,6 @@ public class WindowManagerService extends IWindowManager.Stub
mTempConfiguration.setToDefaults();
if (computeNewConfigurationLocked(mTempConfiguration)) {
if (appConfig.diff(mTempConfiguration) != 0) {
- Log.i(TAG, "Config changed: " + mTempConfiguration);
return new Configuration(mTempConfiguration);
}
}
@@ -3198,12 +3206,14 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.setDummyAnimation();
mOpeningApps.remove(wtoken);
mClosingApps.remove(wtoken);
+ wtoken.waitingToShow = wtoken.waitingToHide = false;
wtoken.inPendingTransaction = true;
if (visible) {
mOpeningApps.add(wtoken);
wtoken.allDrawn = false;
wtoken.startingDisplayed = false;
wtoken.startingMoved = false;
+ wtoken.waitingToShow = true;
if (wtoken.clientHidden) {
// In the case where we are making an app visible
@@ -3217,6 +3227,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
} else {
mClosingApps.add(wtoken);
+ wtoken.waitingToHide = true;
}
return;
}
@@ -3351,10 +3362,12 @@ public class WindowManagerService extends IWindowManager.Stub
delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
wtoken.inPendingTransaction = false;
mOpeningApps.remove(wtoken);
+ wtoken.waitingToShow = false;
if (mClosingApps.contains(wtoken)) {
delayed = true;
} else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
mClosingApps.add(wtoken);
+ wtoken.waitingToHide = true;
delayed = true;
}
if (DEBUG_APP_TRANSITIONS) Log.v(
@@ -3441,6 +3454,12 @@ public class WindowManagerService extends IWindowManager.Stub
final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ "
+ tokenPos + " -- " + wtoken.token);
+ if (wtoken.sendingToBottom) {
+ if (DEBUG_REORDER) Log.v(TAG,
+ "Skipping token -- currently sending to bottom");
+ tokenPos--;
+ continue;
+ }
int i = wtoken.windows.size();
while (i > 0) {
i--;
@@ -3449,7 +3468,7 @@ public class WindowManagerService extends IWindowManager.Stub
while (j > 0) {
j--;
WindowState cwin = (WindowState)win.mChildWindows.get(j);
- if (cwin.mSubLayer >= 0 ) {
+ if (cwin.mSubLayer >= 0) {
for (int pos=NW-1; pos>=0; pos--) {
if (mWindows.get(pos) == cwin) {
if (DEBUG_REORDER) Log.v(TAG,
@@ -3553,6 +3572,26 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ private void moveAppWindowsLocked(AppWindowToken wtoken, int tokenPos,
+ boolean updateFocusAndLayout) {
+ // First remove all of the windows from the list.
+ tmpRemoveAppWindowsLocked(wtoken);
+
+ // Where to start adding?
+ int pos = findWindowOffsetLocked(tokenPos);
+
+ // And now add them back at the correct place.
+ pos = reAddAppWindowsLocked(pos, wtoken);
+
+ if (updateFocusAndLayout) {
+ if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
+ assignLayersLocked();
+ }
+ mLayoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+
private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
// First remove all of the windows from the list.
final int N = tokens.size();
@@ -3575,7 +3614,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
+ if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
+ assignLayersLocked();
+ }
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -3596,9 +3637,19 @@ public class WindowManagerService extends IWindowManager.Stub
AppWindowToken wt = findAppWindowToken(tokens.get(i));
if (wt != null) {
mAppTokens.add(wt);
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ mToTopApps.remove(wt);
+ mToBottomApps.remove(wt);
+ mToTopApps.add(wt);
+ wt.sendingToBottom = false;
+ wt.sendingToTop = true;
+ }
}
}
- moveAppWindowsLocked(tokens, mAppTokens.size());
+
+ if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
+ moveAppWindowsLocked(tokens, mAppTokens.size());
+ }
}
Binder.restoreCallingIdentity(origId);
}
@@ -3618,10 +3669,20 @@ public class WindowManagerService extends IWindowManager.Stub
AppWindowToken wt = findAppWindowToken(tokens.get(i));
if (wt != null) {
mAppTokens.add(pos, wt);
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ mToTopApps.remove(wt);
+ mToBottomApps.remove(wt);
+ mToBottomApps.add(i, wt);
+ wt.sendingToTop = false;
+ wt.sendingToBottom = true;
+ }
pos++;
}
}
- moveAppWindowsLocked(tokens, 0);
+
+ if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
+ moveAppWindowsLocked(tokens, 0);
+ }
}
Binder.restoreCallingIdentity(origId);
}
@@ -4253,19 +4314,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (!computeNewConfigurationLocked(config)) {
return null;
}
- Log.i(TAG, "Config changed: " + config);
- long now = SystemClock.uptimeMillis();
- //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now);
- if (mFreezeGcPending != 0) {
- if (now > (mFreezeGcPending+1000)) {
- //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
- mH.removeMessages(H.FORCE_GC);
- Runtime.getRuntime().gc();
- mFreezeGcPending = now;
- }
- } else {
- mFreezeGcPending = now;
- }
return config;
}
@@ -7213,6 +7261,10 @@ public class WindowManagerService extends IWindowManager.Stub
* of a transition that has not yet been started.
*/
boolean isReadyForDisplay() {
+ if (mRootToken.waitingToShow &&
+ mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ return false;
+ }
final AppWindowToken atoken = mAppToken;
final boolean animating = atoken != null
? (atoken.animation != null) : false;
@@ -7547,6 +7599,22 @@ public class WindowManagerService extends IWindowManager.Stub
// Temporary for finding which tokens no longer have visible windows.
boolean hasVisible;
+ // Set to true when this token is in a pending transaction where it
+ // will be shown.
+ boolean waitingToShow;
+
+ // Set to true when this token is in a pending transaction where it
+ // will be hidden.
+ boolean waitingToHide;
+
+ // Set to true when this token is in a pending transaction where its
+ // windows will be put to the bottom of the list.
+ boolean sendingToBottom;
+
+ // Set to true when this token is in a pending transaction where its
+ // windows will be put to the top of the list.
+ boolean sendingToTop;
+
WindowToken(IBinder _token, int type, boolean _explicit) {
token = _token;
windowType = type;
@@ -7559,6 +7627,12 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(prefix); pw.print("windowType="); pw.print(windowType);
pw.print(" hidden="); pw.print(hidden);
pw.print(" hasVisible="); pw.println(hasVisible);
+ if (waitingToShow || waitingToHide || sendingToBottom || sendingToTop) {
+ pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
+ pw.print(" waitingToHide="); pw.print(waitingToHide);
+ pw.print(" sendingToBottom="); pw.print(sendingToBottom);
+ pw.print(" sendingToTop="); pw.println(sendingToTop);
+ }
}
@Override
@@ -7868,7 +7942,7 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
}
pw.print(prefix); pw.print("groupId="); pw.print(groupId);
- pw.print(" appFullscreen="); pw.println(appFullscreen);
+ pw.print(" appFullscreen="); pw.print(appFullscreen);
pw.print(" requestedOrientation="); pw.println(requestedOrientation);
pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
pw.print(" clientHidden="); pw.print(clientHidden);
@@ -8434,6 +8508,50 @@ public class WindowManagerService extends IWindowManager.Stub
return win;
}
+ final void rebuildAppWindowListLocked() {
+ int NW = mWindows.size();
+ int i;
+
+ // First remove all existing app windows.
+ i=0;
+ while (i < NW) {
+ if (((WindowState)mWindows.get(i)).mAppToken != null) {
+ mWindows.remove(i);
+ NW--;
+ continue;
+ }
+ i++;
+ }
+
+ // Now go through the app tokens and add the windows back in.
+ int NT = mAppTokens.size();
+ i = 0;
+ for (int j=0; j<NT; j++) {
+ AppWindowToken wt = mAppTokens.get(j);
+ final int NTW = wt.windows.size();
+ for (int k=0; k<NTW; k++) {
+ WindowState win = wt.windows.get(k);
+ final int NC = win.mChildWindows.size();
+ int c;
+ for (c=0; c<NC; c++) {
+ WindowState cwin = (WindowState)win.mChildWindows.get(c);
+ if (cwin.mSubLayer >= 0) {
+ break;
+ }
+ mWindows.add(i, cwin);
+ i++;
+ }
+ mWindows.add(i, win);
+ i++;
+ for (; c<NC; c++) {
+ WindowState cwin = (WindowState)win.mChildWindows.get(c);
+ mWindows.add(i, cwin);
+ i++;
+ }
+ }
+ }
+ }
+
private final void assignLayersLocked() {
int N = mWindows.size();
int curBaseLayer = 0;
@@ -8814,12 +8932,30 @@ public class WindowManagerService extends IWindowManager.Stub
}
mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
mAppTransitionReady = false;
+ mAppTransitionRunning = true;
mAppTransitionTimeout = false;
mStartingIconInTransition = false;
mSkipAppTransitionAnimation = false;
mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+ // If there are applications waiting to come to the
+ // top of the stack, now is the time to move their windows.
+ // (Note that we don't do apps going to the bottom
+ // here -- we want to keep their windows in the old
+ // Z-order until the animation completes.)
+ if (mToTopApps.size() > 0) {
+ NN = mAppTokens.size();
+ for (i=0; i<NN; i++) {
+ AppWindowToken wtoken = mAppTokens.get(i);
+ if (wtoken.sendingToTop) {
+ wtoken.sendingToTop = false;
+ moveAppWindowsLocked(wtoken, NN, false);
+ }
+ }
+ mToTopApps.clear();
+ }
+
adjustWallpaperWindowsLocked();
wallpaperMayChange = false;
@@ -8889,6 +9025,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.animation = null;
setTokenVisibilityLocked(wtoken, lp, true, transit, false);
wtoken.updateReportedVisibilityLocked();
+ wtoken.waitingToShow = false;
wtoken.showAllWindowsLocked();
}
NN = mClosingApps.size();
@@ -8900,6 +9037,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.animation = null;
setTokenVisibilityLocked(wtoken, lp, false, transit, false);
wtoken.updateReportedVisibilityLocked();
+ wtoken.waitingToHide = false;
// Force the allDrawn flag, because we want to start
// this guy's animations regardless of whether it's
// gotten drawn.
@@ -8922,10 +9060,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ if (!animating && mAppTransitionRunning) {
+ // We have finished the animation of an app transition. To do
+ // this, we have delayed a lot of operations like showing and
+ // hiding apps, moving apps in Z-order, etc. The app token list
+ // reflects the correct Z-order, but the window list may now
+ // be out of sync with it. So here we will just rebuild the
+ // entire app window list. Fun!
+ mAppTransitionRunning = false;
+ // Clear information about apps that were moving.
+ mToBottomApps.clear();
+
+ rebuildAppWindowListLocked();
+ restart = true;
+ moveInputMethodWindowsIfNeededLocked(false);
+ wallpaperMayChange = true;
+ mLayoutNeeded = true;
+ }
+
if (wallpaperMayChange) {
if (adjustWallpaperWindowsLocked()) {
assignLayersLocked();
}
+ if (mLayoutNeeded) {
+ performLayoutLockedInner();
+ }
}
} while (restart);
@@ -9407,13 +9566,29 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ boolean needRelayout = false;
+
+ if (!animating && mAppTransitionRunning) {
+ // We have finished the animation of an app transition. To do
+ // this, we have delayed a lot of operations like showing and
+ // hiding apps, moving apps in Z-order, etc. The app token list
+ // reflects the correct Z-order, but the window list may now
+ // be out of sync with it. So here we will just rebuild the
+ // entire app window list. Fun!
+ mAppTransitionRunning = false;
+ needRelayout = true;
+ rebuildAppWindowListLocked();
+ // Clear information about apps that were moving.
+ mToBottomApps.clear();
+ }
+
if (focusDisplayed) {
mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
}
if (wallpaperDestroyed) {
- wallpaperDestroyed = adjustWallpaperWindowsLocked();
+ needRelayout = adjustWallpaperWindowsLocked();
}
- if (wallpaperDestroyed) {
+ if (needRelayout) {
requestAnimationLocked(0);
} else if (animating) {
requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
@@ -9909,6 +10084,7 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mNextAppTransition=0x");
pw.print(Integer.toHexString(mNextAppTransition));
pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
+ pw.print(", mAppTransitionRunning="); pw.print(mAppTransitionRunning);
pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
@@ -9918,6 +10094,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (mClosingApps.size() > 0) {
pw.print(" mClosingApps="); pw.println(mClosingApps);
}
+ if (mToTopApps.size() > 0) {
+ pw.print(" mToTopApps="); pw.println(mToTopApps);
+ }
+ if (mToBottomApps.size() > 0) {
+ pw.print(" mToBottomApps="); pw.println(mToBottomApps);
+ }
pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth());
pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
pw.println(" KeyWaiter state:");
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 252a6d2..8ea6699 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12544,6 +12544,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
mConfiguration = newConfig;
+ Log.i(TAG, "Config changed: " + newConfig);
Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
msg.obj = new Configuration(mConfiguration);