diff --git a/api/test-current.txt b/api/test-current.txt index ec134b57cb77c..0a8f7a59d3b15 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2354,6 +2354,15 @@ package android.widget.inline { package android.window { + public final class DisplayAreaAppearedInfo implements android.os.Parcelable { + ctor public DisplayAreaAppearedInfo(@NonNull android.window.DisplayAreaInfo, @NonNull android.view.SurfaceControl); + method public int describeContents(); + method @NonNull public android.window.DisplayAreaInfo getDisplayAreaInfo(); + method @NonNull public android.view.SurfaceControl getLeash(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + public final class DisplayAreaInfo implements android.os.Parcelable { ctor public DisplayAreaInfo(@NonNull android.window.WindowContainerToken, int, int); method public int describeContents(); @@ -2369,7 +2378,7 @@ package android.window { ctor public DisplayAreaOrganizer(); method public void onDisplayAreaAppeared(@NonNull android.window.DisplayAreaInfo, @NonNull android.view.SurfaceControl); method public void onDisplayAreaVanished(@NonNull android.window.DisplayAreaInfo); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void registerOrganizer(int); + method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List registerOrganizer(int); field public static final int FEATURE_DEFAULT_TASK_CONTAINER = 1; // 0x1 field public static final int FEATURE_ONE_HANDED = 3; // 0x3 field public static final int FEATURE_ROOT = 0; // 0x0 diff --git a/core/java/android/window/DisplayAreaAppearedInfo.aidl b/core/java/android/window/DisplayAreaAppearedInfo.aidl new file mode 100644 index 0000000000000..365f3e56d968f --- /dev/null +++ b/core/java/android/window/DisplayAreaAppearedInfo.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020 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.window; + +/** + * Data object for the DisplayArea info provided when a DisplayArea is presented to an organizer. + * + * @hide + */ +parcelable DisplayAreaAppearedInfo; diff --git a/core/java/android/window/DisplayAreaAppearedInfo.java b/core/java/android/window/DisplayAreaAppearedInfo.java new file mode 100644 index 0000000000000..d33d77d54031d --- /dev/null +++ b/core/java/android/window/DisplayAreaAppearedInfo.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2020 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.window; + +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.SurfaceControl; + +/** + * Data object for the DisplayArea info provided when a DisplayArea is presented to an organizer. + * + * @hide + */ +@TestApi +public final class DisplayAreaAppearedInfo implements Parcelable { + + @NonNull + private final DisplayAreaInfo mDisplayAreaInfo; + + @NonNull + private final SurfaceControl mLeash; + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public DisplayAreaAppearedInfo createFromParcel(Parcel source) { + final DisplayAreaInfo displayAreaInfo = source.readTypedObject(DisplayAreaInfo.CREATOR); + final SurfaceControl leash = source.readTypedObject(SurfaceControl.CREATOR); + return new DisplayAreaAppearedInfo(displayAreaInfo, leash); + } + + @Override + public DisplayAreaAppearedInfo[] newArray(int size) { + return new DisplayAreaAppearedInfo[size]; + } + + }; + + public DisplayAreaAppearedInfo(@NonNull DisplayAreaInfo displayAreaInfo, + @NonNull SurfaceControl leash) { + mDisplayAreaInfo = displayAreaInfo; + mLeash = leash; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mDisplayAreaInfo, flags); + dest.writeTypedObject(mLeash, flags); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * @return the DisplayArea info. + */ + @NonNull + public DisplayAreaInfo getDisplayAreaInfo() { + return mDisplayAreaInfo; + } + + /** + * @return the leash for the DisplayArea. + */ + @NonNull + public SurfaceControl getLeash() { + return mLeash; + } +} diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index 38b2190a57f3c..6ec093e045fae 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -16,12 +16,15 @@ package android.window; +import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.os.RemoteException; import android.view.SurfaceControl; +import java.util.List; + /** * Interface for WindowManager to delegate control of display areas. * @hide @@ -84,10 +87,17 @@ public class DisplayAreaOrganizer extends WindowOrganizer { */ public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1; + /** + * Registers a DisplayAreaOrganizer to manage display areas for a given feature. + * + * @return a list of display areas that should be managed by the organizer. + */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) - public void registerOrganizer(int displayAreaFeature) { + @CallSuper + @NonNull + public List registerOrganizer(int displayAreaFeature) { try { - getController().registerOrganizer(mInterface, displayAreaFeature); + return getController().registerOrganizer(mInterface, displayAreaFeature).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -97,6 +107,7 @@ public class DisplayAreaOrganizer extends WindowOrganizer { * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + @CallSuper public void unregisterOrganizer() { try { getController().unregisterOrganizer(mInterface); @@ -105,6 +116,11 @@ public class DisplayAreaOrganizer extends WindowOrganizer { } } + /** + * Called when a DisplayArea of the registered window type can be controlled by this organizer. + * It will not be called for the DisplayAreas that exist when {@link #registerOrganizer(int)} is + * called. + */ public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo, @NonNull SurfaceControl leash) {} diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl index 41b9d027344ea..8943847073c7d 100644 --- a/core/java/android/window/IDisplayAreaOrganizerController.aidl +++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl @@ -16,13 +16,20 @@ package android.window; +import android.content.pm.ParceledListSlice; +import android.window.DisplayAreaAppearedInfo; import android.window.IDisplayAreaOrganizer; /** @hide */ interface IDisplayAreaOrganizerController { - /** Register a DisplayAreaOrganizer to manage display areas for a given feature. */ - void registerOrganizer(in IDisplayAreaOrganizer organizer, int displayAreaFeature); + /** + * Registers a DisplayAreaOrganizer to manage display areas for a given feature. + * + * @return a list of display areas that should be managed by the organizer. + */ + ParceledListSlice registerOrganizer(in IDisplayAreaOrganizer organizer, + int displayAreaFeature); /** * Unregisters a previously registered display area organizer. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 17418f9346912..bd6c1e096d013 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -30,6 +30,7 @@ import android.os.SystemProperties; import android.util.ArrayMap; import android.util.Log; import android.view.SurfaceControl; +import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; import android.window.WindowContainerTransaction; @@ -188,6 +189,17 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { } } + @Override + public List registerOrganizer(int displayAreaFeature) { + final List displayAreaInfos = + super.registerOrganizer(displayAreaFeature); + for (int i = 0; i < displayAreaInfos.size(); i++) { + final DisplayAreaAppearedInfo info = displayAreaInfos.get(i); + onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash()); + } + return displayAreaInfos; + } + @Override public void unregisterOrganizer() { super.unregisterOrganizer(); diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 5e1a26b918636..ce20dbdb29977 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -397,6 +397,10 @@ public class DisplayArea extends WindowContainer { } void setOrganizer(IDisplayAreaOrganizer organizer) { + setOrganizer(organizer, false /* skipDisplayAreaAppeared */); + } + + void setOrganizer(IDisplayAreaOrganizer organizer, boolean skipDisplayAreaAppeared) { if (mOrganizer == organizer) return; IDisplayAreaOrganizer lastOrganizer = mOrganizer; // Update the new display area organizer before calling sendDisplayAreaVanished since it @@ -404,7 +408,9 @@ public class DisplayArea extends WindowContainer { // about it. mOrganizer = organizer; sendDisplayAreaVanished(lastOrganizer); - sendDisplayAreaAppeared(); + if (!skipDisplayAreaAppeared) { + sendDisplayAreaAppeared(); + } } void sendDisplayAreaAppeared() { diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java index 667f3dc9d8d34..43b9a218d072d 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java @@ -18,16 +18,20 @@ package com.android.server.wm; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; +import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; +import android.window.DisplayAreaAppearedInfo; import android.window.IDisplayAreaOrganizer; import android.window.IDisplayAreaOrganizerController; import com.android.internal.protolog.common.ProtoLog; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub { private static final String TAG = "DisplayAreaOrganizerController"; @@ -64,7 +68,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } @Override - public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) { + public ParceledListSlice registerOrganizer( + IDisplayAreaOrganizer organizer, int feature) { enforceTaskPermission("registerOrganizer()"); final long uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); @@ -83,12 +88,18 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } catch (RemoteException e) { // Oh well... } + + final List displayAreaInfos = new ArrayList<>(); mService.mRootWindowContainer.forAllDisplayAreas((da) -> { if (da.mFeatureId != feature) return; - da.setOrganizer(organizer); + da.setOrganizer(organizer, true /* skipDisplayAreaAppeared */); + displayAreaInfos.add(new DisplayAreaAppearedInfo(da.getDisplayAreaInfo(), + new SurfaceControl(da.getSurfaceControl(), + "DisplayAreaOrganizerController.registerOrganizer"))); }); mOrganizersByFeatureIds.put(feature, organizer); + return new ParceledListSlice<>(displayAreaInfos); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java index 54b2b3b4a0098..3220d1d6a990a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java @@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,6 +32,7 @@ import android.os.Binder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; +import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.IDisplayAreaOrganizer; @@ -41,6 +43,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.List; + /** * Build/Install/Run: * atest WmTests:DisplayAreaOrganizerTest @@ -88,28 +92,40 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase { .unregisterOrganizer(organizer); } + @Test + public void testRegisterOrganizer() throws RemoteException { + IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder()); + List infos = mWm.mAtmService.mWindowOrganizerController + .mDisplayAreaOrganizerController + .registerOrganizer(organizer, FEATURE_VENDOR_FIRST).getList(); + + // Return a list contains the DA, and no onDisplayAreaAppeared triggered. + assertThat(infos).hasSize(1); + assertThat(infos.get(0).getDisplayAreaInfo().token) + .isEqualTo(mTestDisplayArea.getDisplayAreaInfo().token); + verify(organizer, never()).onDisplayAreaAppeared(any(DisplayAreaInfo.class), + any(SurfaceControl.class)); + } + @Test public void testAppearedVanished() throws RemoteException { IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST); - verify(organizer) - .onDisplayAreaAppeared(any(DisplayAreaInfo.class), any(SurfaceControl.class)); - unregisterMockOrganizer(organizer); + verify(organizer).onDisplayAreaVanished(any()); } @Test public void testChanged() throws RemoteException { IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST); - verify(organizer) - .onDisplayAreaAppeared(any(DisplayAreaInfo.class), any(SurfaceControl.class)); - mDisplayContent.setBounds(new Rect(0, 0, 1000, 1000)); + verify(organizer).onDisplayAreaInfoChanged(any()); Configuration tmpConfiguration = new Configuration(); tmpConfiguration.setTo(mDisplayContent.getRequestedOverrideConfiguration()); mDisplayContent.onRequestedOverrideConfigurationChanged(tmpConfiguration); + // Ensure it was still only called once if the bounds didn't change verify(organizer).onDisplayAreaInfoChanged(any()); }