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
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;
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);
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;
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) {
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;
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;
}
// renderer about it.
mBackdropFrameRenderer.onConfigurationChange();
}
+ mWindow.onViewRootImplSet(getViewRootImpl());
}
@Override
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;
private boolean mUseDecorContext = false;
+ /** @see ViewRootImpl#mActivityConfigCallback */
+ private ActivityConfigCallback mActivityConfigCallback;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
/**
* 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.
DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
mSupportsPictureInPicture = forceResizable || context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE);
+ mActivityConfigCallback = activityConfigCallback;
}
@Override
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";
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);
}
/**
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.
}
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
}
prevDc.mTaskStackContainers.removeStackFromDisplay(stack);
- mTaskStackContainers.addStackToDisplay(stack, true /* onTop */);
+ mTaskStackContainers.addStackToDisplay(stack, onTop);
}
@Override
}
}
- 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
+ " to unknown displayId=" + displayId);
}
- targetDc.moveStackToDisplay(mContainer);
+ targetDc.moveStackToDisplay(mContainer, onTop);
getRawBounds(outStackBounds);
}
}
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());
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);