Loading core/java/android/inputmethodservice/InputMethodService.java +120 −8 Original line number Diff line number Diff line Loading @@ -19,16 +19,22 @@ package android.inputmethodservice; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.MainThread; import android.app.ActivityManager; import android.app.Dialog; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.Rect; import android.graphics.Region; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ResultReceiver; import android.os.SystemClock; Loading Loading @@ -68,6 +74,8 @@ import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * InputMethodService provides a standard implementation of an InputMethod, Loading Loading @@ -633,6 +641,97 @@ public class InputMethodService extends AbstractInputMethodService { public int touchableInsets; } /** * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}. * * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API. * Basically this functionality still needs to be considered as implementation details.</p> */ @MainThread private static final class SettingsObserver extends ContentObserver { @Retention(RetentionPolicy.SOURCE) @IntDef({ ShowImeWithHardKeyboardType.UNKNOWN, ShowImeWithHardKeyboardType.FALSE, ShowImeWithHardKeyboardType.TRUE, }) private @interface ShowImeWithHardKeyboardType { int UNKNOWN = 0; int FALSE = 1; int TRUE = 2; } @ShowImeWithHardKeyboardType private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN; private final InputMethodService mService; private SettingsObserver(InputMethodService service) { super(new Handler(service.getMainLooper())); mService = service; } /** * A factory method that internally enforces two-phase initialization to make sure that the * object reference will not be escaped until the object is properly constructed. * * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence * this enforcement of two-phase initialization may be unnecessary at the moment.</p> * * @param service {@link InputMethodService} that needs to receive the callback. * @return {@link SettingsObserver} that is already registered to * {@link android.content.ContentResolver}. The caller must call * {@link SettingsObserver#unregister()}. */ public static SettingsObserver createAndRegister(InputMethodService service) { final SettingsObserver observer = new SettingsObserver(service); // The observer is properly constructed. Let's start accepting the event. service.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, observer); return observer; } void unregister() { mService.getContentResolver().unregisterContentObserver(this); } private boolean shouldShowImeWithHardKeyboard() { // Lazily initialize as needed. if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) { mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ? ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE; } switch (mShowImeWithHardKeyboard) { case ShowImeWithHardKeyboardType.TRUE: return true; case ShowImeWithHardKeyboardType.FALSE: return false; default: Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard); return false; } } @Override public void onChange(boolean selfChange, Uri uri) { final Uri showImeWithHardKeyboardUri = Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); if (showImeWithHardKeyboardUri.equals(uri)) { mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ? ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE; mService.updateInputViewShown(); } } @Override public String toString() { return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}"; } } private SettingsObserver mSettingsObserver; /** * You can call this to customize the theme used by your IME's window. * This theme should typically be one that derives from Loading Loading @@ -682,6 +781,7 @@ public class InputMethodService extends AbstractInputMethodService { super.setTheme(mTheme); super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); mSettingsObserver = SettingsObserver.createAndRegister(this); // If the previous IME has occupied non-empty inset in the screen, we need to decide whether // we continue to use the same size of the inset or update it mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0); Loading Loading @@ -764,6 +864,10 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.getWindow().setWindowAnimations(0); mWindow.dismiss(); } if (mSettingsObserver != null) { mSettingsObserver.unregister(); mSettingsObserver = null; } } /** Loading Loading @@ -1142,14 +1246,21 @@ public class InputMethodService extends AbstractInputMethodService { } /** * Override this to control when the soft input area should be shown to * the user. The default implementation only shows the input view when * there is no hard keyboard or the keyboard is hidden. If you change what * this returns, you will need to call {@link #updateInputViewShown()} * yourself whenever the returned value may have changed to have it * re-evaluated and applied. * Override this to control when the soft input area should be shown to the user. The default * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden * unless the user shows an intention to use software keyboard. If you change what this * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned * value may have changed to have it re-evaluated and applied. * * <p>When you override this method, it is recommended to call * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is * returned.</p> */ @CallSuper public boolean onEvaluateInputViewShown() { if (mSettingsObserver.shouldShowImeWithHardKeyboard()) { return true; } Configuration config = getResources().getConfiguration(); return config.keyboard == Configuration.KEYBOARD_NOKEYS || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; Loading Loading @@ -2483,5 +2594,6 @@ public class InputMethodService extends AbstractInputMethodService { + " touchableInsets=" + mTmpInsets.touchableInsets + " touchableRegion=" + mTmpInsets.touchableRegion); p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); p.println(" mSettingsObserver=" + mSettingsObserver); } } services/core/java/com/android/server/wm/WindowManagerService.java +1 −25 Original line number Diff line number Diff line Loading @@ -578,31 +578,23 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowState> mTmpWindows = new ArrayList<>(); boolean mHardKeyboardAvailable; boolean mShowImeWithHardKeyboard; WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; SettingsObserver mSettingsObserver; private final class SettingsObserver extends ContentObserver { private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); public SettingsObserver() { super(new Handler()); ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL); } @Override public void onChange(boolean selfChange, Uri uri) { if (mShowImeWithHardKeyboardUri.equals(uri)) { updateShowImeWithHardKeyboard(); } else if (mDisplayInversionEnabledUri.equals(uri)) { if (mDisplayInversionEnabledUri.equals(uri)) { updateCircularDisplayMaskIfNeeded(); } } Loading Loading @@ -946,7 +938,6 @@ public class WindowManagerService extends IWindowManager.Stub mContext.registerReceiver(mBroadcastReceiver, filter); mSettingsObserver = new SettingsObserver(); updateShowImeWithHardKeyboard(); mHoldingScreenWakeLock = mPowerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM); Loading Loading @@ -7111,9 +7102,6 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); } if (mShowImeWithHardKeyboard) { config.keyboard = Configuration.KEYBOARD_NOKEYS; } // Let the policy update hidden states. config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; Loading @@ -7122,18 +7110,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence); } public void updateShowImeWithHardKeyboard() { synchronized (mWindowMap) { final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mCurrentUserId) == 1; if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) { mShowImeWithHardKeyboard = showImeWithHardKeyboard; mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } } void notifyHardKeyboardStatusChange() { final boolean available; final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener; Loading Loading
core/java/android/inputmethodservice/InputMethodService.java +120 −8 Original line number Diff line number Diff line Loading @@ -19,16 +19,22 @@ package android.inputmethodservice; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.MainThread; import android.app.ActivityManager; import android.app.Dialog; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.Rect; import android.graphics.Region; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ResultReceiver; import android.os.SystemClock; Loading Loading @@ -68,6 +74,8 @@ import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * InputMethodService provides a standard implementation of an InputMethod, Loading Loading @@ -633,6 +641,97 @@ public class InputMethodService extends AbstractInputMethodService { public int touchableInsets; } /** * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}. * * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API. * Basically this functionality still needs to be considered as implementation details.</p> */ @MainThread private static final class SettingsObserver extends ContentObserver { @Retention(RetentionPolicy.SOURCE) @IntDef({ ShowImeWithHardKeyboardType.UNKNOWN, ShowImeWithHardKeyboardType.FALSE, ShowImeWithHardKeyboardType.TRUE, }) private @interface ShowImeWithHardKeyboardType { int UNKNOWN = 0; int FALSE = 1; int TRUE = 2; } @ShowImeWithHardKeyboardType private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN; private final InputMethodService mService; private SettingsObserver(InputMethodService service) { super(new Handler(service.getMainLooper())); mService = service; } /** * A factory method that internally enforces two-phase initialization to make sure that the * object reference will not be escaped until the object is properly constructed. * * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence * this enforcement of two-phase initialization may be unnecessary at the moment.</p> * * @param service {@link InputMethodService} that needs to receive the callback. * @return {@link SettingsObserver} that is already registered to * {@link android.content.ContentResolver}. The caller must call * {@link SettingsObserver#unregister()}. */ public static SettingsObserver createAndRegister(InputMethodService service) { final SettingsObserver observer = new SettingsObserver(service); // The observer is properly constructed. Let's start accepting the event. service.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, observer); return observer; } void unregister() { mService.getContentResolver().unregisterContentObserver(this); } private boolean shouldShowImeWithHardKeyboard() { // Lazily initialize as needed. if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) { mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ? ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE; } switch (mShowImeWithHardKeyboard) { case ShowImeWithHardKeyboardType.TRUE: return true; case ShowImeWithHardKeyboardType.FALSE: return false; default: Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard); return false; } } @Override public void onChange(boolean selfChange, Uri uri) { final Uri showImeWithHardKeyboardUri = Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); if (showImeWithHardKeyboardUri.equals(uri)) { mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ? ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE; mService.updateInputViewShown(); } } @Override public String toString() { return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}"; } } private SettingsObserver mSettingsObserver; /** * You can call this to customize the theme used by your IME's window. * This theme should typically be one that derives from Loading Loading @@ -682,6 +781,7 @@ public class InputMethodService extends AbstractInputMethodService { super.setTheme(mTheme); super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); mSettingsObserver = SettingsObserver.createAndRegister(this); // If the previous IME has occupied non-empty inset in the screen, we need to decide whether // we continue to use the same size of the inset or update it mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0); Loading Loading @@ -764,6 +864,10 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.getWindow().setWindowAnimations(0); mWindow.dismiss(); } if (mSettingsObserver != null) { mSettingsObserver.unregister(); mSettingsObserver = null; } } /** Loading Loading @@ -1142,14 +1246,21 @@ public class InputMethodService extends AbstractInputMethodService { } /** * Override this to control when the soft input area should be shown to * the user. The default implementation only shows the input view when * there is no hard keyboard or the keyboard is hidden. If you change what * this returns, you will need to call {@link #updateInputViewShown()} * yourself whenever the returned value may have changed to have it * re-evaluated and applied. * Override this to control when the soft input area should be shown to the user. The default * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden * unless the user shows an intention to use software keyboard. If you change what this * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned * value may have changed to have it re-evaluated and applied. * * <p>When you override this method, it is recommended to call * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is * returned.</p> */ @CallSuper public boolean onEvaluateInputViewShown() { if (mSettingsObserver.shouldShowImeWithHardKeyboard()) { return true; } Configuration config = getResources().getConfiguration(); return config.keyboard == Configuration.KEYBOARD_NOKEYS || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; Loading Loading @@ -2483,5 +2594,6 @@ public class InputMethodService extends AbstractInputMethodService { + " touchableInsets=" + mTmpInsets.touchableInsets + " touchableRegion=" + mTmpInsets.touchableRegion); p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); p.println(" mSettingsObserver=" + mSettingsObserver); } }
services/core/java/com/android/server/wm/WindowManagerService.java +1 −25 Original line number Diff line number Diff line Loading @@ -578,31 +578,23 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowState> mTmpWindows = new ArrayList<>(); boolean mHardKeyboardAvailable; boolean mShowImeWithHardKeyboard; WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; SettingsObserver mSettingsObserver; private final class SettingsObserver extends ContentObserver { private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); public SettingsObserver() { super(new Handler()); ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL); } @Override public void onChange(boolean selfChange, Uri uri) { if (mShowImeWithHardKeyboardUri.equals(uri)) { updateShowImeWithHardKeyboard(); } else if (mDisplayInversionEnabledUri.equals(uri)) { if (mDisplayInversionEnabledUri.equals(uri)) { updateCircularDisplayMaskIfNeeded(); } } Loading Loading @@ -946,7 +938,6 @@ public class WindowManagerService extends IWindowManager.Stub mContext.registerReceiver(mBroadcastReceiver, filter); mSettingsObserver = new SettingsObserver(); updateShowImeWithHardKeyboard(); mHoldingScreenWakeLock = mPowerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM); Loading Loading @@ -7111,9 +7102,6 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); } if (mShowImeWithHardKeyboard) { config.keyboard = Configuration.KEYBOARD_NOKEYS; } // Let the policy update hidden states. config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; Loading @@ -7122,18 +7110,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence); } public void updateShowImeWithHardKeyboard() { synchronized (mWindowMap) { final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mCurrentUserId) == 1; if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) { mShowImeWithHardKeyboard = showImeWithHardKeyboard; mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } } void notifyHardKeyboardStatusChange() { final boolean available; final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener; Loading