diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java index 9bf2a578a..537c4440b 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java @@ -25,6 +25,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; +import androidx.annotation.NonNull; + import org.dslul.openboard.inputmethod.event.Event; import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; import org.dslul.openboard.inputmethod.keyboard.clipboard.ClipboardHistoryView; @@ -93,23 +95,24 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mIsHardwareAcceleratedDrawingEnabled = mLatinIME.enableHardwareAcceleration(); } - public void updateKeyboardTheme() { + public void updateKeyboardTheme(@NonNull Context displayContext) { final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper( - mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */)); + displayContext, KeyboardTheme.getKeyboardTheme(displayContext /* context */)); if (themeUpdated && mKeyboardView != null) { - mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled)); + mLatinIME.setInputView(onCreateInputView(displayContext, mIsHardwareAcceleratedDrawingEnabled)); } } - public void forceUpdateKeyboardTheme() { - mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled)); + public void forceUpdateKeyboardTheme(@NonNull Context displayContext) { + mLatinIME.setInputView(onCreateInputView(displayContext, mIsHardwareAcceleratedDrawingEnabled)); } private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context, final KeyboardTheme keyboardTheme) { final boolean nightModeChanged = (mCurrentUiMode & Configuration.UI_MODE_NIGHT_MASK) != (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK); - if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme) || nightModeChanged) { + if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme) || nightModeChanged + || !mThemeContext.getResources().equals(context.getResources())) { mKeyboardTheme = keyboardTheme; mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId); mCurrentUiMode = context.getResources().getConfiguration().uiMode; @@ -530,13 +533,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } } - public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { + public View onCreateInputView(@NonNull Context displayContext, + final boolean isHardwareAcceleratedDrawingEnabled) { if (mKeyboardView != null) { mKeyboardView.closing(); } updateKeyboardThemeAndContextThemeWrapper( - mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */)); + displayContext, KeyboardTheme.getKeyboardTheme(displayContext /* context */)); mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( R.layout.input_view, null); mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame); diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java index 17ebf02af..c63439187 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java @@ -98,11 +98,14 @@ import java.util.Locale; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII; import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE; import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT; +import androidx.annotation.NonNull; + /** * Input method implementation for Qwerty'ish keyboard. */ @@ -163,6 +166,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // {@link #onEvaluateInputViewShown()}. private boolean mIsExecutingStartShowingInputView; + // Used for re-initialize keyboard layout after onConfigurationChange. + @Nullable private Context mDisplayContext; + // Object for reacting to adding/removing a dictionary pack. private final BroadcastReceiver mDictionaryPackInstallReceiver = new DictionaryPackInstallBroadcastReceiver(this); @@ -620,10 +626,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen DebugFlags.init(DeviceProtectedUtils.getSharedPreferences(this)); RichInputMethodManager.init(this); mRichImm = RichInputMethodManager.getInstance(); - KeyboardSwitcher.init(this); AudioAndHapticFeedbackManager.init(this); AccessibilityUtils.init(this); mStatsUtilsManager.onCreate(this /* context */, mDictionaryFacilitator); + mDisplayContext = getDisplayContext(); + KeyboardSwitcher.init(this); super.onCreate(); mClipboardHistoryManager.onCreate(); @@ -816,14 +823,46 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } // KeyboardSwitcher will check by itself if theme update is necessary - mKeyboardSwitcher.updateKeyboardTheme(); + mKeyboardSwitcher.updateKeyboardTheme(getDisplayContext()); super.onConfigurationChanged(conf); } + @Override + public void onInitializeInterface() { + mDisplayContext = getDisplayContext(); + mKeyboardSwitcher.updateKeyboardTheme(mDisplayContext); + } + + /** + * Returns the context object whose resources are adjusted to match the metrics of the display. + * + * Note that before {@link android.os.Build.VERSION_CODES#KITKAT}, there is no way to support + * multi-display scenarios, so the context object will just return the IME context itself. + * + * With initiating multi-display APIs from {@link android.os.Build.VERSION_CODES#KITKAT}, the + * context object has to return with re-creating the display context according the metrics + * of the display in runtime. + * + * Starts from {@link android.os.Build.VERSION_CODES#S_V2}, the returning context object has + * became to IME context self since it ends up capable of updating its resources internally. + */ + private @NonNull Context getDisplayContext() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { + // IME context sources is now managed by WindowProviderService from Android 12L. + return this; + } + // An issue in Q that non-activity components Resources / DisplayMetrics in + // Context doesn't well updated when the IME window moving to external display. + // Currently we do a workaround is to create new display context directly and re-init + // keyboard layout with this context. + final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); + return createDisplayContext(wm.getDefaultDisplay()); + } + @Override public View onCreateInputView() { StatsUtils.onCreateInputView(); - return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled); + return mKeyboardSwitcher.onCreateInputView(getDisplayContext(), mIsHardwareAcceleratedDrawingEnabled); } @Override @@ -906,7 +945,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER; mRichImm.refreshSubtypeCaches(); final KeyboardSwitcher switcher = mKeyboardSwitcher; - switcher.updateKeyboardTheme(); + switcher.updateKeyboardTheme(mDisplayContext); final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView(); // If we are starting input in a different text field from before, we'll have to reload // settings, so currentSettingsValues can't be final. diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt index 31902e5cf..c7813bf82 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt @@ -81,7 +81,8 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC override fun onPause() { super.onPause() if (needsReload) - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme() + // todo: is this the correct "displayContext? if not it may cause weird rare issues on some android versions + KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(activity) needsReload = false }