diff --git a/samples/MultiClientInputMethod/Android.bp b/samples/MultiClientInputMethod/Android.bp deleted file mode 100644 index 32c6ae006..000000000 --- a/samples/MultiClientInputMethod/Android.bp +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package { - // See: http://go/android-license-faq - default_applicable_licenses: ["Android-Apache-2.0"], -} - -android_app { - name: "MultiClientInputMethod", - srcs: ["**/*.java"], - platform_apis: true, - certificate: "platform", - privileged: true, - dex_preopt: { - enabled: false, - }, -} diff --git a/samples/MultiClientInputMethod/AndroidManifest.xml b/samples/MultiClientInputMethod/AndroidManifest.xml deleted file mode 100755 index 54087769b..000000000 --- a/samples/MultiClientInputMethod/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - diff --git a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_delete.png b/samples/MultiClientInputMethod/res/drawable/sym_keyboard_delete.png deleted file mode 100755 index 5139c7179..000000000 Binary files a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_delete.png and /dev/null differ diff --git a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_done.png b/samples/MultiClientInputMethod/res/drawable/sym_keyboard_done.png deleted file mode 100755 index 471c5021b..000000000 Binary files a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_done.png and /dev/null differ diff --git a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_return.png b/samples/MultiClientInputMethod/res/drawable/sym_keyboard_return.png deleted file mode 100755 index 5a5670c32..000000000 Binary files a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_return.png and /dev/null differ diff --git a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_search.png b/samples/MultiClientInputMethod/res/drawable/sym_keyboard_search.png deleted file mode 100755 index e72cde3bb..000000000 Binary files a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_search.png and /dev/null differ diff --git a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_shift.png b/samples/MultiClientInputMethod/res/drawable/sym_keyboard_shift.png deleted file mode 100755 index 275769618..000000000 Binary files a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_shift.png and /dev/null differ diff --git a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_space.png b/samples/MultiClientInputMethod/res/drawable/sym_keyboard_space.png deleted file mode 100755 index cef2daa5d..000000000 Binary files a/samples/MultiClientInputMethod/res/drawable/sym_keyboard_space.png and /dev/null differ diff --git a/samples/MultiClientInputMethod/res/layout/input.xml b/samples/MultiClientInputMethod/res/layout/input.xml deleted file mode 100755 index 528a15361..000000000 --- a/samples/MultiClientInputMethod/res/layout/input.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/samples/MultiClientInputMethod/res/values/config.xml b/samples/MultiClientInputMethod/res/values/config.xml deleted file mode 100644 index 133b73e67..000000000 --- a/samples/MultiClientInputMethod/res/values/config.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/samples/MultiClientInputMethod/res/xml/method.xml b/samples/MultiClientInputMethod/res/xml/method.xml deleted file mode 100644 index abac23b5a..000000000 --- a/samples/MultiClientInputMethod/res/xml/method.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - diff --git a/samples/MultiClientInputMethod/res/xml/qwerty.xml b/samples/MultiClientInputMethod/res/xml/qwerty.xml deleted file mode 100755 index 05164d3d2..000000000 --- a/samples/MultiClientInputMethod/res/xml/qwerty.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/MultiClientInputMethod/res/xml/symbols.xml b/samples/MultiClientInputMethod/res/xml/symbols.xml deleted file mode 100755 index df4692b36..000000000 --- a/samples/MultiClientInputMethod/res/xml/symbols.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/MultiClientInputMethod/res/xml/symbols_shift.xml b/samples/MultiClientInputMethod/res/xml/symbols_shift.xml deleted file mode 100755 index fe771b408..000000000 --- a/samples/MultiClientInputMethod/res/xml/symbols_shift.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/ClientCallbackImpl.java b/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/ClientCallbackImpl.java deleted file mode 100644 index 23e2757de..000000000 --- a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/ClientCallbackImpl.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.multiclientinputmethod; - -import android.inputmethodservice.MultiClientInputMethodServiceDelegate; -import android.os.Bundle; -import android.os.Looper; -import android.os.ResultReceiver; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.WindowManager; -import android.view.inputmethod.CompletionInfo; -import android.view.inputmethod.CursorAnchorInfo; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; - -final class ClientCallbackImpl implements MultiClientInputMethodServiceDelegate.ClientCallback { - private static final String TAG = "ClientCallbackImpl"; - private static final boolean DEBUG = false; - - private final MultiClientInputMethodServiceDelegate mDelegate; - private final SoftInputWindowManager mSoftInputWindowManager; - private final int mClientId; - private final int mUid; - private final int mPid; - private final int mSelfReportedDisplayId; - private final KeyEvent.DispatcherState mDispatcherState; - private final Looper mLooper; - private final MultiClientInputMethod mInputMethod; - - ClientCallbackImpl(MultiClientInputMethod inputMethod, - MultiClientInputMethodServiceDelegate delegate, - SoftInputWindowManager softInputWindowManager, int clientId, int uid, int pid, - int selfReportedDisplayId) { - mInputMethod = inputMethod; - mDelegate = delegate; - mSoftInputWindowManager = softInputWindowManager; - mClientId = clientId; - mUid = uid; - mPid = pid; - mSelfReportedDisplayId = selfReportedDisplayId; - mDispatcherState = new KeyEvent.DispatcherState(); - // For simplicity, we use the main looper for this sample. - // To use other looper thread, make sure that the IME Window also runs on the same looper - // and introduce an appropriate synchronization mechanism instead of directly accessing - // MultiClientInputMethod#mDisplayToLastClientId. - mLooper = Looper.getMainLooper(); - } - - KeyEvent.DispatcherState getDispatcherState() { - return mDispatcherState; - } - - Looper getLooper() { - return mLooper; - } - - @Override - public void onAppPrivateCommand(String action, Bundle data) { - } - - @Override - public void onDisplayCompletions(CompletionInfo[] completions) { - } - - @Override - public void onFinishSession() { - if (DEBUG) { - Log.v(TAG, "onFinishSession clientId=" + mClientId); - } - final SoftInputWindow window = - mSoftInputWindowManager.getSoftInputWindow(mSelfReportedDisplayId); - if (window == null) { - return; - } - // SoftInputWindow also needs to be cleaned up when this IME client is still associated with - // it. - if (mClientId == window.getClientId()) { - window.onFinishClient(); - } - } - - @Override - public void onHideSoftInput(int flags, ResultReceiver resultReceiver) { - if (DEBUG) { - Log.v(TAG, "onHideSoftInput clientId=" + mClientId + " flags=" + flags); - } - final SoftInputWindow window = - mSoftInputWindowManager.getSoftInputWindow(mSelfReportedDisplayId); - if (window == null) { - return; - } - // Seems that the Launcher3 has a bug to call onHideSoftInput() too early so we cannot - // enforce clientId check yet. - // TODO: Check clientId like we do so for onShowSoftInput(). - window.hide(); - } - - @Override - public void onShowSoftInput(int flags, ResultReceiver resultReceiver) { - if (DEBUG) { - Log.v(TAG, "onShowSoftInput clientId=" + mClientId + " flags=" + flags); - } - final SoftInputWindow window = - mSoftInputWindowManager.getSoftInputWindow(mSelfReportedDisplayId); - if (window == null) { - return; - } - if (mClientId != window.getClientId()) { - Log.w(TAG, "onShowSoftInput() from a background client is ignored." - + " windowClientId=" + window.getClientId() - + " clientId=" + mClientId); - return; - } - window.show(); - } - - @Override - public void onStartInputOrWindowGainedFocus(InputConnection inputConnection, - EditorInfo editorInfo, int startInputFlags, int softInputMode, int targetWindowHandle) { - if (DEBUG) { - Log.v(TAG, "onStartInputOrWindowGainedFocus clientId=" + mClientId - + " editorInfo=" + editorInfo - + " startInputFlags=" - + InputMethodDebug.startInputFlagsToString(startInputFlags) - + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode) - + " targetWindowHandle=" + targetWindowHandle); - } - - final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; - final boolean forwardNavigation = - (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; - - final SoftInputWindow window = - mSoftInputWindowManager.getOrCreateSoftInputWindow(mSelfReportedDisplayId); - if (window == null) { - return; - } - - if (window.getTargetWindowHandle() != targetWindowHandle) { - // Target window has changed. Report new IME target window to the system. - mDelegate.reportImeWindowTarget( - mClientId, targetWindowHandle, window.getWindow().getAttributes().token); - } - final int lastClientId = mInputMethod.mDisplayToLastClientId.get(mSelfReportedDisplayId); - if (lastClientId != mClientId) { - // deactivate previous client and activate current. - mDelegate.setActive(lastClientId, false /* active */); - mDelegate.setActive(mClientId, true /* active */); - } - if (inputConnection == null || editorInfo == null) { - // Placeholder InputConnection case. - if (window.getClientId() == mClientId) { - // Special hack for temporary focus changes (e.g. notification shade). - // If we have already established a connection to this client, and if a placeholder - // InputConnection is notified, just ignore this event. - } else { - window.onDummyStartInput(mClientId, targetWindowHandle); - } - } else { - window.onStartInput(mClientId, targetWindowHandle, inputConnection); - } - - switch (state) { - case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: - if (forwardNavigation) { - window.show(); - } - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: - window.show(); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: - if (forwardNavigation) { - window.hide(); - } - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: - window.hide(); - break; - } - mInputMethod.mDisplayToLastClientId.put(mSelfReportedDisplayId, mClientId); - } - - @Override - public void onUpdateCursorAnchorInfo(CursorAnchorInfo info) { - } - - @Override - public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, - int candidatesStart, int candidatesEnd) { - } - - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - return false; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (DEBUG) { - Log.v(TAG, "onKeyDown clientId=" + mClientId + " keyCode=" + keyCode - + " event=" + event); - } - if (keyCode == KeyEvent.KEYCODE_BACK) { - final SoftInputWindow window = - mSoftInputWindowManager.getSoftInputWindow(mSelfReportedDisplayId); - if (window != null && window.isShowing()) { - event.startTracking(); - return true; - } - } - return false; - } - - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - return false; - } - - @Override - public boolean onKeyMultiple(int keyCode, KeyEvent event) { - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (DEBUG) { - Log.v(TAG, "onKeyUp clientId=" + mClientId + "keyCode=" + keyCode - + " event=" + event); - } - if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() && !event.isCanceled()) { - final SoftInputWindow window = - mSoftInputWindowManager.getSoftInputWindow(mSelfReportedDisplayId); - if (window != null && window.isShowing()) { - window.hide(); - return true; - } - } - return false; - } - - @Override - public boolean onTrackballEvent(MotionEvent event) { - return false; - } -} diff --git a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/InputMethodDebug.java b/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/InputMethodDebug.java deleted file mode 100644 index dd11d212a..000000000 --- a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/InputMethodDebug.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.multiclientinputmethod; - -import android.view.WindowManager; - -import com.android.internal.inputmethod.StartInputFlags; - -import java.util.StringJoiner; - -/** - * Provides useful methods for debugging. - */ -final class InputMethodDebug { - - /** - * Not intended to be instantiated. - */ - private InputMethodDebug() { - } - - /** - * Converts soft input flags to {@link String} for debug logging. - * - * @param softInputMode integer constant for soft input flags. - * @return {@link String} message corresponds for the given {@code softInputMode}. - */ - public static String softInputModeToString(int softInputMode) { - final StringJoiner joiner = new StringJoiner("|"); - final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; - final int adjust = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; - final boolean isForwardNav = - (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; - - switch (state) { - case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: - joiner.add("STATE_UNSPECIFIED"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: - joiner.add("STATE_UNCHANGED"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: - joiner.add("STATE_HIDDEN"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: - joiner.add("STATE_ALWAYS_HIDDEN"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: - joiner.add("STATE_VISIBLE"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: - joiner.add("STATE_ALWAYS_VISIBLE"); - break; - default: - joiner.add("STATE_UNKNOWN(" + state + ")"); - break; - } - - switch (adjust) { - case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED: - joiner.add("ADJUST_UNSPECIFIED"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE: - joiner.add("ADJUST_RESIZE"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN: - joiner.add("ADJUST_PAN"); - break; - case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING: - joiner.add("ADJUST_NOTHING"); - break; - default: - joiner.add("ADJUST_UNKNOWN(" + adjust + ")"); - break; - } - - if (isForwardNav) { - // This is a special bit that is set by the system only during the window navigation. - joiner.add("IS_FORWARD_NAVIGATION"); - } - - return joiner.setEmptyValue("(none)").toString(); - } - - /** - * Converts start input flags to {@link String} for debug logging. - * - * @param startInputFlags integer constant for start input flags. - * @return {@link String} message corresponds for the given {@code startInputFlags}. - */ - public static String startInputFlagsToString(int startInputFlags) { - final StringJoiner joiner = new StringJoiner("|"); - if ((startInputFlags & StartInputFlags.VIEW_HAS_FOCUS) != 0) { - joiner.add("VIEW_HAS_FOCUS"); - } - if ((startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) { - joiner.add("IS_TEXT_EDITOR"); - } - if ((startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0) { - joiner.add("INITIAL_CONNECTION"); - } - - return joiner.setEmptyValue("(none)").toString(); - } -} diff --git a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/MultiClientInputMethod.java b/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/MultiClientInputMethod.java deleted file mode 100644 index a3f9d1b74..000000000 --- a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/MultiClientInputMethod.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.multiclientinputmethod; - -import android.annotation.NonNull; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManager.DisplayListener; -import android.inputmethodservice.MultiClientInputMethodServiceDelegate; -import android.os.IBinder; -import android.util.Log; -import android.util.SparseIntArray; -import android.view.Display; - -/** - * A {@link Service} that implements multi-client IME protocol. - */ -public final class MultiClientInputMethod extends Service implements DisplayListener { - private static final String TAG = "MultiClientInputMethod"; - private static final boolean DEBUG = false; - - // last client that had active InputConnection for a given displayId. - final SparseIntArray mDisplayToLastClientId = new SparseIntArray(); - // Mapping table from the display where IME is attached to the display where IME window will be - // shown. Assumes that missing display will use the same display for the IME window. - SparseIntArray mInputDisplayToImeDisplay; - SoftInputWindowManager mSoftInputWindowManager; - MultiClientInputMethodServiceDelegate mDelegate; - - private DisplayManager mDisplayManager; - - @Override - public void onCreate() { - if (DEBUG) { - Log.v(TAG, "onCreate"); - } - mInputDisplayToImeDisplay = buildInputDisplayToImeDisplay(); - mDelegate = MultiClientInputMethodServiceDelegate.create(this, - new MultiClientInputMethodServiceDelegate.ServiceCallback() { - @Override - public void initialized() { - if (DEBUG) { - Log.i(TAG, "initialized"); - } - } - - @Override - public void addClient(int clientId, int uid, int pid, - int selfReportedDisplayId) { - int imeDisplayId = mInputDisplayToImeDisplay.get(selfReportedDisplayId, - selfReportedDisplayId); - final ClientCallbackImpl callback = new ClientCallbackImpl( - MultiClientInputMethod.this, mDelegate, - mSoftInputWindowManager, clientId, uid, pid, imeDisplayId); - if (DEBUG) { - Log.v(TAG, "addClient clientId=" + clientId + " uid=" + uid - + " pid=" + pid + " displayId=" + selfReportedDisplayId - + " imeDisplayId=" + imeDisplayId); - } - - mDelegate.acceptClient(clientId, callback, callback.getDispatcherState(), - callback.getLooper()); - } - - @Override - public void removeClient(int clientId) { - if (DEBUG) { - Log.v(TAG, "removeClient clientId=" + clientId); - } - } - }); - mSoftInputWindowManager = new SoftInputWindowManager(this, mDelegate); - } - - @Override - public void onDisplayAdded(int displayId) { - mInputDisplayToImeDisplay = buildInputDisplayToImeDisplay(); - } - - @Override - public void onDisplayRemoved(int displayId) { - mDisplayToLastClientId.delete(displayId); - } - - @Override - public void onDisplayChanged(int displayId) { - } - - @Override - public IBinder onBind(Intent intent) { - if (DEBUG) { - Log.v(TAG, "onBind intent=" + intent); - } - mDisplayManager = getApplicationContext().getSystemService(DisplayManager.class); - mDisplayManager.registerDisplayListener(this, getMainThreadHandler()); - return mDelegate.onBind(intent); - } - - @Override - public boolean onUnbind(Intent intent) { - if (DEBUG) { - Log.v(TAG, "onUnbind intent=" + intent); - } - if (mDisplayManager != null) { - mDisplayManager.unregisterDisplayListener(this); - } - return mDelegate.onUnbind(intent); - } - - @Override - public void onDestroy() { - if (DEBUG) { - Log.v(TAG, "onDestroy"); - } - mDelegate.onDestroy(); - } - - @NonNull - private SparseIntArray buildInputDisplayToImeDisplay() { - Context context = getApplicationContext(); - String config[] = context.getResources().getStringArray( - R.array.config_inputDisplayToImeDisplay); - - SparseIntArray inputDisplayToImeDisplay = new SparseIntArray(); - Display[] displays = context.getSystemService(DisplayManager.class).getDisplays(); - for (String item: config) { - String[] pair = item.split("/"); - if (pair.length != 2) { - Log.w(TAG, "Skip illegal config: " + item); - continue; - } - int inputDisplay = findDisplayId(displays, pair[0]); - int imeDisplay = findDisplayId(displays, pair[1]); - if (inputDisplay != Display.INVALID_DISPLAY && imeDisplay != Display.INVALID_DISPLAY) { - inputDisplayToImeDisplay.put(inputDisplay, imeDisplay); - } - } - return inputDisplayToImeDisplay; - } - - private static int findDisplayId(Display displays[], String regexp) { - for (Display display: displays) { - if (display.getUniqueId().matches(regexp)) { - int displayId = display.getDisplayId(); - if (DEBUG) { - Log.v(TAG, regexp + " matches displayId=" + displayId); - } - return displayId; - } - } - Log.w(TAG, "Can't find the display of " + regexp); - return Display.INVALID_DISPLAY; - } -} diff --git a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/NoopKeyboardActionListener.java b/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/NoopKeyboardActionListener.java deleted file mode 100644 index 94248ce52..000000000 --- a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/NoopKeyboardActionListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.multiclientinputmethod; - -import android.inputmethodservice.KeyboardView; - -/** - * Provides the no-op implementation of {@link KeyboardView.OnKeyboardActionListener} - */ -class NoopKeyboardActionListener implements KeyboardView.OnKeyboardActionListener { - @Override - public void onPress(int primaryCode) { - } - - @Override - public void onRelease(int primaryCode) { - } - - @Override - public void onKey(int primaryCode, int[] keyCodes) { - } - - @Override - public void onText(CharSequence text) { - } - - @Override - public void swipeLeft() { - } - - @Override - public void swipeRight() { - } - - @Override - public void swipeDown() { - } - - @Override - public void swipeUp() { - } -} diff --git a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/SoftInputWindow.java b/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/SoftInputWindow.java deleted file mode 100644 index 93e60a7a9..000000000 --- a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/SoftInputWindow.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.multiclientinputmethod; - -import android.app.Dialog; -import android.content.Context; -import android.inputmethodservice.Keyboard; -import android.inputmethodservice.KeyboardView; -import android.inputmethodservice.MultiClientInputMethodServiceDelegate; -import android.os.IBinder; -import android.util.Log; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.ViewGroup; -import android.view.WindowManager.LayoutParams; -import android.view.inputmethod.InputConnection; -import android.widget.LinearLayout; - -import java.util.Arrays; - -final class SoftInputWindow extends Dialog { - private static final String TAG = "SoftInputWindow"; - private static final boolean DEBUG = false; - - private final KeyboardView mKeyboardView; - - private final Keyboard mQwertygKeyboard; - private final Keyboard mSymbolKeyboard; - private final Keyboard mSymbolShiftKeyboard; - - private int mClientId = MultiClientInputMethodServiceDelegate.INVALID_CLIENT_ID; - private int mTargetWindowHandle = MultiClientInputMethodServiceDelegate.INVALID_WINDOW_HANDLE; - - private static final KeyboardView.OnKeyboardActionListener sNoopListener = - new NoopKeyboardActionListener(); - - SoftInputWindow(Context context, IBinder token) { - super(context, android.R.style.Theme_DeviceDefault_InputMethod); - - final LayoutParams lp = getWindow().getAttributes(); - lp.type = LayoutParams.TYPE_INPUT_METHOD; - lp.setTitle("InputMethod"); - lp.gravity = Gravity.BOTTOM; - lp.width = LayoutParams.MATCH_PARENT; - lp.height = LayoutParams.WRAP_CONTENT; - lp.token = token; - getWindow().setAttributes(lp); - - final int windowSetFlags = LayoutParams.FLAG_LAYOUT_IN_SCREEN - | LayoutParams.FLAG_NOT_FOCUSABLE - | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - final int windowModFlags = LayoutParams.FLAG_LAYOUT_IN_SCREEN - | LayoutParams.FLAG_NOT_FOCUSABLE - | LayoutParams.FLAG_DIM_BEHIND - | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - getWindow().setFlags(windowSetFlags, windowModFlags); - - final LinearLayout layout = new LinearLayout(context); - layout.setOrientation(LinearLayout.VERTICAL); - - mKeyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.input, null); - mQwertygKeyboard = new Keyboard(context, R.xml.qwerty); - mSymbolKeyboard = new Keyboard(context, R.xml.symbols); - mSymbolShiftKeyboard = new Keyboard(context, R.xml.symbols_shift); - mKeyboardView.setKeyboard(mQwertygKeyboard); - mKeyboardView.setOnKeyboardActionListener(sNoopListener); - - // TODO(b/158663354): Disabling keyboard popped preview key since it is currently broken. - mKeyboardView.setPreviewEnabled(false); - - layout.addView(mKeyboardView); - - setContentView(layout, new ViewGroup.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - // TODO: Check why we need to call this. - getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - } - - int getClientId() { - return mClientId; - } - - int getTargetWindowHandle() { - return mTargetWindowHandle; - } - - boolean isQwertyKeyboard() { - return mKeyboardView.getKeyboard() == mQwertygKeyboard; - } - - boolean isSymbolKeyboard() { - Keyboard keyboard = mKeyboardView.getKeyboard(); - return keyboard == mSymbolKeyboard || keyboard == mSymbolShiftKeyboard; - } - - void onFinishClient() { - mKeyboardView.setOnKeyboardActionListener(sNoopListener); - mClientId = MultiClientInputMethodServiceDelegate.INVALID_CLIENT_ID; - mTargetWindowHandle = MultiClientInputMethodServiceDelegate.INVALID_WINDOW_HANDLE; - } - - void onDummyStartInput(int clientId, int targetWindowHandle) { - if (DEBUG) { - Log.v(TAG, "onDummyStartInput clientId=" + clientId - + " targetWindowHandle=" + targetWindowHandle); - } - mKeyboardView.setOnKeyboardActionListener(sNoopListener); - mClientId = clientId; - mTargetWindowHandle = targetWindowHandle; - } - - void onStartInput(int clientId, int targetWindowHandle, InputConnection inputConnection) { - if (DEBUG) { - Log.v(TAG, "onStartInput clientId=" + clientId - + " targetWindowHandle=" + targetWindowHandle); - } - mClientId = clientId; - mTargetWindowHandle = targetWindowHandle; - mKeyboardView.setOnKeyboardActionListener(new NoopKeyboardActionListener() { - @Override - public void onKey(int primaryCode, int[] keyCodes) { - if (DEBUG) { - Log.v(TAG, "onKey clientId=" + clientId + " primaryCode=" + primaryCode - + " keyCodes=" + Arrays.toString(keyCodes)); - } - boolean isShifted = isShifted(); // Store the current state before resetting it. - resetShift(); - switch (primaryCode) { - case Keyboard.KEYCODE_CANCEL: - hide(); - break; - case Keyboard.KEYCODE_DELETE: - inputConnection.sendKeyEvent( - new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); - inputConnection.sendKeyEvent( - new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); - break; - case Keyboard.KEYCODE_MODE_CHANGE: - handleSwitchKeyboard(); - break; - case Keyboard.KEYCODE_SHIFT: - handleShift(isShifted); - break; - default: - handleCharacter(inputConnection, primaryCode, isShifted); - break; - } - } - - @Override - public void onText(CharSequence text) { - if (DEBUG) { - Log.v(TAG, "onText clientId=" + clientId + " text=" + text); - } - if (inputConnection == null) { - return; - } - inputConnection.commitText(text, 0); - } - }); - } - - void handleSwitchKeyboard() { - if (isQwertyKeyboard()) { - mKeyboardView.setKeyboard(mSymbolKeyboard); - } else { - mKeyboardView.setKeyboard(mQwertygKeyboard); - } - - } - - boolean isShifted() { - return mKeyboardView.isShifted(); - } - - void resetShift() { - if (isSymbolKeyboard() && isShifted()) { - mKeyboardView.setKeyboard(mSymbolKeyboard); - } - mKeyboardView.setShifted(false); - } - - void handleShift(boolean isShifted) { - if (isSymbolKeyboard()) { - mKeyboardView.setKeyboard(isShifted ? mSymbolKeyboard : mSymbolShiftKeyboard); - } - mKeyboardView.setShifted(!isShifted); - } - - void handleCharacter(InputConnection inputConnection, int primaryCode, boolean isShifted) { - if (isQwertyKeyboard() && isShifted) { - primaryCode = Character.toUpperCase(primaryCode); - } - inputConnection.commitText(String.valueOf((char) primaryCode), 1); - } -} diff --git a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/SoftInputWindowManager.java b/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/SoftInputWindowManager.java deleted file mode 100644 index f97c44980..000000000 --- a/samples/MultiClientInputMethod/src/com/example/android/multiclientinputmethod/SoftInputWindowManager.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.multiclientinputmethod; - -import android.content.Context; -import android.hardware.display.DisplayManager; -import android.inputmethodservice.MultiClientInputMethodServiceDelegate; -import android.os.IBinder; -import android.util.SparseArray; -import android.view.Display; - -final class SoftInputWindowManager { - private final Context mContext; - private final MultiClientInputMethodServiceDelegate mDelegate; - private final SparseArray mSoftInputWindows = new SparseArray<>(); - - SoftInputWindowManager(Context context, MultiClientInputMethodServiceDelegate delegate) { - mContext = context; - mDelegate = delegate; - } - - SoftInputWindow getOrCreateSoftInputWindow(int displayId) { - final SoftInputWindow existingWindow = mSoftInputWindows.get(displayId); - if (existingWindow != null) { - return existingWindow; - } - - final Display display = - mContext.getSystemService(DisplayManager.class).getDisplay(displayId); - if (display == null) { - return null; - } - final IBinder windowToken = mDelegate.createInputMethodWindowToken(displayId); - if (windowToken == null) { - return null; - } - - final Context displayContext = mContext.createDisplayContext(display); - final SoftInputWindow newWindow = new SoftInputWindow(displayContext, windowToken); - mSoftInputWindows.put(displayId, newWindow); - return newWindow; - } - - SoftInputWindow getSoftInputWindow(int displayId) { - return mSoftInputWindows.get(displayId); - } -}