Loading core/java/android/inputmethodservice/InputMethodService.java +7 −0 Original line number Diff line number Diff line Loading @@ -3363,6 +3363,13 @@ public class InputMethodService extends AbstractInputMethodService { return true; } return false; } else if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE && KeyEvent.metaStateHasModifiers( event.getMetaState() & ~KeyEvent.META_SHIFT_MASK, KeyEvent.META_CTRL_ON)) { if (mDecorViewVisible && mWindowVisible) { int direction = (event.getMetaState() & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1; mPrivOps.switchKeyboardLayoutAsync(direction); return true; } } return doMovementKey(keyCode, event, MOVEMENT_DOWN); } Loading core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -46,4 +46,5 @@ oneway interface IInputMethodPrivilegedOperations { in @nullable ImeTracker.Token statsToken); void onStylusHandwritingReady(int requestId, int pid); void resetStylusHandwriting(int requestId); void switchKeyboardLayoutAsync(int direction); } core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +16 −0 Original line number Diff line number Diff line Loading @@ -431,4 +431,20 @@ public final class InputMethodPrivilegedOperations { throw e.rethrowFromSystemServer(); } } /** * Calls {@link IInputMethodPrivilegedOperations#switchKeyboardLayoutAsync(int)}. */ @AnyThread public void switchKeyboardLayoutAsync(int direction) { final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); if (ops == null) { return; } try { ops.switchKeyboardLayoutAsync(direction); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +53 −32 Original line number Diff line number Diff line Loading @@ -5529,6 +5529,42 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return canAccess; } @GuardedBy("ImfLock.class") private void switchKeyboardLayoutLocked(int direction) { final InputMethodInfo currentImi = mMethodMap.get(getSelectedMethodIdLocked()); if (currentImi == null) { return; } final InputMethodSubtypeHandle currentSubtypeHandle = InputMethodSubtypeHandle.of(currentImi, mCurrentSubtype); final InputMethodSubtypeHandle nextSubtypeHandle = mHardwareKeyboardShortcutController.onSubtypeSwitch(currentSubtypeHandle, direction > 0); if (nextSubtypeHandle == null) { return; } final InputMethodInfo nextImi = mMethodMap.get(nextSubtypeHandle.getImeId()); if (nextImi == null) { return; } final int subtypeCount = nextImi.getSubtypeCount(); if (subtypeCount == 0) { if (nextSubtypeHandle.equals(InputMethodSubtypeHandle.of(nextImi, null))) { setInputMethodLocked(nextImi.getId(), NOT_A_SUBTYPE_ID); } return; } for (int i = 0; i < subtypeCount; ++i) { if (nextSubtypeHandle.equals( InputMethodSubtypeHandle.of(nextImi, nextImi.getSubtypeAt(i)))) { setInputMethodLocked(nextImi.getId(), i); return; } } } private void publishLocalService() { LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl()); } Loading Loading @@ -5734,38 +5770,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void switchKeyboardLayout(int direction) { synchronized (ImfLock.class) { final InputMethodInfo currentImi = mMethodMap.get(getSelectedMethodIdLocked()); if (currentImi == null) { return; } final InputMethodSubtypeHandle currentSubtypeHandle = InputMethodSubtypeHandle.of(currentImi, mCurrentSubtype); final InputMethodSubtypeHandle nextSubtypeHandle = mHardwareKeyboardShortcutController.onSubtypeSwitch(currentSubtypeHandle, direction > 0); if (nextSubtypeHandle == null) { return; } final InputMethodInfo nextImi = mMethodMap.get(nextSubtypeHandle.getImeId()); if (nextImi == null) { return; } final int subtypeCount = nextImi.getSubtypeCount(); if (subtypeCount == 0) { if (nextSubtypeHandle.equals(InputMethodSubtypeHandle.of(nextImi, null))) { setInputMethodLocked(nextImi.getId(), NOT_A_SUBTYPE_ID); } return; } for (int i = 0; i < subtypeCount; ++i) { if (nextSubtypeHandle.equals( InputMethodSubtypeHandle.of(nextImi, nextImi.getSubtypeAt(i)))) { setInputMethodLocked(nextImi.getId(), i); return; } } switchKeyboardLayoutLocked(direction); } } Loading Loading @@ -6767,5 +6772,21 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub public void resetStylusHandwriting(int requestId) { mImms.resetStylusHandwriting(requestId); } @BinderThread @Override public void switchKeyboardLayoutAsync(int direction) { synchronized (ImfLock.class) { if (!mImms.calledWithValidTokenLocked(mToken)) { return; } final long ident = Binder.clearCallingIdentity(); try { mImms.switchKeyboardLayoutLocked(direction); } finally { Binder.restoreCallingIdentity(ident); } } } } } services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; import android.util.Log; import android.view.KeyEvent; import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; Loading Loading @@ -598,6 +599,28 @@ public class InputMethodServiceTest { false /* orientationPortrait */); } @Test public void switchesKeyboardLayout_withShortcut_onlyIfImeVisible() throws Exception { setShowImeWithHardKeyboard(true /* enabled */); assertThat(mInputMethodService.isInputViewShown()).isFalse(); assertThat(mInputMethodService.onKeyDown(KeyEvent.KEYCODE_SPACE, new KeyEvent(0 /* downTime */, 0 /* eventTime */, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE, 0 /* repeat */, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON))).isFalse(); verifyInputViewStatusOnMainSync( () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(), true /* expected */, true /* inputViewStarted */); assertThat(mInputMethodService.isInputViewShown()).isTrue(); assertThat(mInputMethodService.onKeyDown(KeyEvent.KEYCODE_SPACE, new KeyEvent(0 /* downTime */, 0 /* eventTime */, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE, 0 /* repeat */, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON))).isTrue(); } /** * This checks that when the system navigation bar is not created (e.g. emulator), * then the IME caption bar is also not created. Loading Loading
core/java/android/inputmethodservice/InputMethodService.java +7 −0 Original line number Diff line number Diff line Loading @@ -3363,6 +3363,13 @@ public class InputMethodService extends AbstractInputMethodService { return true; } return false; } else if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE && KeyEvent.metaStateHasModifiers( event.getMetaState() & ~KeyEvent.META_SHIFT_MASK, KeyEvent.META_CTRL_ON)) { if (mDecorViewVisible && mWindowVisible) { int direction = (event.getMetaState() & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1; mPrivOps.switchKeyboardLayoutAsync(direction); return true; } } return doMovementKey(keyCode, event, MOVEMENT_DOWN); } Loading
core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -46,4 +46,5 @@ oneway interface IInputMethodPrivilegedOperations { in @nullable ImeTracker.Token statsToken); void onStylusHandwritingReady(int requestId, int pid); void resetStylusHandwriting(int requestId); void switchKeyboardLayoutAsync(int direction); }
core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +16 −0 Original line number Diff line number Diff line Loading @@ -431,4 +431,20 @@ public final class InputMethodPrivilegedOperations { throw e.rethrowFromSystemServer(); } } /** * Calls {@link IInputMethodPrivilegedOperations#switchKeyboardLayoutAsync(int)}. */ @AnyThread public void switchKeyboardLayoutAsync(int direction) { final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); if (ops == null) { return; } try { ops.switchKeyboardLayoutAsync(direction); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +53 −32 Original line number Diff line number Diff line Loading @@ -5529,6 +5529,42 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return canAccess; } @GuardedBy("ImfLock.class") private void switchKeyboardLayoutLocked(int direction) { final InputMethodInfo currentImi = mMethodMap.get(getSelectedMethodIdLocked()); if (currentImi == null) { return; } final InputMethodSubtypeHandle currentSubtypeHandle = InputMethodSubtypeHandle.of(currentImi, mCurrentSubtype); final InputMethodSubtypeHandle nextSubtypeHandle = mHardwareKeyboardShortcutController.onSubtypeSwitch(currentSubtypeHandle, direction > 0); if (nextSubtypeHandle == null) { return; } final InputMethodInfo nextImi = mMethodMap.get(nextSubtypeHandle.getImeId()); if (nextImi == null) { return; } final int subtypeCount = nextImi.getSubtypeCount(); if (subtypeCount == 0) { if (nextSubtypeHandle.equals(InputMethodSubtypeHandle.of(nextImi, null))) { setInputMethodLocked(nextImi.getId(), NOT_A_SUBTYPE_ID); } return; } for (int i = 0; i < subtypeCount; ++i) { if (nextSubtypeHandle.equals( InputMethodSubtypeHandle.of(nextImi, nextImi.getSubtypeAt(i)))) { setInputMethodLocked(nextImi.getId(), i); return; } } } private void publishLocalService() { LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl()); } Loading Loading @@ -5734,38 +5770,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void switchKeyboardLayout(int direction) { synchronized (ImfLock.class) { final InputMethodInfo currentImi = mMethodMap.get(getSelectedMethodIdLocked()); if (currentImi == null) { return; } final InputMethodSubtypeHandle currentSubtypeHandle = InputMethodSubtypeHandle.of(currentImi, mCurrentSubtype); final InputMethodSubtypeHandle nextSubtypeHandle = mHardwareKeyboardShortcutController.onSubtypeSwitch(currentSubtypeHandle, direction > 0); if (nextSubtypeHandle == null) { return; } final InputMethodInfo nextImi = mMethodMap.get(nextSubtypeHandle.getImeId()); if (nextImi == null) { return; } final int subtypeCount = nextImi.getSubtypeCount(); if (subtypeCount == 0) { if (nextSubtypeHandle.equals(InputMethodSubtypeHandle.of(nextImi, null))) { setInputMethodLocked(nextImi.getId(), NOT_A_SUBTYPE_ID); } return; } for (int i = 0; i < subtypeCount; ++i) { if (nextSubtypeHandle.equals( InputMethodSubtypeHandle.of(nextImi, nextImi.getSubtypeAt(i)))) { setInputMethodLocked(nextImi.getId(), i); return; } } switchKeyboardLayoutLocked(direction); } } Loading Loading @@ -6767,5 +6772,21 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub public void resetStylusHandwriting(int requestId) { mImms.resetStylusHandwriting(requestId); } @BinderThread @Override public void switchKeyboardLayoutAsync(int direction) { synchronized (ImfLock.class) { if (!mImms.calledWithValidTokenLocked(mToken)) { return; } final long ident = Binder.clearCallingIdentity(); try { mImms.switchKeyboardLayoutLocked(direction); } finally { Binder.restoreCallingIdentity(ident); } } } } }
services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; import android.util.Log; import android.view.KeyEvent; import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; Loading Loading @@ -598,6 +599,28 @@ public class InputMethodServiceTest { false /* orientationPortrait */); } @Test public void switchesKeyboardLayout_withShortcut_onlyIfImeVisible() throws Exception { setShowImeWithHardKeyboard(true /* enabled */); assertThat(mInputMethodService.isInputViewShown()).isFalse(); assertThat(mInputMethodService.onKeyDown(KeyEvent.KEYCODE_SPACE, new KeyEvent(0 /* downTime */, 0 /* eventTime */, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE, 0 /* repeat */, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON))).isFalse(); verifyInputViewStatusOnMainSync( () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(), true /* expected */, true /* inputViewStarted */); assertThat(mInputMethodService.isInputViewShown()).isTrue(); assertThat(mInputMethodService.onKeyDown(KeyEvent.KEYCODE_SPACE, new KeyEvent(0 /* downTime */, 0 /* eventTime */, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE, 0 /* repeat */, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON))).isTrue(); } /** * This checks that when the system navigation bar is not created (e.g. emulator), * then the IME caption bar is also not created. Loading