api-impl: add ATLKeyboardViewer to support launching IMEs

This commit is contained in:
Mis012
2025-03-28 19:51:23 +01:00
parent bb7eb461c8
commit bce91cc527
19 changed files with 792 additions and 8 deletions

View File

@@ -0,0 +1,34 @@
package android.inputmethodservice;
import android.app.Activity;
import android.os.Bundle;
import java.lang.reflect.Constructor;
public class ATLKeyboardViewer extends Activity {
@Override
public void onCreate(Bundle savedState) {
Bundle extras = this.getIntent().getExtras();
if (extras == null || !extras.containsKey("kb_class")) {
System.err.println("ATLKeyboardViewer: usage: `-e 'kb_class=com.example.LatinIME'`");
System.exit(1);
}
String kb_class = extras.getString("kb_class");
InputMethodService ims = null;
try {
Class<? extends InputMethodService> cls = Class.forName(kb_class).asSubclass(InputMethodService.class);
Constructor<? extends InputMethodService> constructor = cls.getConstructor();
ims = constructor.newInstance();
} catch (ReflectiveOperationException e) {
System.err.println("ATLKeyboardViewer: failed to instantiate InputMethodService (kb_class: "+kb_class+")");
e.printStackTrace();
System.exit(1);
}
ims.launch_keyboard();
}
}

View File

@@ -0,0 +1,16 @@
package android.inputmethodservice;
import android.app.Service;
import android.content.Context;
import android.view.inputmethod.InputMethod;
public abstract class AbstractInputMethodService extends Service {
public AbstractInputMethodService(Context context) {
super(context);
}
public abstract class AbstractInputMethodImpl implements InputMethod {
public void createSession(SessionCallback callback) {
}
}
}

View File

@@ -0,0 +1,245 @@
package android.inputmethodservice;
import android.app.Dialog;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Region;
import android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
import android.widget.LinearLayout;
public class InputMethodService extends AbstractInputMethodService {
private LinearLayout kb_box;
private View kb_view;
private View candidates_view;
private Dialog kb_dialog;
class ATLInputConnection extends BaseInputConnection {
ATLInputConnection() {
super(null, false);
}
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
System.out.println("softkeyboard preview: setComposingText(\""+text+"\", "+newCursorPosition+")");
return true;
}
@Override
public boolean finishComposingText() {
System.out.println("softkeyboard preview: finishComposingText()");
return true;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
System.out.println("softkeyboard preview: commitText(\""+text+"\", "+newCursorPosition+")");
return true;
}
@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
System.out.println("softkeyboard preview: deleteSurroundingText("+beforeLength+", "+afterLength+")");
return true;
}
@Override
public boolean sendKeyEvent(KeyEvent event) {
System.out.println("softkeyboard preview: sendKeyEvent("+event+")");
return true;
}
/* these functions are noop on AOSP by default, so we just add a print for debugging purposes and still return false */
@Override
public boolean commitCompletion(CompletionInfo completionInfo) {
System.out.println("softkeyboard preview: commitCompletion(\""+completionInfo+"\")");
return false;
}
@Override
public boolean commitCorrection(CorrectionInfo correctionInfo) {
System.out.println("softkeyboard preview: commitCorrection(\""+correctionInfo+"\")");
return false;
}
}
private InputConnection input_connection = new ATLInputConnection();
public InputMethodService() {
super(new Context());
}
public void launch_keyboard() {
kb_dialog = new Dialog(this);
View decorview = kb_dialog.getWindow().getDecorView();
decorview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
onCreate();
AbstractInputMethodImpl impl = onCreateInputMethodInterface();
impl.createSession(null);
// to force portrait version:
getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
onConfigurationChanged(getResources().getConfiguration());
onBindInput();
onStartInput(new EditorInfo(), false);
kb_box = new LinearLayout(this);
kb_box.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
kb_box.setOrientation(LinearLayout.VERTICAL);
candidates_view = onCreateCandidatesView();
kb_view = onCreateInputView();
if (candidates_view != null)
kb_box.addView(candidates_view);
kb_box.addView(kb_view);
kb_dialog.setContentView(kb_box);
kb_dialog.show();
onConfigureWindow(kb_dialog.getWindow(), false, false);
onComputeInsets(new Insets());
onStartInputView(new EditorInfo(), false);
}
public void sendKeyChar(char c) {
System.out.println("softkeyboard preview: sendKeyChar('"+c+"')");
}
public void setInputView(View view) {
kb_view = view;
}
public void setCandidatesView(View view) {
candidates_view = view;
}
public InputBinding getCurrentInputBinding() {
return new InputBinding(new ATLInputConnection(), null, 0, 0);
}
public IBinder onBind(Intent intent) {
return null;
}
public LayoutInflater getLayoutInflater() {
return (LayoutInflater)getSystemService("layout_inflater");
}
public boolean onEvaluateInputViewShown() {
return true;
}
public void setCandidatesViewShown(boolean shown) {
}
public void showStatusIcon(int resId) {
}
public void hideStatusIcon() {
}
public void updateInputViewShown() {
}
public void updateFullscreenMode() {
}
public boolean isFullscreenMode() {
return false;
}
public int getMaxWidth() {
return (kb_view != null && kb_view.getWidth() > 0) ? kb_view.getWidth() : Resources.getSystem().getDisplayMetrics().widthPixels;
}
public EditorInfo getCurrentInputEditorInfo() {
return new EditorInfo();
}
public void requestHideSelf(int flags) {
}
public Dialog getWindow() {
return kb_dialog;
}
public InputConnection getCurrentInputConnection() {
return input_connection;
}
/* --- */
public AbstractInputMethodImpl onCreateInputMethodInterface() {
return null;
}
public View onCreateCandidatesView() {
return null;
}
public View onCreateInputView() {
return null;
}
public void onConfigurationChanged(Configuration configuration) {
}
public void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly) {
}
public void onComputeInsets(Insets insets) {
}
public void onStartInput(EditorInfo info, boolean restarting) {
}
public void onFinishInput() {
}
public void onStartInputView(EditorInfo info, boolean restarting) {
}
public void onBindInput() {
}
/* --- */
public static final class Insets {
public int contentTopInsets;
public int visibleTopInsets;
public final Region touchableRegion = new Region();
public static final int TOUCHABLE_INSETS_FRAME = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
public static final int TOUCHABLE_INSETS_CONTENT = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
public static final int TOUCHABLE_INSETS_VISIBLE = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
public static final int TOUCHABLE_INSETS_REGION = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
public int touchableInsets;
}
public class InputMethodImpl extends AbstractInputMethodImpl {
}
}