Skip to content

Commit 82352f9

Browse files
Evan RoskyAndroid (Google) Code Review
authored andcommitted
Merge "Use boundsChangeTransaction to improve split-screen enter/exit" into rvc-dev
2 parents 4c65d2c + 3613854 commit 82352f9

9 files changed

Lines changed: 406 additions & 68 deletions

File tree

core/java/android/view/WindowlessWindowManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,11 @@ private boolean isOpaque(WindowManager.LayoutParams attrs) {
209209

210210
/** @hide */
211211
protected SurfaceControl getSurfaceControl(View rootView) {
212-
final State s = mStateForWindow.get(rootView.getViewRootImpl().mWindow.asBinder());
212+
final ViewRootImpl root = rootView.getViewRootImpl();
213+
if (root == null) {
214+
return null;
215+
}
216+
final State s = mStateForWindow.get(root.mWindow.asBinder());
213217
if (s == null) {
214218
return null;
215219
}

core/java/android/window/WindowContainerTransaction.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,29 @@ public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, b
264264
return this;
265265
}
266266

267+
/**
268+
* Merges another WCT into this one.
269+
* @param transfer When true, this will transfer everything from other potentially leaving
270+
* other in an unusable state. When false, other is left alone, but
271+
* SurfaceFlinger Transactions will not be merged.
272+
* @hide
273+
*/
274+
public void merge(WindowContainerTransaction other, boolean transfer) {
275+
for (int i = 0, n = other.mChanges.size(); i < n; ++i) {
276+
final IBinder key = other.mChanges.keyAt(i);
277+
Change existing = mChanges.get(key);
278+
if (existing == null) {
279+
existing = new Change();
280+
mChanges.put(key, existing);
281+
}
282+
existing.merge(other.mChanges.valueAt(i), transfer);
283+
}
284+
for (int i = 0, n = other.mHierarchyOps.size(); i < n; ++i) {
285+
mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i)
286+
: new HierarchyOp(other.mHierarchyOps.get(i)));
287+
}
288+
}
289+
267290
/** @hide */
268291
public Map<IBinder, Change> getChanges() {
269292
return mChanges;
@@ -359,6 +382,41 @@ protected Change(Parcel in) {
359382
mActivityWindowingMode = in.readInt();
360383
}
361384

385+
/**
386+
* @param transfer When true, this will transfer other into this leaving other in an
387+
* undefined state. Use this if you don't intend to use other. When false,
388+
* SurfaceFlinger Transactions will not merge.
389+
*/
390+
public void merge(Change other, boolean transfer) {
391+
mConfiguration.setTo(other.mConfiguration, other.mConfigSetMask, other.mWindowSetMask);
392+
mConfigSetMask |= other.mConfigSetMask;
393+
mWindowSetMask |= other.mWindowSetMask;
394+
if ((other.mChangeMask & CHANGE_FOCUSABLE) != 0) {
395+
mFocusable = other.mFocusable;
396+
}
397+
if (transfer && (other.mChangeMask & CHANGE_BOUNDS_TRANSACTION) != 0) {
398+
mBoundsChangeTransaction = other.mBoundsChangeTransaction;
399+
other.mBoundsChangeTransaction = null;
400+
}
401+
if ((other.mChangeMask & CHANGE_PIP_CALLBACK) != 0) {
402+
mPinnedBounds = transfer ? other.mPinnedBounds : new Rect(other.mPinnedBounds);
403+
}
404+
if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
405+
mHidden = other.mHidden;
406+
}
407+
mChangeMask |= other.mChangeMask;
408+
if (other.mActivityWindowingMode >= 0) {
409+
mActivityWindowingMode = other.mActivityWindowingMode;
410+
}
411+
if (other.mWindowingMode >= 0) {
412+
mWindowingMode = other.mWindowingMode;
413+
}
414+
if (other.mBoundsChangeSurfaceBounds != null) {
415+
mBoundsChangeSurfaceBounds = transfer ? other.mBoundsChangeSurfaceBounds
416+
: new Rect(other.mBoundsChangeSurfaceBounds);
417+
}
418+
}
419+
362420
public int getWindowingMode() {
363421
return mWindowingMode;
364422
}
@@ -522,6 +580,12 @@ public HierarchyOp(@NonNull IBinder container, boolean toTop) {
522580
mToTop = toTop;
523581
}
524582

583+
public HierarchyOp(@NonNull HierarchyOp copy) {
584+
mContainer = copy.mContainer;
585+
mReparent = copy.mReparent;
586+
mToTop = copy.mToTop;
587+
}
588+
525589
protected HierarchyOp(Parcel in) {
526590
mContainer = in.readStrongBinder();
527591
mReparent = in.readStrongBinder();

packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,19 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
9999
private Handler mHandler;
100100
private KeyguardStateController mKeyguardStateController;
101101

102+
private WindowManagerProxy mWindowManagerProxy;
103+
102104
private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
103105
new ArrayList<>();
104106

105107
private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
106108

107109
private DisplayChangeController.OnDisplayChangingListener mRotationController =
108-
(display, fromRotation, toRotation, t) -> {
109-
if (!mSplits.isSplitScreenSupported()) {
110+
(display, fromRotation, toRotation, wct) -> {
111+
if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
110112
return;
111113
}
114+
WindowContainerTransaction t = new WindowContainerTransaction();
112115
DisplayLayout displayLayout =
113116
new DisplayLayout(mDisplayController.getDisplayLayout(display));
114117
SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
@@ -127,6 +130,17 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
127130
if (isSplitActive()) {
128131
WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
129132
}
133+
if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
134+
// Because sync transactions are serialized, its possible for an "older"
135+
// bounds-change to get applied after a screen rotation. In that case, we
136+
// want to actually defer on that rather than apply immediately. Of course,
137+
// this means that the bounds may not change until after the rotation so
138+
// the user might see some artifacts. This should be rare.
139+
Slog.w(TAG, "Screen rotated while other operations were pending, this may"
140+
+ " result in some graphical artifacts.");
141+
} else {
142+
wct.merge(t, true /* transfer */);
143+
}
130144
};
131145

132146
private final DividerImeController mImePositionProcessor;
@@ -159,6 +173,7 @@ public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
159173
mRecentsOptionalLazy = recentsOptionalLazy;
160174
mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
161175
mTransactionPool = transactionPool;
176+
mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
162177
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
163178
}
164179

@@ -278,9 +293,9 @@ private void addDivider(Configuration configuration) {
278293
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
279294
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
280295
mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
281-
mImePositionProcessor);
296+
mImePositionProcessor, mWindowManagerProxy);
282297
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
283-
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
298+
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
284299
final int size = dctx.getResources().getDimensionPixelSize(
285300
com.android.internal.R.dimen.docked_stack_divider_thickness);
286301
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
@@ -303,7 +318,7 @@ private void update(Configuration configuration) {
303318
addDivider(configuration);
304319

305320
if (mMinimized) {
306-
mView.setMinimizedDockStack(true, mHomeStackResizable);
321+
mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
307322
updateTouchable();
308323
}
309324
mView.setHidden(isDividerHidden);
@@ -327,11 +342,13 @@ private void updateVisibility(final boolean visible) {
327342
if (visible) {
328343
mView.enterSplitMode(mHomeStackResizable);
329344
// Update state because animations won't finish.
330-
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
345+
mWindowManagerProxy.runInSync(
346+
t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
347+
331348
} else {
332349
mView.exitSplitMode();
333-
// un-minimize so that next entry triggers minimize anim.
334-
mView.setMinimizedDockStack(false /* minimized */, mHomeStackResizable);
350+
mWindowManagerProxy.runInSync(
351+
t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
335352
}
336353
// Notify existence listeners
337354
synchronized (mDockedStackExistsListeners) {
@@ -344,12 +361,6 @@ private void updateVisibility(final boolean visible) {
344361
}
345362
}
346363

347-
void onSplitDismissed() {
348-
updateVisibility(false /* visible */);
349-
mMinimized = false;
350-
removeDivider();
351-
}
352-
353364
/** Switch to minimized state if appropriate */
354365
public void setMinimized(final boolean minimized) {
355366
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
@@ -405,7 +416,7 @@ private void setHomeMinimized(final boolean minimized, boolean homeStackResizabl
405416
}
406417
}
407418
updateTouchable();
408-
WindowOrganizer.applyTransaction(wct);
419+
mWindowManagerProxy.applySyncTransaction(wct);
409420
}
410421

411422
void setAdjustedForIme(boolean adjustedForIme) {
@@ -501,7 +512,14 @@ void startEnterSplit() {
501512
update(mDisplayController.getDisplayContext(
502513
mContext.getDisplayId()).getResources().getConfiguration());
503514
// Set resizable directly here because applyEnterSplit already resizes home stack.
504-
mHomeStackResizable = WindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
515+
mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
516+
}
517+
518+
void startDismissSplit() {
519+
mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
520+
updateVisibility(false /* visible */);
521+
mMinimized = false;
522+
removeDivider();
505523
}
506524

507525
void ensureMinimizedSplit() {
@@ -530,6 +548,10 @@ SplitDisplayLayout getSplitLayout() {
530548
return mSplitLayout;
531549
}
532550

551+
WindowManagerProxy getWmProxy() {
552+
return mWindowManagerProxy;
553+
}
554+
533555
/** @return the container token for the secondary split root task. */
534556
public WindowContainerToken getSecondaryRoot() {
535557
if (mSplits == null || mSplits.mSecondary == null) {

packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import android.window.TaskOrganizer;
3030
import android.window.WindowContainerToken;
3131
import android.window.WindowContainerTransaction;
32-
import android.window.WindowOrganizer;
3332

3433
import androidx.annotation.Nullable;
3534

@@ -213,7 +212,7 @@ private void updateImeAdjustState() {
213212
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
214213
}
215214

216-
WindowOrganizer.applyTransaction(wct);
215+
mSplits.mDivider.getWmProxy().applySyncTransaction(wct);
217216

218217
// Update all the adjusted-for-ime states
219218
if (!mPaused) {

0 commit comments

Comments
 (0)