Merge "Migrate WindowContext#onConfigurationChanged to ClientTransaction (7/n)" into main
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 58c2548..a09d7dc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -203,6 +203,7 @@
import android.window.SizeConfigurationBuckets;
import android.window.SplashScreen;
import android.window.SplashScreenView;
+import android.window.WindowContextInfo;
import android.window.WindowProviderService;
import android.window.WindowTokenClientController;
@@ -6248,10 +6249,9 @@
}
@Override
- public void handleWindowContextConfigurationChanged(@NonNull IBinder clientToken,
- @NonNull Configuration configuration, int displayId) {
- WindowTokenClientController.getInstance().onWindowContextConfigurationChanged(clientToken,
- configuration, displayId);
+ public void handleWindowContextInfoChanged(@NonNull IBinder clientToken,
+ @NonNull WindowContextInfo info) {
+ WindowTokenClientController.getInstance().onWindowContextInfoChanged(clientToken, info);
}
@Override
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index f7a43f4..6753cb8 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -28,6 +28,7 @@
import android.util.MergedConfiguration;
import android.view.SurfaceControl;
import android.window.SplashScreenView.SplashScreenViewParcelable;
+import android.window.WindowContextInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
@@ -163,9 +164,9 @@
public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
Configuration overrideConfig, int displayId);
- /** Deliver {@link android.window.WindowContext} configuration change. */
- public abstract void handleWindowContextConfigurationChanged(@NonNull IBinder clientToken,
- @NonNull Configuration configuration, int displayId);
+ /** Deliver {@link android.window.WindowContextInfo} change. */
+ public abstract void handleWindowContextInfoChanged(@NonNull IBinder clientToken,
+ @NonNull WindowContextInfo info);
/** Deliver {@link android.window.WindowContext} window removal event. */
public abstract void handleWindowContextWindowRemoval(@NonNull IBinder clientToken);
diff --git a/core/java/android/app/servertransaction/WindowContextConfigurationChangeItem.java b/core/java/android/app/servertransaction/WindowContextConfigurationChangeItem.java
deleted file mode 100644
index 3ac642f..0000000
--- a/core/java/android/app/servertransaction/WindowContextConfigurationChangeItem.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.content.res.Configuration;
-import android.os.IBinder;
-import android.os.Parcel;
-
-import java.util.Objects;
-
-/**
- * {@link android.window.WindowContext} configuration change message.
- * @hide
- */
-public class WindowContextConfigurationChangeItem extends ClientTransactionItem {
-
- @Nullable
- private IBinder mClientToken;
- @Nullable
- private Configuration mConfiguration;
- private int mDisplayId;
-
- @Override
- public void execute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
- @NonNull PendingTransactionActions pendingActions) {
- client.handleWindowContextConfigurationChanged(mClientToken, mConfiguration, mDisplayId);
- }
-
- // ObjectPoolItem implementation
-
- private WindowContextConfigurationChangeItem() {}
-
- /** Obtains an instance initialized with provided params. */
- public static WindowContextConfigurationChangeItem obtain(
- @NonNull IBinder clientToken, @NonNull Configuration config, int displayId) {
- WindowContextConfigurationChangeItem instance =
- ObjectPool.obtain(WindowContextConfigurationChangeItem.class);
- if (instance == null) {
- instance = new WindowContextConfigurationChangeItem();
- }
- instance.mClientToken = requireNonNull(clientToken);
- instance.mConfiguration = requireNonNull(config);
- instance.mDisplayId = displayId;
-
- return instance;
- }
-
- @Override
- public void recycle() {
- mClientToken = null;
- mConfiguration = null;
- mDisplayId = INVALID_DISPLAY;
- ObjectPool.recycle(this);
- }
-
- // Parcelable implementation
-
- /** Writes to Parcel. */
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeStrongBinder(mClientToken);
- dest.writeTypedObject(mConfiguration, flags);
- dest.writeInt(mDisplayId);
- }
-
- /** Reads from Parcel. */
- private WindowContextConfigurationChangeItem(@NonNull Parcel in) {
- mClientToken = in.readStrongBinder();
- mConfiguration = in.readTypedObject(Configuration.CREATOR);
- mDisplayId = in.readInt();
- }
-
- public static final @NonNull Creator<WindowContextConfigurationChangeItem> CREATOR =
- new Creator<>() {
- public WindowContextConfigurationChangeItem createFromParcel(Parcel in) {
- return new WindowContextConfigurationChangeItem(in);
- }
-
- public WindowContextConfigurationChangeItem[] newArray(int size) {
- return new WindowContextConfigurationChangeItem[size];
- }
- };
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- final WindowContextConfigurationChangeItem other = (WindowContextConfigurationChangeItem) o;
- return Objects.equals(mClientToken, other.mClientToken)
- && Objects.equals(mConfiguration, other.mConfiguration)
- && mDisplayId == other.mDisplayId;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + Objects.hashCode(mClientToken);
- result = 31 * result + Objects.hashCode(mConfiguration);
- result = 31 * result + mDisplayId;
- return result;
- }
-
- @Override
- public String toString() {
- return "WindowContextConfigurationChangeItem{clientToken=" + mClientToken
- + ", config=" + mConfiguration
- + ", displayId=" + mDisplayId
- + "}";
- }
-}
diff --git a/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java b/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java
new file mode 100644
index 0000000..74721d5
--- /dev/null
+++ b/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java
@@ -0,0 +1,126 @@
+/*
+ * 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 java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ClientTransactionHandler;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.window.WindowContextInfo;
+
+import java.util.Objects;
+
+/**
+ * {@link android.window.WindowContext} configuration change message.
+ * @hide
+ */
+public class WindowContextInfoChangeItem extends ClientTransactionItem {
+
+ @Nullable
+ private IBinder mClientToken;
+ @Nullable
+ private WindowContextInfo mInfo;
+
+ @Override
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
+ client.handleWindowContextInfoChanged(mClientToken, mInfo);
+ }
+
+ // ObjectPoolItem implementation
+
+ private WindowContextInfoChangeItem() {}
+
+ /** Obtains an instance initialized with provided params. */
+ public static WindowContextInfoChangeItem obtain(
+ @NonNull IBinder clientToken, @NonNull Configuration config, int displayId) {
+ WindowContextInfoChangeItem instance =
+ ObjectPool.obtain(WindowContextInfoChangeItem.class);
+ if (instance == null) {
+ instance = new WindowContextInfoChangeItem();
+ }
+ instance.mClientToken = requireNonNull(clientToken);
+ instance.mInfo = new WindowContextInfo(config, displayId);
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mClientToken = null;
+ mInfo = null;
+ ObjectPool.recycle(this);
+ }
+
+ // Parcelable implementation
+
+ /** Writes to Parcel. */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(mClientToken);
+ dest.writeTypedObject(mInfo, flags);
+ }
+
+ /** Reads from Parcel. */
+ private WindowContextInfoChangeItem(@NonNull Parcel in) {
+ mClientToken = in.readStrongBinder();
+ mInfo = in.readTypedObject(WindowContextInfo.CREATOR);
+ }
+
+ public static final @NonNull Creator<WindowContextInfoChangeItem> CREATOR =
+ new Creator<>() {
+ public WindowContextInfoChangeItem createFromParcel(Parcel in) {
+ return new WindowContextInfoChangeItem(in);
+ }
+
+ public WindowContextInfoChangeItem[] newArray(int size) {
+ return new WindowContextInfoChangeItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final WindowContextInfoChangeItem other = (WindowContextInfoChangeItem) o;
+ return Objects.equals(mClientToken, other.mClientToken)
+ && Objects.equals(mInfo, other.mInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(mClientToken);
+ result = 31 * result + Objects.hashCode(mInfo);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "WindowContextInfoChangeItem{clientToken=" + mClientToken
+ + ", info=" + mInfo
+ + "}";
+ }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c1474eb..d3b7a5b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -71,6 +71,7 @@
import android.window.ISurfaceSyncGroupCompletedListener;
import android.window.ITaskFpsCallback;
import android.window.ScreenCapture;
+import android.window.WindowContextInfo;
/**
* System private interface to the window manager.
@@ -858,10 +859,10 @@
* @param displayId The display associated with the window context
* @param options A bundle used to pass window-related options and choose the right DisplayArea
*
- * @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is
- * attached to the DisplayArea successfully. {@code null}, otherwise.
+ * @return the {@link WindowContextInfo} of the DisplayArea if the WindowContext is attached to
+ * the DisplayArea successfully. {@code null}, otherwise.
*/
- @nullable Configuration attachWindowContextToDisplayArea(in IApplicationThread appThread,
+ @nullable WindowContextInfo attachWindowContextToDisplayArea(in IApplicationThread appThread,
IBinder clientToken, int type, int displayId, in @nullable Bundle options);
/**
@@ -879,13 +880,15 @@
* the WindowContext's token}
* @param token the WindowToken to attach
*
+ * @return the {@link WindowContextInfo} of the WindowToken if the WindowContext is attached to
+ * the WindowToken successfully. {@code null}, otherwise.
* @throws IllegalArgumentException if the {@code clientToken} have not been attached to
* the server or the WindowContext's type doesn't match WindowToken {@code token}'s type.
*
* @see #attachWindowContextToDisplayArea(IBinder, int, int, Bundle)
*/
- void attachWindowContextToWindowToken(in IApplicationThread appThread, IBinder clientToken,
- IBinder token);
+ @nullable WindowContextInfo attachWindowContextToWindowToken(in IApplicationThread appThread,
+ IBinder clientToken, IBinder token);
/**
* Attaches a {@code clientToken} to associate with DisplayContent.
@@ -899,11 +902,11 @@
* the WindowContext's token}
* @param displayId The display associated with the window context
*
- * @return the DisplayContent's {@link android.app.res.Configuration} if the Context is
- * attached to the DisplayContent successfully. {@code null}, otherwise.
+ * @return the {@link WindowContextInfo} of the DisplayContent if the WindowContext is attached
+ * to the DisplayContent successfully. {@code null}, otherwise.
* @throws android.view.WindowManager.InvalidDisplayException if the display ID is invalid
*/
- @nullable Configuration attachWindowContextToDisplayContent(in IApplicationThread appThread,
+ @nullable WindowContextInfo attachWindowContextToDisplayContent(in IApplicationThread appThread,
IBinder clientToken, int displayId);
/**
diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java
index 36eef53..c9ac245 100644
--- a/core/java/android/window/WindowContextController.java
+++ b/core/java/android/window/WindowContextController.java
@@ -137,12 +137,14 @@
* @see WindowProviderService#attachToWindowToken(IBinder))
* @see IWindowManager#attachWindowContextToWindowToken
*/
- public void attachToWindowToken(IBinder windowToken) {
+ public void attachToWindowToken(@NonNull IBinder windowToken) {
if (mAttachedToDisplayArea != AttachStatus.STATUS_ATTACHED) {
throw new IllegalStateException("The Window Context should have been attached"
+ " to a DisplayArea. AttachToDisplayArea:" + mAttachedToDisplayArea);
}
- getWindowTokenClientController().attachToWindowToken(mToken, windowToken);
+ if (!getWindowTokenClientController().attachToWindowToken(mToken, windowToken)) {
+ Log.e(TAG, "attachToWindowToken fail");
+ }
}
/** Detaches the window context from the node it's currently associated with. */
diff --git a/core/java/android/window/WindowContextInfo.aidl b/core/java/android/window/WindowContextInfo.aidl
new file mode 100644
index 0000000..360431c
--- /dev/null
+++ b/core/java/android/window/WindowContextInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 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.window;
+
+/** @hide */
+parcelable WindowContextInfo;
\ No newline at end of file
diff --git a/core/java/android/window/WindowContextInfo.java b/core/java/android/window/WindowContextInfo.java
new file mode 100644
index 0000000..3c21cd4
--- /dev/null
+++ b/core/java/android/window/WindowContextInfo.java
@@ -0,0 +1,117 @@
+/*
+ * 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.window;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Stores information about a particular window that a {@link WindowContext} is attached to.
+ * @hide
+ */
+public class WindowContextInfo implements Parcelable {
+
+ /**
+ * Configuration of the window.
+ */
+ @NonNull
+ private final Configuration mConfiguration;
+
+ /**
+ * The display id that the window is attached to.
+ */
+ private final int mDisplayId;
+
+ public WindowContextInfo(@NonNull Configuration configuration, int displayId) {
+ mConfiguration = requireNonNull(configuration);
+ mDisplayId = displayId;
+ }
+
+ @NonNull
+ public Configuration getConfiguration() {
+ return mConfiguration;
+ }
+
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ // Parcelable implementation
+
+ /** Writes to Parcel. */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedObject(mConfiguration, flags);
+ dest.writeInt(mDisplayId);
+ }
+
+ /** Reads from Parcel. */
+ private WindowContextInfo(@NonNull Parcel in) {
+ mConfiguration = in.readTypedObject(Configuration.CREATOR);
+ mDisplayId = in.readInt();
+ }
+
+ public static final @NonNull Creator<WindowContextInfo> CREATOR = new Creator<>() {
+ public WindowContextInfo createFromParcel(Parcel in) {
+ return new WindowContextInfo(in);
+ }
+
+ public WindowContextInfo[] newArray(int size) {
+ return new WindowContextInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final WindowContextInfo other = (WindowContextInfo) o;
+ return Objects.equals(mConfiguration, other.mConfiguration)
+ && mDisplayId == other.mDisplayId;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(mConfiguration);
+ result = 31 * result + mDisplayId;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "WindowContextInfo{config=" + mConfiguration
+ + ", displayId=" + mDisplayId
+ + "}";
+ }
+}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 7458563..6a32529 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -99,6 +99,13 @@
@Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
// TODO(b/290876897): No need to post on mHandler after migrating to ClientTransaction
+ postOnConfigurationChanged(newConfig, newDisplayId);
+ }
+
+ /**
+ * Posts an {@link #onConfigurationChanged} to the main thread.
+ */
+ public void postOnConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId) {
mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
}
@@ -162,7 +169,6 @@
windowContext.dispatchConfigurationChanged(newConfig);
}
-
if (shouldReportConfigChange && diff != 0
&& context instanceof WindowProviderService) {
final WindowProviderService windowProviderService = (WindowProviderService) context;
diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java
index 14b9df6..7a84123 100644
--- a/core/java/android/window/WindowTokenClientController.java
+++ b/core/java/android/window/WindowTokenClientController.java
@@ -22,10 +22,9 @@
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.IApplicationThread;
-import android.app.servertransaction.WindowContextConfigurationChangeItem;
+import android.app.servertransaction.WindowContextInfoChangeItem;
import android.app.servertransaction.WindowContextWindowRemovalItem;
import android.content.Context;
-import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -94,17 +93,17 @@
*/
public boolean attachToDisplayArea(@NonNull WindowTokenClient client,
@WindowType int type, int displayId, @Nullable Bundle options) {
- final Configuration configuration;
+ final WindowContextInfo info;
try {
- configuration = getWindowManagerService().attachWindowContextToDisplayArea(
+ info = getWindowManagerService().attachWindowContextToDisplayArea(
mAppThread, client, type, displayId, options);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- if (configuration == null) {
+ if (info == null) {
return false;
}
- onWindowContextTokenAttached(client, displayId, configuration);
+ onWindowContextTokenAttached(client, info, false /* shouldReportConfigChange */);
return true;
}
@@ -121,16 +120,16 @@
if (wms == null) {
return false;
}
- final Configuration configuration;
+ final WindowContextInfo info;
try {
- configuration = wms.attachWindowContextToDisplayContent(mAppThread, client, displayId);
+ info = wms.attachWindowContextToDisplayContent(mAppThread, client, displayId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- if (configuration == null) {
+ if (info == null) {
return false;
}
- onWindowContextTokenAttached(client, displayId, configuration);
+ onWindowContextTokenAttached(client, info, false /* shouldReportConfigChange */);
return true;
}
@@ -139,19 +138,23 @@
*
* @param client The {@link WindowTokenClient} to attach.
* @param windowToken the window token to associated with
+ * @return {@code true} if attaching successfully.
*/
- public void attachToWindowToken(@NonNull WindowTokenClient client,
+ public boolean attachToWindowToken(@NonNull WindowTokenClient client,
@NonNull IBinder windowToken) {
+ final WindowContextInfo info;
try {
- getWindowManagerService().attachWindowContextToWindowToken(
+ info = getWindowManagerService().attachWindowContextToWindowToken(
mAppThread, client, windowToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- // We don't report configuration change for now.
- synchronized (mLock) {
- mWindowTokenClientMap.put(client.asBinder(), client);
+ if (info == null) {
+ return false;
}
+ // We currently report configuration for WindowToken after attached.
+ onWindowContextTokenAttached(client, info, true /* shouldReportConfigChange */);
+ return true;
}
/** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */
@@ -168,21 +171,30 @@
}
}
- private void onWindowContextTokenAttached(@NonNull WindowTokenClient client, int displayId,
- @NonNull Configuration configuration) {
+ private void onWindowContextTokenAttached(@NonNull WindowTokenClient client,
+ @NonNull WindowContextInfo info, boolean shouldReportConfigChange) {
synchronized (mLock) {
mWindowTokenClientMap.put(client.asBinder(), client);
}
- client.onConfigurationChanged(configuration, displayId,
- false /* shouldReportConfigChange */);
+ if (shouldReportConfigChange) {
+ // Should trigger an #onConfigurationChanged callback to the WindowContext. Post the
+ // dispatch in the next loop to prevent the callback from being dispatched before
+ // #onCreate or WindowContext creation..
+ client.postOnConfigurationChanged(info.getConfiguration(), info.getDisplayId());
+ } else {
+ // Apply the config change directly in case users get stale values after WindowContext
+ // creation.
+ client.onConfigurationChanged(info.getConfiguration(), info.getDisplayId(),
+ false /* shouldReportConfigChange */);
+ }
}
- /** Called when receives {@link WindowContextConfigurationChangeItem}. */
- public void onWindowContextConfigurationChanged(@NonNull IBinder clientToken,
- @NonNull Configuration configuration, int displayId) {
+ /** Called when receives {@link WindowContextInfoChangeItem}. */
+ public void onWindowContextInfoChanged(@NonNull IBinder clientToken,
+ @NonNull WindowContextInfo info) {
final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
if (windowTokenClient != null) {
- windowTokenClient.onConfigurationChanged(configuration, displayId);
+ windowTokenClient.onConfigurationChanged(info.getConfiguration(), info.getDisplayId());
}
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 8da6d74..c904d96 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -64,6 +64,7 @@
import android.util.MergedConfiguration;
import android.view.Display;
import android.view.View;
+import android.window.WindowContextInfo;
import android.window.WindowTokenClientController;
import androidx.test.filters.MediumTest;
@@ -753,13 +754,12 @@
WindowTokenClientController.overrideForTesting(windowTokenClientController);
final IBinder clientToken = mock(IBinder.class);
final Configuration configuration = new Configuration();
+ final WindowContextInfo info = new WindowContextInfo(configuration, DEFAULT_DISPLAY);
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> activityThread
- .handleWindowContextConfigurationChanged(
- clientToken, configuration, DEFAULT_DISPLAY));
+ .handleWindowContextInfoChanged(clientToken, info));
- verify(windowTokenClientController).onWindowContextConfigurationChanged(
- clientToken, configuration, DEFAULT_DISPLAY);
+ verify(windowTokenClientController).onWindowContextInfoChanged(clientToken, info);
}
@Test
diff --git a/core/tests/coretests/src/android/app/servertransaction/WindowContextConfigurationChangeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/WindowContextInfoChangeItemTest.java
similarity index 79%
rename from core/tests/coretests/src/android/app/servertransaction/WindowContextConfigurationChangeItemTest.java
rename to core/tests/coretests/src/android/app/servertransaction/WindowContextInfoChangeItemTest.java
index 7811e1a..37a517e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/WindowContextConfigurationChangeItemTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/WindowContextInfoChangeItemTest.java
@@ -23,6 +23,7 @@
import android.app.ClientTransactionHandler;
import android.content.res.Configuration;
import android.os.IBinder;
+import android.window.WindowContextInfo;
import org.junit.Before;
import org.junit.Test;
@@ -30,12 +31,12 @@
import org.mockito.MockitoAnnotations;
/**
- * Tests for {@link WindowContextConfigurationChangeItem}.
+ * Tests for {@link WindowContextInfoChangeItem}.
*
* Build/Install/Run:
- * atest FrameworksCoreTests:WindowContextConfigurationChangeItemTest
+ * atest FrameworksCoreTests:WindowContextInfoChangeItemTest
*/
-public class WindowContextConfigurationChangeItemTest {
+public class WindowContextInfoChangeItemTest {
@Mock
private ClientTransactionHandler mHandler;
@@ -55,11 +56,11 @@
@Test
public void testExecute() {
- final WindowContextConfigurationChangeItem item = WindowContextConfigurationChangeItem
+ final WindowContextInfoChangeItem item = WindowContextInfoChangeItem
.obtain(mClientToken, mConfiguration, DEFAULT_DISPLAY);
item.execute(mHandler, mToken, mPendingActions);
- verify(mHandler).handleWindowContextConfigurationChanged(mClientToken, mConfiguration,
- DEFAULT_DISPLAY);
+ verify(mHandler).handleWindowContextInfoChanged(mClientToken,
+ new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY));
}
}
diff --git a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
index c4f7b3b..7bd6f05 100644
--- a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
@@ -64,6 +64,7 @@
// Can't mock final class.
private final Configuration mConfiguration = new Configuration();
+ private WindowContextInfo mWindowContextInfo;
private WindowTokenClientController mController;
@Before
@@ -72,6 +73,7 @@
doReturn(mClientToken).when(mWindowTokenClient).asBinder();
mController = spy(WindowTokenClientController.createInstanceForTesting());
doReturn(mWindowManagerService).when(mController).getWindowManagerService();
+ mWindowContextInfo = new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY);
}
@Test
@@ -86,7 +88,7 @@
TYPE_APPLICATION_OVERLAY, DEFAULT_DISPLAY, null /* options */);
verify(mWindowTokenClient, never()).onConfigurationChanged(any(), anyInt(), anyBoolean());
- doReturn(mConfiguration).when(mWindowManagerService).attachWindowContextToDisplayArea(
+ doReturn(mWindowContextInfo).when(mWindowManagerService).attachWindowContextToDisplayArea(
any(), any(), anyInt(), anyInt(), any());
assertTrue(mController.attachToDisplayArea(mWindowTokenClient, TYPE_APPLICATION_OVERLAY,
@@ -109,7 +111,7 @@
verify(mWindowManagerService, never()).detachWindowContext(any());
- doReturn(mConfiguration).when(mWindowManagerService).attachWindowContextToDisplayArea(
+ doReturn(mWindowContextInfo).when(mWindowManagerService).attachWindowContextToDisplayArea(
any(), any(), anyInt(), anyInt(), any());
mController.attachToDisplayArea(mWindowTokenClient, TYPE_APPLICATION_OVERLAY,
DEFAULT_DISPLAY, null /* options */);
@@ -129,8 +131,8 @@
DEFAULT_DISPLAY);
verify(mWindowTokenClient, never()).onConfigurationChanged(any(), anyInt(), anyBoolean());
- doReturn(mConfiguration).when(mWindowManagerService).attachWindowContextToDisplayContent(
- any(), any(), anyInt());
+ doReturn(mWindowContextInfo).when(mWindowManagerService)
+ .attachWindowContextToDisplayContent(any(), any(), anyInt());
assertTrue(mController.attachToDisplayContent(mWindowTokenClient, DEFAULT_DISPLAY));
verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY,
@@ -150,8 +152,8 @@
verify(mWindowManagerService, never()).detachWindowContext(any());
- doReturn(mConfiguration).when(mWindowManagerService).attachWindowContextToDisplayContent(
- any(), any(), anyInt());
+ doReturn(mWindowContextInfo).when(mWindowManagerService)
+ .attachWindowContextToDisplayContent(any(), any(), anyInt());
mController.attachToDisplayContent(mWindowTokenClient, DEFAULT_DISPLAY);
mController.detachIfNeeded(mWindowTokenClient);
@@ -160,11 +162,20 @@
@Test
public void testAttachToWindowToken() throws RemoteException {
- mController.attachToWindowToken(mWindowTokenClient, mWindowToken);
+ doReturn(null).when(mWindowManagerService).attachWindowContextToWindowToken(
+ any(), any(), any());
+ assertFalse(mController.attachToWindowToken(mWindowTokenClient, mWindowToken));
verify(mWindowManagerService).attachWindowContextToWindowToken(
ActivityThread.currentActivityThread().getApplicationThread(), mWindowTokenClient,
mWindowToken);
+ verify(mWindowTokenClient, never()).onConfigurationChanged(any(), anyInt(), anyBoolean());
+
+ doReturn(mWindowContextInfo).when(mWindowManagerService)
+ .attachWindowContextToWindowToken(any(), any(), any());
+
+ assertTrue(mController.attachToWindowToken(mWindowTokenClient, mWindowToken));
+ verify(mWindowTokenClient).postOnConfigurationChanged(mConfiguration, DEFAULT_DISPLAY);
}
@Test
@@ -173,6 +184,15 @@
verify(mWindowManagerService, never()).detachWindowContext(any());
+ doReturn(null).when(mWindowManagerService).attachWindowContextToWindowToken(
+ any(), any(), any());
+ mController.attachToWindowToken(mWindowTokenClient, mWindowToken);
+ mController.detachIfNeeded(mWindowTokenClient);
+
+ verify(mWindowManagerService, never()).detachWindowContext(any());
+
+ doReturn(mWindowContextInfo).when(mWindowManagerService).attachWindowContextToWindowToken(
+ any(), any(), any());
mController.attachToWindowToken(mWindowTokenClient, mWindowToken);
mController.detachIfNeeded(mWindowTokenClient);
@@ -180,28 +200,43 @@
}
@Test
- public void testOnWindowContextConfigurationChanged() {
- mController.onWindowContextConfigurationChanged(
- mClientToken, mConfiguration, DEFAULT_DISPLAY);
+ public void testOnWindowContextInfoChanged() throws RemoteException {
+ doReturn(mWindowContextInfo).when(mWindowManagerService)
+ .attachWindowContextToWindowToken(any(), any(), any());
+
+ // No invoke if not attached.
+ mController.onWindowContextInfoChanged(mClientToken, mWindowContextInfo);
verify(mWindowTokenClient, never()).onConfigurationChanged(any(), anyInt());
- mController.attachToWindowToken(mWindowTokenClient, mWindowToken);
+ // Invoke postOnConfigurationChanged when attached
+ assertTrue(mController.attachToWindowToken(mWindowTokenClient, mWindowToken));
- mController.onWindowContextConfigurationChanged(
- mClientToken, mConfiguration, DEFAULT_DISPLAY);
+ verify(mWindowTokenClient).postOnConfigurationChanged(mConfiguration, DEFAULT_DISPLAY);
- verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY);
+ // Invoke onConfigurationChanged when onWindowContextInfoChanged
+ mController.onWindowContextInfoChanged(
+ mClientToken, new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY + 1));
+
+ verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY + 1);
}
@Test
- public void testOnWindowContextWindowRemoved() {
+ public void testOnWindowContextWindowRemoved() throws RemoteException {
+ doReturn(mWindowContextInfo).when(mWindowManagerService)
+ .attachWindowContextToWindowToken(any(), any(), any());
+
+ // No invoke if not attached.
mController.onWindowContextWindowRemoved(mClientToken);
verify(mWindowTokenClient, never()).onWindowTokenRemoved();
+ // No invoke if not onWindowTokenRemoved.
mController.attachToWindowToken(mWindowTokenClient, mWindowToken);
+ verify(mWindowTokenClient, never()).onWindowTokenRemoved();
+
+ // Invoke onWindowTokenRemoved when onWindowContextWindowRemoved
mController.onWindowContextWindowRemoved(mClientToken);
verify(mWindowTokenClient).onWindowTokenRemoved();
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index 26aab07..726ae5c 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -76,7 +76,7 @@
@NonNull IBinder clientToken, @NonNull WindowContainer<?> container,
@WindowType int type, @Nullable Bundle options) {
registerWindowContainerListener(wpc, clientToken, container, type, options,
- true /* shouDispatchConfigWhenRegistering */);
+ true /* shouldDispatchConfigWhenRegistering */);
}
/**
@@ -91,19 +91,19 @@
* @param container the {@link WindowContainer} which the listener is going to listen to.
* @param type the window type
* @param options a bundle used to pass window-related options.
- * @param shouDispatchConfigWhenRegistering {@code true} to indicate the current
+ * @param shouldDispatchConfigWhenRegistering {@code true} to indicate the current
* {@code container}'s config will dispatch to the client side when
* registering the {@link WindowContextListenerImpl}
*/
void registerWindowContainerListener(@NonNull WindowProcessController wpc,
@NonNull IBinder clientToken, @NonNull WindowContainer<?> container,
@WindowType int type, @Nullable Bundle options,
- boolean shouDispatchConfigWhenRegistering) {
+ boolean shouldDispatchConfigWhenRegistering) {
WindowContextListenerImpl listener = mListeners.get(clientToken);
if (listener == null) {
listener = new WindowContextListenerImpl(wpc, clientToken, container, type,
options);
- listener.register(shouDispatchConfigWhenRegistering);
+ listener.register(shouldDispatchConfigWhenRegistering);
} else {
updateContainerForWindowContextListener(clientToken, container);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 210378f..261d6bc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -305,6 +305,7 @@
import android.window.ScreenCapture;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
+import android.window.WindowContextInfo;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -2737,7 +2738,7 @@
@Nullable
@Override
- public Configuration attachWindowContextToDisplayArea(@NonNull IApplicationThread appThread,
+ public WindowContextInfo attachWindowContextToDisplayArea(@NonNull IApplicationThread appThread,
@NonNull IBinder clientToken, @LayoutParams.WindowType int type, int displayId,
@Nullable Bundle options) {
Objects.requireNonNull(appThread);
@@ -2766,8 +2767,8 @@
final DisplayArea<?> da = dc.findAreaForWindowType(type, options,
callerCanManageAppTokens, false /* roundedCornerOverlay */);
mWindowContextListenerController.registerWindowContainerListener(wpc, clientToken,
- da, type, options, false /* shouDispatchConfigWhenRegistering */);
- return da.getConfiguration();
+ da, type, options, false /* shouldDispatchConfigWhenRegistering */);
+ return new WindowContextInfo(da.getConfiguration(), displayId);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2776,8 +2777,8 @@
@Nullable
@Override
- public Configuration attachWindowContextToDisplayContent(@NonNull IApplicationThread appThread,
- @NonNull IBinder clientToken, int displayId) {
+ public WindowContextInfo attachWindowContextToDisplayContent(
+ @NonNull IApplicationThread appThread, @NonNull IBinder clientToken, int displayId) {
Objects.requireNonNull(appThread);
Objects.requireNonNull(clientToken);
final int callingPid = Binder.getCallingPid();
@@ -2809,16 +2810,17 @@
mWindowContextListenerController.registerWindowContainerListener(wpc, clientToken,
dc, INVALID_WINDOW_TYPE, null /* options */,
- false /* shouDispatchConfigWhenRegistering */);
- return dc.getConfiguration();
+ false /* shouldDispatchConfigWhenRegistering */);
+ return new WindowContextInfo(dc.getConfiguration(), displayId);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ @Nullable
@Override
- public void attachWindowContextToWindowToken(@NonNull IApplicationThread appThread,
+ public WindowContextInfo attachWindowContextToWindowToken(@NonNull IApplicationThread appThread,
@NonNull IBinder clientToken, @NonNull IBinder token) {
Objects.requireNonNull(appThread);
Objects.requireNonNull(clientToken);
@@ -2834,13 +2836,13 @@
if (wpc == null) {
ProtoLog.w(WM_ERROR, "attachWindowContextToWindowToken: calling from"
+ " non-existing process pid=%d uid=%d", callingPid, callingUid);
- return;
+ return null;
}
final WindowToken windowToken = mRoot.getWindowToken(token);
if (windowToken == null) {
ProtoLog.w(WM_ERROR, "Then token:%s is invalid. It might be "
+ "removed", token);
- return;
+ return null;
}
final int type = mWindowContextListenerController.getWindowType(clientToken);
if (type == INVALID_WINDOW_TYPE) {
@@ -2854,10 +2856,13 @@
}
if (!mWindowContextListenerController.assertCallerCanModifyListener(clientToken,
callerCanManageAppTokens, callingUid)) {
- return;
+ return null;
}
mWindowContextListenerController.registerWindowContainerListener(wpc, clientToken,
- windowToken, windowToken.windowType, windowToken.mOptions);
+ windowToken, windowToken.windowType, windowToken.mOptions,
+ false /* shouldDispatchConfigWhenRegistering */);
+ return new WindowContextInfo(windowToken.getConfiguration(),
+ windowToken.getDisplayContent().getDisplayId());
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
index 1180ebd..c3db241 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
@@ -47,6 +47,7 @@
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.window.WindowContextInfo;
import android.window.WindowTokenClient;
import com.android.server.inputmethod.InputMethodDialogWindowContext;
@@ -99,7 +100,7 @@
final WindowProcessController wpc = mAtm.getProcessController(appThread);
mWm.mWindowContextListenerController.registerWindowContainerListener(wpc, clientToken,
dc.getImeContainer(), TYPE_INPUT_METHOD_DIALOG, null /* options */);
- return dc.getImeContainer().getConfiguration();
+ return new WindowContextInfo(dc.getImeContainer().getConfiguration(), displayId);
}).when(mIWindowManager).attachWindowContextToDisplayArea(any(), any(),
eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any());
mDisplayManagerGlobal = DisplayManagerGlobal.getInstance();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 325176f..55fda05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -468,7 +468,7 @@
mWm.attachWindowContextToWindowToken(mAppThread, new Binder(), windowToken.token);
verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(
- any(), any(), any(), anyInt(), any());
+ any(), any(), any(), anyInt(), any(), anyBoolean());
}
@Test
@@ -484,9 +484,9 @@
final IBinder clientToken = new Binder();
mWm.attachWindowContextToWindowToken(mAppThread, clientToken, windowToken.token);
final WindowProcessController wpc = mAtm.getProcessController(mAppThread);
- verify(mWm.mWindowContextListenerController).registerWindowContainerListener(eq(wpc),
- eq(clientToken), eq(windowToken), eq(TYPE_INPUT_METHOD),
- eq(windowToken.mOptions));
+ verify(mWm.mWindowContextListenerController).registerWindowContainerListener(wpc,
+ clientToken, windowToken, TYPE_INPUT_METHOD, windowToken.mOptions,
+ false /* shouldDispatchConfigWhenRegistering */);
}
@Test
@@ -514,7 +514,7 @@
new InsetsSourceControl.Array(), new Rect(), new float[1]);
verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
- any(), any(), anyInt(), any());
+ any(), any(), anyInt(), any(), anyBoolean());
}
@Test