diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java index f8484d15344e0..2d2c8de726466 100644 --- a/core/java/android/window/WindowProviderService.java +++ b/core/java/android/window/WindowProviderService.java @@ -165,10 +165,11 @@ public abstract class WindowProviderService extends Service implements WindowPro } } + // Suppress the lint because ths is overridden from Context. @SuppressLint("OnNameExpected") @Override - // Suppress the lint because ths is overridden from Context. - public @Nullable Object getSystemService(@NonNull String name) { + @Nullable + public Object getSystemService(@NonNull String name) { if (WINDOW_SERVICE.equals(name)) { return mWindowManager; } diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 547535d90e5aa..7db4243d3a83e 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -19,8 +19,8 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; import static android.window.ConfigurationHelper.isDifferentDisplay; import static android.window.ConfigurationHelper.shouldUpdateResources; +import android.annotation.AnyThread; import android.annotation.BinderThread; -import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.IWindowToken; @@ -40,6 +40,7 @@ import android.view.IWindowManager; import android.view.WindowManager.LayoutParams.WindowType; import android.view.WindowManagerGlobal; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.lang.ref.WeakReference; @@ -68,6 +69,7 @@ public class WindowTokenClient extends IWindowToken.Stub { private IWindowManager mWms; + @GuardedBy("itself") private final Configuration mConfiguration = new Configuration(); private boolean mShouldDumpConfigForIme; @@ -91,7 +93,6 @@ public class WindowTokenClient extends IWindowToken.Stub { throw new IllegalStateException("Context is already attached."); } mContextRef = new WeakReference<>(context); - mConfiguration.setTo(context.getResources().getConfiguration()); mShouldDumpConfigForIme = Build.IS_DEBUGGABLE && context instanceof AbstractInputMethodService; } @@ -137,8 +138,7 @@ public class WindowTokenClient extends IWindowToken.Stub { if (configuration == null) { return false; } - mHandler.post(() -> onConfigurationChanged(configuration, displayId, - false /* shouldReportConfigChange */)); + onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */); mAttachToWindowContainer = true; return true; } catch (RemoteException e) { @@ -199,8 +199,19 @@ public class WindowTokenClient extends IWindowToken.Stub { * * Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control * whether to dispatch configuration update or not. + *

+ * Note that this method must be executed on the main thread if + * {@code shouldReportConfigChange} is {@code true}, which is usually from + * {@link IWindowToken#onConfigurationChanged(Configuration, int)} + * directly, while this method could be run on any thread if it is used to initialize + * Context's {@code Configuration} via {@link #attachToDisplayArea(int, int, Bundle)} + * or {@link #attachToDisplayContent(int)}. + * + * @param shouldReportConfigChange {@code true} to indicate that the {@code Configuration} + * should be dispatched to listeners. + * */ - @MainThread + @AnyThread @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void onConfigurationChanged(Configuration newConfig, int newDisplayId, boolean shouldReportConfigChange) { @@ -208,18 +219,29 @@ public class WindowTokenClient extends IWindowToken.Stub { if (context == null) { return; } - final boolean displayChanged = isDifferentDisplay(context.getDisplayId(), newDisplayId); - final boolean shouldUpdateResources = shouldUpdateResources(this, mConfiguration, - newConfig, newConfig /* overrideConfig */, displayChanged, - null /* configChanged */); + final boolean displayChanged; + final boolean shouldUpdateResources; + final int diff; + final Configuration currentConfig; + + synchronized (mConfiguration) { + displayChanged = isDifferentDisplay(context.getDisplayId(), newDisplayId); + shouldUpdateResources = shouldUpdateResources(this, mConfiguration, + newConfig, newConfig /* overrideConfig */, displayChanged, + null /* configChanged */); + diff = mConfiguration.diffPublicOnly(newConfig); + currentConfig = mShouldDumpConfigForIme ? new Configuration(mConfiguration) : null; + if (shouldUpdateResources) { + mConfiguration.setTo(newConfig); + } + } if (!shouldUpdateResources && mShouldDumpConfigForIme) { Log.d(TAG, "Configuration not dispatch to IME because configuration is up" + " to date. Current config=" + context.getResources().getConfiguration() - + ", reported config=" + mConfiguration + + ", reported config=" + currentConfig + ", updated config=" + newConfig); } - if (shouldUpdateResources) { // TODO(ag/9789103): update resource manager logic to track non-activity tokens mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId); @@ -229,7 +251,7 @@ public class WindowTokenClient extends IWindowToken.Stub { windowContext.dispatchConfigurationChanged(newConfig); } - final int diff = mConfiguration.diffPublicOnly(newConfig); + if (shouldReportConfigChange && diff != 0 && context instanceof WindowProviderService) { final WindowProviderService windowProviderService = (WindowProviderService) context; @@ -244,11 +266,10 @@ public class WindowTokenClient extends IWindowToken.Stub { Log.d(TAG, "Configuration not dispatch to IME because configuration has no " + " public difference with updated config. " + " Current config=" + context.getResources().getConfiguration() - + ", reported config=" + mConfiguration + + ", reported config=" + currentConfig + ", updated config=" + newConfig); } } - mConfiguration.setTo(newConfig); } if (displayChanged) { context.updateDisplay(newDisplayId); diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index dbc08cd5d1a94..e7c03aa7a099c 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -637,12 +637,19 @@ public abstract class ConfigurationContainer { } void registerConfigurationChangeListener(ConfigurationContainerListener listener) { + registerConfigurationChangeListener(listener, true /* shouldDispatchConfig */); + } + + void registerConfigurationChangeListener(ConfigurationContainerListener listener, + boolean shouldDispatchConfig) { if (mChangeListeners.contains(listener)) { return; } mChangeListeners.add(listener); - listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration); - listener.onMergedOverrideConfigurationChanged(mMergedOverrideConfiguration); + if (shouldDispatchConfig) { + listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration); + listener.onMergedOverrideConfigurationChanged(mMergedOverrideConfiguration); + } } void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f5af2b4e29fa9..c7bc51356c765 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3747,13 +3747,20 @@ class WindowContainer extends ConfigurationContainer< } void registerWindowContainerListener(WindowContainerListener listener) { + registerWindowContainerListener(listener, true /* shouldPropConfig */); + } + + void registerWindowContainerListener(WindowContainerListener listener, + boolean shouldDispatchConfig) { if (mListeners.contains(listener)) { return; } mListeners.add(listener); // Also register to ConfigurationChangeListener to receive configuration changes. - registerConfigurationChangeListener(listener); - listener.onDisplayChanged(getDisplayContent()); + registerConfigurationChangeListener(listener, shouldDispatchConfig); + if (shouldDispatchConfig) { + listener.onDisplayChanged(getDisplayContent()); + } } void unregisterWindowContainerListener(WindowContainerListener listener) { diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java index 7956a112539e3..912fdb2e32af9 100644 --- a/services/core/java/com/android/server/wm/WindowContextListenerController.java +++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java @@ -68,6 +68,16 @@ class WindowContextListenerController { @VisibleForTesting final ArrayMap mListeners = new ArrayMap<>(); + /** + * @see #registerWindowContainerListener(IBinder, WindowContainer, int, int, Bundle, boolean) + */ + void registerWindowContainerListener(@NonNull IBinder clientToken, + @NonNull WindowContainer container, int ownerUid, @WindowType int type, + @Nullable Bundle options) { + registerWindowContainerListener(clientToken, container, ownerUid, type, options, + true /* shouDispatchConfigWhenRegistering */); + } + /** * Registers the listener to a {@code container} which is associated with * a {@code clientToken}, which is a {@link android.window.WindowContext} representation. If the @@ -80,15 +90,18 @@ class WindowContextListenerController { * @param ownerUid the caller UID * @param type the window type * @param options a bundle used to pass window-related options. + * @param shouDispatchConfigWhenRegistering {@code true} to indicate the current + * {@code container}'s config will dispatch to the client side when + * registering the {@link WindowContextListenerImpl} */ void registerWindowContainerListener(@NonNull IBinder clientToken, @NonNull WindowContainer container, int ownerUid, @WindowType int type, - @Nullable Bundle options) { + @Nullable Bundle options, boolean shouDispatchConfigWhenRegistering) { WindowContextListenerImpl listener = mListeners.get(clientToken); if (listener == null) { listener = new WindowContextListenerImpl(clientToken, container, ownerUid, type, options); - listener.register(); + listener.register(shouDispatchConfigWhenRegistering); } else { listener.updateContainer(container); } @@ -228,12 +241,16 @@ class WindowContextListenerController { } private void register() { + register(true /* shouldDispatchConfig */); + } + + private void register(boolean shouldDispatchConfig) { final IBinder token = mClientToken.asBinder(); if (mDeathRecipient == null) { throw new IllegalStateException("Invalid client token: " + token); } mListeners.putIfAbsent(token, this); - mContainer.registerWindowContainerListener(this); + mContainer.registerWindowContainerListener(this, shouldDispatchConfig); } private void unregister() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2f4dc515fd117..c37c9cb72ec5e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2770,12 +2770,10 @@ public class WindowManagerService extends IWindowManager.Stub } // TODO(b/155340867): Investigate if we still need roundedCornerOverlay after // the feature b/155340867 is completed. - final DisplayArea da = dc.findAreaForWindowType(type, options, + final DisplayArea da = dc.findAreaForWindowType(type, options, callerCanManageAppTokens, false /* roundedCornerOverlay */); - // TODO(b/190019118): Avoid to send onConfigurationChanged because it has been done - // in return value of attachWindowContextToDisplayArea. mWindowContextListenerController.registerWindowContainerListener(clientToken, da, - callingUid, type, options); + callingUid, type, options, false /* shouDispatchConfigWhenRegistering */); return da.getConfiguration(); } } finally { @@ -2871,7 +2869,8 @@ public class WindowManagerService extends IWindowManager.Stub } mWindowContextListenerController.registerWindowContainerListener(clientToken, dc, - callingUid, INVALID_WINDOW_TYPE, null /* options */); + callingUid, INVALID_WINDOW_TYPE, null /* options */, + false /* shouDispatchConfigWhenRegistering */); return dc.getConfiguration(); } } finally {