TextView.java
private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
protected void onCreateContextMenu (ContextMenu menu) {
super.onCreateContextMenu(menu);
......
if (canCut()) {
int name;
if (selection) {
name = com.android.internal.R.string.cut;
} else {
name = com.android.internal.R.string.cutAll;
}
menu.add(0, ID_CUT, 0, name).
setOnMenuItemClickListener(handler).
setAlphabeticShortcut('x');
added = true;
}
.......
//判断输入法是否被激活,如果激活的话,将 inputMethod menuitem添加到菜单里
if (isInputMethodTarget ()) {
menu.add(1, ID_SWITCH_INPUT_METHOD, 0, com.android.internal.R.string.inputMethod).
setOnMenuItemClickListener(handler);
added = true;
}
}
*************************************************************************************************************************
isInputMethodTarget()原型如下:
/**
* Returns whether this text view is a current input method target. The
* default implementation just checks with {@link InputMethodManager}.
*/
public boolean isInputMethodTarget () {
InputMethodManager imm = InputMethodManager.peekInstance();
return imm != null && imm.isActive(this);
}
*************************************************************************************************************************
private class MenuHandler implements MenuItem.OnMenuItemClickListener {//menuitem点击的监听事件
public boolean onMenuItemClick (MenuItem item) {
return onTextContextMenuItem (item.getItemId());
}
}
*************************************************************************************************************************
/**
* Called when a context menu option for the text view is selected. Currently
* this will be one of: {@link android.R.id#selectAll},
* {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText},
* {@link android.R.id#cut}, {@link android.R.id#copy},
* {@link android.R.id#paste}, {@link android.R.id#copyUrl},
* or {@link android.R.id#switchInputMethod}.
*/
public boolean onTextContextMenuItem (int id) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
。。。。。。。。
switch (id) {
case ID_SELECT_ALL:
Selection.setSelection((Spannable) mText, 0,
mText.length());
return true;
。。。。。。。。。
case ID_SWITCH_INPUT_METHOD:
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
imm.showInputMethodPicker();//显示所有可获取的输入法
}
return true;
}
*************************************************************************************************************************
p { margin-bottom: 0.21cm; }
InputMethodManager.java( 实现了 showInputMethodPicker ()函数 )
final IInputMethodManager mService;
public void showInputMethodPicker() {
synchronized (mH) {
try {
mService .showInputMethodPickerFromClient (mClient);
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
}
}
p { margin-bottom: 0.21cm; }
InputMethodManager.java( 实现了 showInputMethodPicker ()函数 ) 实现了 InputMethodManager 类。此类调用 IInputMethodManager.aidl 接口功能,而 IInputMethodManager.aidl 接口功能由 InputMethodManagerService.java 实现 ( 实现了 IInputMethodManager.aidl 接口功能 函数 showInputMethodPickerFromClient () ) ,并运行在不同于客户端进程的 server 进程中。
*************************************************************************************************************************
InputMethodManagerService.java
static final int MSG_SHOW_IM_PICKER = 1;
public void showInputMethodPickerFromClient (IInputMethodClient client) {
.....................
mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER );
}
.......................................................................................................................................................
处理MSG_SHOW_IM_PICKER 消息
public boolean handleMessage(Message msg) {
HandlerCaller.SomeArgs args;
switch (msg.what) {
case MSG_SHOW_IM_PICKER:
showInputMethodMenu();
return true;
}
*************************************************************************************************************************
InputMethodManagerService.java
void showInputMethodMenu() {
if (DEBUG) Slog.v(TAG, "Show switching menu");
final Context context = mContext;
// Return PackageManager instance to find global package information.
final PackageManager pm = context.getPackageManager ();p { margin-bottom: 0.21cm; }
String lastInputMethodId = Settings.Secure.getString(context
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);//得到默认输入法字符串
if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
final List<InputMethodInfo> immis = getEnabledInputMethodList();//获取已启用输入法列表
if (immis == null) {
return;
}
synchronized (mMethodMap) {
hideInputMethodMenuLocked();
int N = immis.size();//得到输入法列表的大小
mItems = new CharSequence[N];
mIms = new InputMethodInfo[N];
int j = 0;
for (int i = 0; i < N; ++i) {
InputMethodInfo property = immis.get(i);
if (property == null) {
continue;
}
mItems[j] = property.loadLabel(pm);
mIms[j] = property;
j++;
}
int checkedItem = 0;
for (int i = 0; i < N; ++i) {
if (mIms[i].getId().equals(lastInputMethodId)) {
checkedItem = i;
break;
}
}
AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
hideInputMethodMenu();
}
};
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.DialogPreference,
com.android.internal.R.attr.alertDialogStyle, 0);
mDialogBuilder = new AlertDialog.Builder(context)
.setTitle(com.android.internal.R.string.select_input_method)
.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
hideInputMethodMenu();
}
})
.setIcon(a.getDrawable(
com.android.internal.R.styleable.DialogPreference_dialogTitle));
a.recycle();
mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
synchronized (mMethodMap) {
if (mIms == null || mIms.length <= which) {
return;
}
InputMethodInfo im = mIms[which];
hideInputMethodMenu();
if (im != null) {
setInputMethodLocked(im.getId());
}
}
}
});
mSwitchingDialog = mDialogBuilder.create();
mSwitchingDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
mSwitchingDialog.show();
}
}