OSDN Git Service

Fix activity move between displays
authorAndrii Kulian <akulian@google.com>
Sat, 8 Apr 2017 01:39:32 +0000 (18:39 -0700)
committerAndrii Kulian <akulian@google.com>
Sat, 8 Apr 2017 01:39:32 +0000 (18:39 -0700)
1. ActivityConfigCallback might not have been registered
because DecorView was not yet attached to window and ViewRootImpl
was not available. In this CL the callback is set as soon as a
DecorView is attached to window.
2. When private display was removed from system, its stacks were
moved to bottom in AM but moved to top in WM.
3. When reparenting stack visibility of activities should be updated
before reparenting in WM, because otherwise WM will be resizing
windows that should no longer visible and reporting it to clients.

Bug: 34164473
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testOnMovedToDisplayCallback
Test: #testContentDestroyOnDisplayRemoved
Change-Id: I6ccc27d873d0d60d7650659fb25cbfcaaeb0fd07

core/java/android/app/Activity.java
core/java/android/app/ActivityThread.java
core/java/android/app/Instrumentation.java
core/java/com/android/internal/policy/DecorView.java
core/java/com/android/internal/policy/PhoneWindow.java
services/core/java/com/android/server/am/ActivityStack.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/wm/DisplayContent.java
services/core/java/com/android/server/wm/StackWindowController.java
services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java

index af3bf2a..62a4e45 100644 (file)
@@ -18,6 +18,7 @@ package android.app;
 
 import android.metrics.LogMaker;
 import android.graphics.Rect;
+import android.view.ViewRootImpl.ActivityConfigCallback;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillPopupWindow;
@@ -6778,12 +6779,12 @@ public class Activity extends ContextThemeWrapper
             CharSequence title, Activity parent, String id,
             NonConfigurationInstances lastNonConfigurationInstances,
             Configuration config, String referrer, IVoiceInteractor voiceInteractor,
-            Window window) {
+            Window window, ActivityConfigCallback activityConfigCallback) {
         attachBaseContext(context);
 
         mFragments.attachHost(null /*parent*/);
 
-        mWindow = new PhoneWindow(this, window);
+        mWindow = new PhoneWindow(this, window, activityConfigCallback);
         mWindow.setWindowControllerCallback(this);
         mWindow.setCallback(this);
         mWindow.setOnWindowDismissedCallback(this);
index 7299d6b..80e8527 100644 (file)
@@ -2748,7 +2748,7 @@ public final class ActivityThread {
                 activity.attach(appContext, this, getInstrumentation(), r.token,
                         r.ident, app, r.intent, r.activityInfo, title, r.parent,
                         r.embeddedID, r.lastNonConfigurationInstances, config,
-                        r.referrer, r.voiceInteractor, window);
+                        r.referrer, r.voiceInteractor, window, r.configCallback);
 
                 if (customIntent != null) {
                     activity.mIntent = customIntent;
@@ -3774,12 +3774,6 @@ public final class ActivityThread {
                 if (r.activity.mVisibleFromClient) {
                     r.activity.makeVisible();
                 }
-                final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
-                if (viewRoot != null) {
-                    // TODO: Figure out the best place to set the callback.
-                    // This looks like a place where decor view is already initialized.
-                    viewRoot.setActivityConfigCallback(r.configCallback);
-                }
             }
 
             if (!r.onlyLocalRequest) {
@@ -5147,13 +5141,8 @@ public final class ActivityThread {
             if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r);
             return;
         }
-        final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY;
-        if (movedToDifferentDisplay) {
-            if (r.activity.getDisplay().getDisplayId() == displayId) {
-                throw new IllegalArgumentException("Activity is already on the target display: "
-                        + displayId);
-            }
-        }
+        final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
+                && displayId != r.activity.getDisplay().getDisplayId();
 
         // Perform updates.
         r.overrideConfig = data.overrideConfig;
index f9a3ea7..d546f27 100644 (file)
@@ -1146,10 +1146,11 @@ public class Instrumentation {
             IllegalAccessException {
         Activity activity = (Activity)clazz.newInstance();
         ActivityThread aThread = null;
-        activity.attach(context, aThread, this, token, 0, application, intent,
+        activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
                 info, title, parent, id,
                 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
-                new Configuration(), null, null, null);
+                new Configuration(), null /* referrer */, null /* voiceInteractor */,
+                null /* window */, null /* activityConfigCallback */);
         return activity;
     }
 
index a8e16c9..f1feca3 100644 (file)
@@ -1498,6 +1498,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
             // renderer about it.
             mBackdropFrameRenderer.onConfigurationChange();
         }
+        mWindow.onViewRootImplSet(getViewRootImpl());
     }
 
     @Override
index 6c9280a..7b966de 100644 (file)
@@ -47,6 +47,7 @@ import android.view.ViewGroup;
 import android.view.ViewManager;
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
+import android.view.ViewRootImpl.ActivityConfigCallback;
 import android.view.Window;
 import android.view.WindowManager;
 import com.android.internal.R;
@@ -287,6 +288,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
 
     private boolean mUseDecorContext = false;
 
+    /** @see ViewRootImpl#mActivityConfigCallback */
+    private ActivityConfigCallback mActivityConfigCallback;
+
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService("window"));
@@ -302,7 +306,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
     /**
      * Constructor for main window of an activity.
      */
-    public PhoneWindow(Context context, Window preservedWindow) {
+    public PhoneWindow(Context context, Window preservedWindow,
+            ActivityConfigCallback activityConfigCallback) {
         this(context);
         // Only main activity windows use decor context, all the other windows depend on whatever
         // context that was given to them.
@@ -323,6 +328,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
                 DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
         mSupportsPictureInPicture = forceResizable || context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_PICTURE_IN_PICTURE);
+        mActivityConfigCallback = activityConfigCallback;
     }
 
     @Override
@@ -2060,6 +2066,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
         return mDecor;
     }
 
+    /** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */
+    void onViewRootImplSet(ViewRootImpl viewRoot) {
+        viewRoot.setActivityConfigCallback(mActivityConfigCallback);
+    }
+
     static private final String FOCUSED_ID_TAG = "android:focusedViewId";
     static private final String VIEWS_TAG = "android:views";
     static private final String PANELS_TAG = "android:Panels";
index 51011b5..78887c6 100644 (file)
@@ -489,10 +489,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
     void reparent(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
         removeFromDisplay();
         mTmpRect2.setEmpty();
-        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2);
         postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
         adjustFocusToNextFocusableStackLocked("reparent", true /* allowFocusSelf */);
         mStackSupervisor.resumeFocusedStackTopActivityLocked();
+        // Update visibility of activities before notifying WM. This way it won't try to resize
+        // windows that are no longer visible.
+        mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+                !PRESERVE_WINDOWS);
+        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
     }
 
     /**
index c9bb9e5..68e25c3 100644 (file)
@@ -2775,9 +2775,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
             throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown stackId="
                     + stackId);
         }
-
-        ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
-                !PRESERVE_WINDOWS);
         // TODO(multi-display): resize stacks properly if moved from split-screen.
     }
 
index 21be742..23058bd 100644 (file)
@@ -1662,7 +1662,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         return stack;
     }
 
-    void moveStackToDisplay(TaskStack stack) {
+    void moveStackToDisplay(TaskStack stack, boolean onTop) {
         final DisplayContent prevDc = stack.getDisplayContent();
         if (prevDc == null) {
             throw new IllegalStateException("Trying to move stackId=" + stack.mStackId
@@ -1674,7 +1674,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         }
 
         prevDc.mTaskStackContainers.removeStackFromDisplay(stack);
-        mTaskStackContainers.addStackToDisplay(stack, true /* onTop */);
+        mTaskStackContainers.addStackToDisplay(stack, onTop);
     }
 
     @Override
index 5d0384e..bf024cf 100644 (file)
@@ -100,7 +100,7 @@ public class StackWindowController
         }
     }
 
-    public void reparent(int displayId, Rect outStackBounds) {
+    public void reparent(int displayId, Rect outStackBounds, boolean onTop) {
         synchronized (mWindowMap) {
             if (mContainer == null) {
                 throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId
@@ -113,7 +113,7 @@ public class StackWindowController
                         + " to unknown displayId=" + displayId);
             }
 
-            targetDc.moveStackToDisplay(mContainer);
+            targetDc.moveStackToDisplay(mContainer, onTop);
             getRawBounds(outStackBounds);
         }
     }
index d7d365e..0270bb9 100644 (file)
@@ -181,7 +181,7 @@ public class DisplayContentTests extends WindowTestsBase {
         assertEquals(dc, token.getDisplayContent());
 
         // Move stack to first display.
-        sDisplayContent.moveStackToDisplay(stack);
+        sDisplayContent.moveStackToDisplay(stack, true /* onTop */);
         assertEquals(sDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
         assertEquals(sDisplayContent, stack.getParent().getParent());
         assertEquals(sDisplayContent, stack.getDisplayContent());
index 13098f6..61f7f57 100644 (file)
@@ -103,7 +103,7 @@ public class StackWindowControllerTests extends WindowTestsBase {
         final TaskStack stack2 = stack2Controller.mContainer;
 
         // Reparent
-        stack1Controller.reparent(dc.getDisplayId(), new Rect());
+        stack1Controller.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
         assertEquals(dc, stack1.getDisplayContent());
         final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
         final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);