Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +21 −8 Original line number Diff line number Diff line Loading @@ -1958,10 +1958,10 @@ public final class ActivityStackSupervisor implements DisplayListener { || tempOtherTaskInsetBounds != null); } void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { if (!task.mResizeable) { Slog.w(TAG, "resizeTask: task " + task + " not resizeable."); return; return true; } adjustForMinimalTaskDimensions(task, bounds); Loading @@ -1971,7 +1971,7 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) { // Nothing to do here... return; return true; } if (!mWindowManager.isValidTaskId(task.taskId)) { Loading @@ -1983,7 +1983,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // re-restore the task so it can have the proper stack association. restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID); } return; return true; } // Do not move the task to another stack here. Loading Loading @@ -2012,6 +2012,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); return kept; } private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) { Loading Loading @@ -2169,13 +2170,17 @@ public final class ActivityStackSupervisor implements DisplayListener { } final ActivityRecord topActivity = task.getTopActivity(); if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) { final boolean mightReplaceWindow = StackId.preserveWindowOnTaskMove(stackId) && topActivity != null; if (mightReplaceWindow) { // We are about to relaunch the activity because its configuration changed due to // being maximized, i.e. size change. The activity will first remove the old window // and then add a new one. This call will tell window manager about this, so it can // preserve the old window until the new one is drawn. This prevents having a gap // between the removal and addition, in which no window is visible. We also want the // entrance of the new window to be properly animated. // Note here we always set the replacing window first, as the flags might be needed // during the relaunch. If we end up not doing any relaunch, we clear the flags later. mWindowManager.setReplacingWindow(topActivity.appToken, animate); } final ActivityStack stack = moveTaskToStackUncheckedLocked( Loading @@ -2185,15 +2190,23 @@ public final class ActivityStackSupervisor implements DisplayListener { stack.mNoAnimActivities.add(topActivity); } boolean kept = true; // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID && task.mBounds == null && task.mLastNonFullscreenBounds != null) { resizeTaskLocked(task, task.mLastNonFullscreenBounds, kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) { resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } if (mightReplaceWindow) { // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old // window), we need to clear the replace window settings. Otherwise, we schedule a // timeout to remove the old window if the replacing window is not coming in time. mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept); } // The task might have already been running and its visibility needs to be synchronized with Loading services/core/java/com/android/server/wm/AppWindowToken.java +23 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; Loading Loading @@ -403,12 +404,28 @@ class AppWindowToken extends WindowToken { } } void resetReplacingWindows() { if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken + " of replacing window marks."); for (int i = allAppWindows.size() - 1; i >= 0; i--) { final WindowState w = allAppWindows.get(i); w.resetReplacing(); } } void addWindow(WindowState w) { for (int i = allAppWindows.size() - 1; i >= 0; i--) { WindowState candidate = allAppWindows.get(i); if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null && candidate.getWindowTag().equals(w.getWindowTag().toString())) { candidate.mReplacingWindow = w; // if we got a replacement window, reset the timeout to give drawing more time service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); service.mH.sendMessageDelayed( service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this), WINDOW_REPLACEMENT_TIMEOUT_DURATION); } } allAppWindows.add(w); Loading @@ -424,7 +441,7 @@ class AppWindowToken extends WindowToken { return false; } void clearTimedoutReplaceesLocked() { void clearTimedoutReplacesLocked() { for (int i = allAppWindows.size() - 1; i >= 0; // removeWindowLocked at bottom of loop may remove multiple entries from // allAppWindows if the window to be removed has child windows. It also may Loading @@ -437,7 +454,11 @@ class AppWindowToken extends WindowToken { continue; } candidate.mWillReplaceWindow = false; service.removeWindowLocked(candidate); // Since the window already timed out, remove it immediately now. // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter // delays removal on certain conditions, which will leave the stale window in the // stack and marked mWillReplaceWindow=false, so the window will never be removed. service.removeWindowInnerLocked(candidate); } } Loading services/core/java/com/android/server/wm/WindowManagerService.java +28 −5 Original line number Diff line number Diff line Loading @@ -8106,7 +8106,7 @@ public class WindowManagerService extends IWindowManager.Stub case WINDOW_REPLACEMENT_TIMEOUT: { final AppWindowToken token = (AppWindowToken) msg.obj; synchronized (mWindowMap) { token.clearTimedoutReplaceesLocked(); token.clearTimedoutReplacesLocked(); } } break; Loading Loading @@ -10192,11 +10192,34 @@ public class WindowManagerService extends IWindowManager.Stub } appWindowToken.setReplacingWindows(animate); } } if (appWindowToken != null) { /** * If we're replacing the window, schedule a timer to clear the replaced window * after a timeout, in case the replacing window is not coming. * * If we're not replacing the window, clear the replace window settings of the app. * * @param token Application token for the activity whose window might be replaced. * @param replacing Whether the window is being replaced or not. */ public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) { AppWindowToken appWindowToken = null; synchronized (mWindowMap) { appWindowToken = findAppWindowToken(token); if (appWindowToken == null) { Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " + token); return; } if (replacing) { mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken), mH.sendMessageDelayed( mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken), WINDOW_REPLACEMENT_TIMEOUT_DURATION); } else { appWindowToken.resetReplacingWindows(); } } } Loading services/core/java/com/android/server/wm/WindowState.java +6 −0 Original line number Diff line number Diff line Loading @@ -2363,4 +2363,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { mReplacingWindow = null; mAnimateReplacingWindow = animate; } void resetReplacing() { mWillReplaceWindow = false; mReplacingWindow = null; mAnimateReplacingWindow = false; } } Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +21 −8 Original line number Diff line number Diff line Loading @@ -1958,10 +1958,10 @@ public final class ActivityStackSupervisor implements DisplayListener { || tempOtherTaskInsetBounds != null); } void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { if (!task.mResizeable) { Slog.w(TAG, "resizeTask: task " + task + " not resizeable."); return; return true; } adjustForMinimalTaskDimensions(task, bounds); Loading @@ -1971,7 +1971,7 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) { // Nothing to do here... return; return true; } if (!mWindowManager.isValidTaskId(task.taskId)) { Loading @@ -1983,7 +1983,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // re-restore the task so it can have the proper stack association. restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID); } return; return true; } // Do not move the task to another stack here. Loading Loading @@ -2012,6 +2012,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); return kept; } private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) { Loading Loading @@ -2169,13 +2170,17 @@ public final class ActivityStackSupervisor implements DisplayListener { } final ActivityRecord topActivity = task.getTopActivity(); if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) { final boolean mightReplaceWindow = StackId.preserveWindowOnTaskMove(stackId) && topActivity != null; if (mightReplaceWindow) { // We are about to relaunch the activity because its configuration changed due to // being maximized, i.e. size change. The activity will first remove the old window // and then add a new one. This call will tell window manager about this, so it can // preserve the old window until the new one is drawn. This prevents having a gap // between the removal and addition, in which no window is visible. We also want the // entrance of the new window to be properly animated. // Note here we always set the replacing window first, as the flags might be needed // during the relaunch. If we end up not doing any relaunch, we clear the flags later. mWindowManager.setReplacingWindow(topActivity.appToken, animate); } final ActivityStack stack = moveTaskToStackUncheckedLocked( Loading @@ -2185,15 +2190,23 @@ public final class ActivityStackSupervisor implements DisplayListener { stack.mNoAnimActivities.add(topActivity); } boolean kept = true; // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID && task.mBounds == null && task.mLastNonFullscreenBounds != null) { resizeTaskLocked(task, task.mLastNonFullscreenBounds, kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) { resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } if (mightReplaceWindow) { // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old // window), we need to clear the replace window settings. Otherwise, we schedule a // timeout to remove the old window if the replacing window is not coming in time. mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept); } // The task might have already been running and its visibility needs to be synchronized with Loading
services/core/java/com/android/server/wm/AppWindowToken.java +23 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; Loading Loading @@ -403,12 +404,28 @@ class AppWindowToken extends WindowToken { } } void resetReplacingWindows() { if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken + " of replacing window marks."); for (int i = allAppWindows.size() - 1; i >= 0; i--) { final WindowState w = allAppWindows.get(i); w.resetReplacing(); } } void addWindow(WindowState w) { for (int i = allAppWindows.size() - 1; i >= 0; i--) { WindowState candidate = allAppWindows.get(i); if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null && candidate.getWindowTag().equals(w.getWindowTag().toString())) { candidate.mReplacingWindow = w; // if we got a replacement window, reset the timeout to give drawing more time service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); service.mH.sendMessageDelayed( service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this), WINDOW_REPLACEMENT_TIMEOUT_DURATION); } } allAppWindows.add(w); Loading @@ -424,7 +441,7 @@ class AppWindowToken extends WindowToken { return false; } void clearTimedoutReplaceesLocked() { void clearTimedoutReplacesLocked() { for (int i = allAppWindows.size() - 1; i >= 0; // removeWindowLocked at bottom of loop may remove multiple entries from // allAppWindows if the window to be removed has child windows. It also may Loading @@ -437,7 +454,11 @@ class AppWindowToken extends WindowToken { continue; } candidate.mWillReplaceWindow = false; service.removeWindowLocked(candidate); // Since the window already timed out, remove it immediately now. // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter // delays removal on certain conditions, which will leave the stale window in the // stack and marked mWillReplaceWindow=false, so the window will never be removed. service.removeWindowInnerLocked(candidate); } } Loading
services/core/java/com/android/server/wm/WindowManagerService.java +28 −5 Original line number Diff line number Diff line Loading @@ -8106,7 +8106,7 @@ public class WindowManagerService extends IWindowManager.Stub case WINDOW_REPLACEMENT_TIMEOUT: { final AppWindowToken token = (AppWindowToken) msg.obj; synchronized (mWindowMap) { token.clearTimedoutReplaceesLocked(); token.clearTimedoutReplacesLocked(); } } break; Loading Loading @@ -10192,11 +10192,34 @@ public class WindowManagerService extends IWindowManager.Stub } appWindowToken.setReplacingWindows(animate); } } if (appWindowToken != null) { /** * If we're replacing the window, schedule a timer to clear the replaced window * after a timeout, in case the replacing window is not coming. * * If we're not replacing the window, clear the replace window settings of the app. * * @param token Application token for the activity whose window might be replaced. * @param replacing Whether the window is being replaced or not. */ public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) { AppWindowToken appWindowToken = null; synchronized (mWindowMap) { appWindowToken = findAppWindowToken(token); if (appWindowToken == null) { Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " + token); return; } if (replacing) { mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken), mH.sendMessageDelayed( mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken), WINDOW_REPLACEMENT_TIMEOUT_DURATION); } else { appWindowToken.resetReplacingWindows(); } } } Loading
services/core/java/com/android/server/wm/WindowState.java +6 −0 Original line number Diff line number Diff line Loading @@ -2363,4 +2363,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { mReplacingWindow = null; mAnimateReplacingWindow = animate; } void resetReplacing() { mWillReplaceWindow = false; mReplacingWindow = null; mAnimateReplacingWindow = false; } }