diff options
7 files changed, 322 insertions, 19 deletions
diff --git a/core/java/android/app/servertransaction/WindowStateResizeItem.java b/core/java/android/app/servertransaction/WindowStateResizeItem.java new file mode 100644 index 000000000000..98281338872b --- /dev/null +++ b/core/java/android/app/servertransaction/WindowStateResizeItem.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.servertransaction; + +import static android.view.Display.INVALID_DISPLAY; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ClientTransactionHandler; +import android.os.Parcel; +import android.os.RemoteException; +import android.util.MergedConfiguration; +import android.view.IWindow; +import android.view.InsetsState; +import android.window.ClientWindowFrames; + +import java.util.Objects; + +/** + * Message to deliver window resize info. + * @hide + */ +public class WindowStateResizeItem extends ClientTransactionItem { + + private IWindow mWindow; + private ClientWindowFrames mFrames; + private boolean mReportDraw; + private MergedConfiguration mConfiguration; + private InsetsState mInsetsState; + private boolean mForceLayout; + private boolean mAlwaysConsumeSystemBars; + private int mDisplayId; + private int mSyncSeqId; + private boolean mDragResizing; + + @Override + public void execute(@NonNull ClientTransactionHandler client, + @NonNull PendingTransactionActions pendingActions) { + try { + mWindow.resized(mFrames, mReportDraw, mConfiguration, mInsetsState, mForceLayout, + mAlwaysConsumeSystemBars, mDisplayId, mSyncSeqId, mDragResizing); + } catch (RemoteException e) { + // Should be a local call. + throw new RuntimeException(e); + } + } + + // ObjectPoolItem implementation + + private WindowStateResizeItem() {} + + /** Obtains an instance initialized with provided params. */ + public static WindowStateResizeItem obtain(@NonNull IWindow window, + @NonNull ClientWindowFrames frames, boolean reportDraw, + @NonNull MergedConfiguration configuration, @NonNull InsetsState insetsState, + boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, + boolean dragResizing) { + WindowStateResizeItem instance = + ObjectPool.obtain(WindowStateResizeItem.class); + if (instance == null) { + instance = new WindowStateResizeItem(); + } + instance.mWindow = requireNonNull(window); + instance.mFrames = requireNonNull(frames); + instance.mReportDraw = reportDraw; + instance.mConfiguration = requireNonNull(configuration); + instance.mInsetsState = requireNonNull(insetsState); + instance.mForceLayout = forceLayout; + instance.mAlwaysConsumeSystemBars = alwaysConsumeSystemBars; + instance.mDisplayId = displayId; + instance.mSyncSeqId = syncSeqId; + instance.mDragResizing = dragResizing; + + return instance; + } + + @Override + public void recycle() { + mWindow = null; + mFrames = null; + mReportDraw = false; + mConfiguration = null; + mInsetsState = null; + mForceLayout = false; + mAlwaysConsumeSystemBars = false; + mDisplayId = INVALID_DISPLAY; + mSyncSeqId = -1; + mDragResizing = false; + ObjectPool.recycle(this); + } + + // Parcelable implementation + + /** Writes to Parcel. */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mWindow.asBinder()); + dest.writeTypedObject(mFrames, flags); + dest.writeBoolean(mReportDraw); + dest.writeTypedObject(mConfiguration, flags); + dest.writeTypedObject(mInsetsState, flags); + dest.writeBoolean(mForceLayout); + dest.writeBoolean(mAlwaysConsumeSystemBars); + dest.writeInt(mDisplayId); + dest.writeInt(mSyncSeqId); + dest.writeBoolean(mDragResizing); + } + + /** Reads from Parcel. */ + private WindowStateResizeItem(@NonNull Parcel in) { + mWindow = IWindow.Stub.asInterface(in.readStrongBinder()); + mFrames = in.readTypedObject(ClientWindowFrames.CREATOR); + mReportDraw = in.readBoolean(); + mConfiguration = in.readTypedObject(MergedConfiguration.CREATOR); + mInsetsState = in.readTypedObject(InsetsState.CREATOR); + mForceLayout = in.readBoolean(); + mAlwaysConsumeSystemBars = in.readBoolean(); + mDisplayId = in.readInt(); + mSyncSeqId = in.readInt(); + mDragResizing = in.readBoolean(); + } + + public static final @NonNull Creator<WindowStateResizeItem> CREATOR = new Creator<>() { + public WindowStateResizeItem createFromParcel(@NonNull Parcel in) { + return new WindowStateResizeItem(in); + } + + public WindowStateResizeItem[] newArray(int size) { + return new WindowStateResizeItem[size]; + } + }; + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final WindowStateResizeItem other = (WindowStateResizeItem) o; + return Objects.equals(mWindow, other.mWindow) + && Objects.equals(mFrames, other.mFrames) + && mReportDraw == other.mReportDraw + && Objects.equals(mConfiguration, other.mConfiguration) + && Objects.equals(mInsetsState, other.mInsetsState) + && mForceLayout == other.mForceLayout + && mAlwaysConsumeSystemBars == other.mAlwaysConsumeSystemBars + && mDisplayId == other.mDisplayId + && mSyncSeqId == other.mSyncSeqId + && mDragResizing == other.mDragResizing; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + Objects.hashCode(mWindow); + result = 31 * result + Objects.hashCode(mFrames); + result = 31 * result + (mReportDraw ? 1 : 0); + result = 31 * result + Objects.hashCode(mConfiguration); + result = 31 * result + Objects.hashCode(mInsetsState); + result = 31 * result + (mForceLayout ? 1 : 0); + result = 31 * result + (mAlwaysConsumeSystemBars ? 1 : 0); + result = 31 * result + mDisplayId; + result = 31 * result + mSyncSeqId; + result = 31 * result + (mDragResizing ? 1 : 0); + return result; + } + + @Override + public String toString() { + return "WindowStateResizeItem{window=" + mWindow + + ", reportDrawn=" + mReportDraw + + ", configuration=" + mConfiguration + + "}"; + } +} diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index d554514349c3..11180aef4479 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -54,6 +54,10 @@ oneway interface IWindow { */ void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor); + /** + * Please dispatch through WindowStateResizeItem instead of directly calling this method from + * the system server. + */ void resized(in ClientWindowFrames frames, boolean reportDraw, in MergedConfiguration newMergedConfiguration, in InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index cf46bcccdf87..0fd7c0db1687 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -10521,6 +10521,8 @@ public final class ViewRootImpl implements ViewParent, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) { + // Although this is a AIDL method, it will only be triggered in local process through + // either WindowStateResizeItem or WindowlessWindowManager. final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState, diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index ec5d4ff16ee5..24dc6dbfede8 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -22,3 +22,10 @@ flag { description: "Whether the TaskFragment system organizer feature is enabled" bug: "284050041" } + +flag { + namespace: "windowing_sdk" + name: "window_state_resize_item_flag" + description: "Whether to dispatch window resize through ClientTransaction is enabled" + bug: "301870955" +} diff --git a/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java new file mode 100644 index 000000000000..c00eb91d752a --- /dev/null +++ b/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.servertransaction; + +import static org.mockito.Mockito.verify; + +import android.app.ClientTransactionHandler; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.util.MergedConfiguration; +import android.view.IWindow; +import android.view.InsetsState; +import android.window.ClientWindowFrames; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link WindowStateResizeItem}. + * + * Build/Install/Run: + * atest FrameworksCoreTests:WindowStateResizeItemTest + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class WindowStateResizeItemTest { + + @Mock + private ClientTransactionHandler mHandler; + @Mock + private PendingTransactionActions mPendingActions; + @Mock + private IWindow mWindow; + @Mock + private ClientWindowFrames mFrames; + @Mock + private MergedConfiguration mConfiguration; + @Mock + private InsetsState mInsetsState; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testExecute() throws RemoteException { + final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames, + true /* reportDraw */, mConfiguration, mInsetsState, true /* forceLayout */, + true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, + true /* dragResizing */); + item.execute(mHandler, mPendingActions); + + verify(mWindow).resized(mFrames, + true /* reportDraw */, mConfiguration, mInsetsState, true /* forceLayout */, + true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, + true /* dragResizing */); + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java index 00b9b4c490a4..5b9acb2f67c4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerFlags.java +++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java @@ -45,5 +45,7 @@ class WindowManagerFlags { final boolean mSyncWindowConfigUpdateFlag = Flags.syncWindowConfigUpdateFlag(); + final boolean mWindowStateResizeItemFlag = Flags.windowStateResizeItemFlag(); + /* End Available Flags */ } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 4beec2bc79e6..726d4d7c34e7 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -186,6 +186,7 @@ import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.admin.DevicePolicyCache; +import android.app.servertransaction.WindowStateResizeItem; import android.content.Context; import android.content.res.Configuration; import android.graphics.Matrix; @@ -3732,30 +3733,44 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP markRedrawForSyncReported(); - try { - mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration, - getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId, - syncWithBuffers ? mSyncSeqId : -1, isDragResizing); - if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration - .getMergedConfiguration().windowConfiguration.getRotation()) { - mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime(); - ProtoLog.v(WM_DEBUG_ORIENTATION, - "Requested redraw for orientation change: %s", this); - } - - if (mWmService.mAccessibilityController.hasCallbacks()) { - mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(displayId); + if (mWmService.mFlags.mWindowStateResizeItemFlag) { + getProcess().scheduleClientTransactionItem( + WindowStateResizeItem.obtain(mClient, mClientWindowFrames, reportDraw, + mLastReportedConfiguration, getCompatInsetsState(), forceRelayout, + alwaysConsumeSystemBars, displayId, + syncWithBuffers ? mSyncSeqId : -1, isDragResizing)); + onResizePostDispatched(drawPending, prevRotation, displayId); + } else { + // TODO(b/301870955): cleanup after launch + try { + mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration, + getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId, + syncWithBuffers ? mSyncSeqId : -1, isDragResizing); + onResizePostDispatched(drawPending, prevRotation, displayId); + } catch (RemoteException e) { + // Cancel orientation change of this window to avoid blocking unfreeze display. + setOrientationChanging(false); + mLastFreezeDuration = (int) (SystemClock.elapsedRealtime() + - mWmService.mDisplayFreezeTime); + Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e); } - } catch (RemoteException e) { - // Cancel orientation change of this window to avoid blocking unfreeze display. - setOrientationChanging(false); - mLastFreezeDuration = (int)(SystemClock.elapsedRealtime() - - mWmService.mDisplayFreezeTime); - Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + private void onResizePostDispatched(boolean drawPending, int prevRotation, int displayId) { + if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration + .getMergedConfiguration().windowConfiguration.getRotation()) { + mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime(); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Requested redraw for orientation change: %s", this); + } + + if (mWmService.mAccessibilityController.hasCallbacks()) { + mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(displayId); + } + } + boolean inRelaunchingActivity() { return mActivityRecord != null && mActivityRecord.isRelaunching(); } |