diff options
author | Ming-Shin Lu <lumark@google.com> | 2022-01-10 12:14:51 +0800 |
---|---|---|
committer | Ming-Shin Lu <lumark@google.com> | 2022-01-14 12:49:13 +0000 |
commit | 29de30597b65c9111418278d04f03c35eb37d700 (patch) | |
tree | 605022d40a6316f8947cfd68bd21106ec5f9ee24 | |
parent | 54fed092f842043cd0414c14a7d4e1f353f0cee9 (diff) | |
download | base-29de30597b65c9111418278d04f03c35eb37d700.tar.gz |
Fix IME shrunk by WindowTokenClient mis-detach
As CL[1] introduced WindowTokenClient for WindowProviderService (aka the
parent class of InputMethodService starts from CL[2]) as a token that
IME context can associate with the windowContainer of
the InputMethod window in server side. Like the activity context,
IME context can adopt configuration/resources update when the IME
window changed by display/window changes.
And, the IME context caller can also create another type of context
with wrapping IME context (i.e. calling createDisplayContext to create
a display context), that makes this context can be mixed the window
token of WindowProviderService since it's the base context.
However, the finalization of the context mixed WindowTokenClient
will detach the token when the attached context type is non-window
context, this action will mis-detach the token when it managed by
WindowProviderService.
So like SoftKeyboard previously using
createDisplayContext in CL[3] to workaround context resources issues,
will in-directly expose this mis-detach token issue as the above.
Beside, the handling of WindowTokenClient#{onConfigurationChange,
onWindowTokenRemoved} does not thread-safe since this is called from
IPC.
As the result, the fix is to ignore the check in ContextImpl#finalize
to not detach the token when it managed by WindowProviderService,
also make sure to post to the main handler when received
onConfigurationChanged/onWindowTokenRemoved in WindowTokenClient.
Note that this fix could help to resolve "The Window Context should
have been attached to a DisplayArea." exception if the token has been
detached as the above case that happens before the next
WindowProviderService#attachToWindowToken invoked.
[1]: I64a1614f32d097785915f6105b1813a929e0fe32
[2]: Ie565e30ed5dd3f2cfe27355a6dded76dc3adc14b
[3]: Ic592a1d2fb2da149220c8b503b522b3e864bcc77
Bug: 213118079
Bug: 211062619
Test: manual as steps:
1) adb install -r EditTextVariations.apk
2) adb install -r SoftKeyboard.apk
3) adb shell ime enable com.example.android.softkeyboard/.SoftKeyboard
4) adb shell ime set com.example.android.softkeyboard/.SoftKeyboard5
5) Enable screen auto-rotation
6) Launch EditTextVariations from launcher's shortcut
7) Tap the first EditText field to show IME
8) Rotate the device to the landscape mode
9) Expect the IME should not be shrunk
Change-Id: I7beb7a122af93e596239a36db62073233cea0726
-rw-r--r-- | core/java/android/app/ContextImpl.java | 11 | ||||
-rw-r--r-- | core/java/android/window/WindowTokenClient.java | 34 |
2 files changed, 32 insertions, 13 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index db3c7d9bcb02..30e088f15ff6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -311,6 +311,14 @@ class ContextImpl extends Context { @ContextType private int mContextType; + /** + * {@code true} to indicate that the {@link Context} owns the {@link #getWindowContextToken()} + * and is responsible for detaching the token when the Context is released. + * + * @see #finalize() + */ + private boolean mOwnsToken = false; + @GuardedBy("mSync") private File mDatabasesDir; @GuardedBy("mSync") @@ -2979,7 +2987,7 @@ class ContextImpl extends Context { // WindowContainer. We should detach from WindowContainer when the Context is finalized // if this Context is not a WindowContext. WindowContext finalization is handled in // WindowContext class. - if (mToken instanceof WindowTokenClient && mContextType != CONTEXT_TYPE_WINDOW_CONTEXT) { + if (mToken instanceof WindowTokenClient && mOwnsToken) { ((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded(); } super.finalize(); @@ -3010,6 +3018,7 @@ class ContextImpl extends Context { token.attachContext(context); token.attachToDisplayContent(displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; + context.mOwnsToken = true; return context; } diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index b331a9e81e27..1ba63f5fca3c 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -20,9 +20,10 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; import static android.window.ConfigurationHelper.isDifferentDisplay; import static android.window.ConfigurationHelper.shouldUpdateResources; +import android.annotation.BinderThread; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityThread; import android.app.IWindowToken; import android.app.ResourcesManager; import android.content.Context; @@ -31,7 +32,9 @@ import android.inputmethodservice.AbstractInputMethodService; import android.os.Build; import android.os.Bundle; import android.os.Debug; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.view.IWindowManager; @@ -72,6 +75,8 @@ public class WindowTokenClient extends IWindowToken.Stub { private boolean mAttachToWindowContainer; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + /** * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. @@ -133,7 +138,8 @@ public class WindowTokenClient extends IWindowToken.Stub { if (configuration == null) { return false; } - onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */); + mHandler.post(() -> onConfigurationChanged(configuration, displayId, + false /* shouldReportConfigChange */)); mAttachToWindowContainer = true; return true; } catch (RemoteException e) { @@ -180,9 +186,11 @@ public class WindowTokenClient extends IWindowToken.Stub { * @param newConfig the updated {@link Configuration} * @param newDisplayId the updated {@link android.view.Display} ID */ + @BinderThread @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { - onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */); + mHandler.post(() -> onConfigurationChanged(newConfig, newDisplayId, + true /* shouldReportConfigChange */)); } // TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService @@ -193,6 +201,7 @@ 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. */ + @MainThread @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void onConfigurationChanged(Configuration newConfig, int newDisplayId, boolean shouldReportConfigChange) { @@ -218,8 +227,7 @@ public class WindowTokenClient extends IWindowToken.Stub { if (shouldReportConfigChange && context instanceof WindowContext) { final WindowContext windowContext = (WindowContext) context; - ActivityThread.currentActivityThread().getHandler().post( - () -> windowContext.dispatchConfigurationChanged(newConfig)); + windowContext.dispatchConfigurationChanged(newConfig); } // Dispatch onConfigurationChanged only if there's a significant public change to @@ -233,8 +241,7 @@ public class WindowTokenClient extends IWindowToken.Stub { if (shouldReportConfigChange && diff != 0 && context instanceof WindowProviderService) { final WindowProviderService windowProviderService = (WindowProviderService) context; - ActivityThread.currentActivityThread().getHandler().post( - () -> windowProviderService.onConfigurationChanged(newConfig)); + windowProviderService.onConfigurationChanged(newConfig); } freeTextLayoutCachesIfNeeded(diff); if (mShouldDumpConfigForIme) { @@ -256,12 +263,15 @@ public class WindowTokenClient extends IWindowToken.Stub { } } + @BinderThread @Override public void onWindowTokenRemoved() { - final Context context = mContextRef.get(); - if (context != null) { - context.destroy(); - mContextRef.clear(); - } + mHandler.post(() -> { + final Context context = mContextRef.get(); + if (context != null) { + context.destroy(); + mContextRef.clear(); + } + }); } } |