1 原理
- 首先,我们要知道 如果想直接调出输入法的弹窗并显示内容,一定是通过三方输入法来操作,但是三方的输入法代码我们是无法改变的,因此要调用他们的父类中的公共接口。
- 其次,所有的输入法应用都是要继承 InputMethodService来写,所有的三方输入法都是可以用InputMethodService方法中的getCurrentInputConnection().commitText(text,0) 方法来提交文本。
- 最后,我们的思路就是 使用广播给InputMethodService发消息,InputMethodService收到消息后调用getCurrentInputConnection().commitText(text,0) 方法来提交并显示文本内容。
2 修改方案(Android Q)
发广播,在android上层使用以下方法实现广播的发送,关键代码如下所示:
//...
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class AGSManager {
private static final String TAG = "AGSManager";
public static int MSG_INPUT_TEXT = 1104;
private Context mContext;
private static final String BROADCAST_ACTION = "ags.input.text";
//...
public String parseInputMetodData(String val){
//...
//关键代码部分
JSONObject jsonObject = new JSONObject(val);
int id = jsonObject.getInt("event");
if(id == MSG_INPUT_TEXT){
JSONObject dataJsonObj = jsonObject.optJSONObject("data");
String text = dataJsonObj.getString("text");
Intent intent = new Intent(BROADCAST_ACTION);
intent.putExtra("text",text);
mContext.sendBroadcast(intent);
return text;
}
//...
}
//...
}
收广播,在android framework层需要修改InputMethodService.java,文件对应的具体路径为:$AOSP/frameworks/base/core/java/android/inputmethodservice/InputMethodService.java。其中的修改内容如下所示:
package android.inputmethodservice;
//...
//添加广播需要的包
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
static final boolean DEBUG = false;
//...
int mBackDisposition;
private static final String BROADCAST_ACTION = "ags.input.text";
IntentFilter mIntentFilter = null;
//添加一个广播接受者
private BroadcastReceiver mSeedlandTextReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BROADCAST_ACTION.equals(action)){
String text = intent.getStringExtra("text");
//提交字符串给到输入法上层显示框。
getCurrentInputConnection().commitText(text,0);
}
}
};
//...
@Override public void onCreate() {
mTheme = Resources.selectSystemTheme(mTheme,
getApplicationInfo().targetSdkVersion,
android.R.style.Theme_InputMethod,
android.R.style.Theme_Holo_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod);
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);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
initViews();
mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
//添加 注册广播
if(mIntentFilter == null){
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(BROADCAST_ACTION);
mIntentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(mSeedlandTextReceiver,mIntentFilter);
}
}
//...
@Override public void onDestroy() {
super.onDestroy();
mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
mInsetsComputer);
doFinishInput();
if (mWindowAdded) {
mWindow.getWindow().setWindowAnimations(0);
mWindow.dismiss();
}
if (mSettingsObserver != null) {
mSettingsObserver.unregister();
mSettingsObserver = null;
}
//添加 注销广播
if(mIntentFilter !=null){
unregisterReceiver(mSeedlandTextReceiver);
}
}
//...
}