现象:
浏览器页面搜索框比较靠下时;无法看到输入内容。
当加入页面滚动效果以后;由于输入法上边有一个白框,这个白框影响了页面的整体上移、挡住了部分页面输入框。
第一部分:如何增加页面滚动上移效果
一、AndroidManifest.xml设置windowSoftInputMode方法
1.应用程序安装PackageManagerServices解析AndroidManifest.xml
应用程序的AndroidManifest.xml
<span style="font-size:14px;">android:windowSoftInputMode="adjustPan" //输入法挡输入框时;页面整体上移
android:windowSoftInputMode="adjustResize" //输入法挡输入框时;页面整体压缩</span>
2.系统读取上处AndroidManifest.xml的地方PackageParser.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/core/java/android/content/pm/PackageParser.java
<span style="font-size:14px;">private Activity parseActivity(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestActivity);
a.info.softInputMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
0);
/*
out/target/common/R/com/android/internal/R.java
public static final int AndroidManifestActivity_windowSoftInputMode = 20;
<tr><td><code>adjustPan</code></td><td>0x20</td><td>
*/
/*
frameworks/base/core/java/android/content/res/TypedArray.java
import com.android.internal.util.XmlUtils;
public int getInt(int index, int defValue) {
XmlUtils.convertValueToInt
}
frameworks/base/core/java/com/android/internal/util/XmlUtils.java
*/
a.info.softInputMode = android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; //mt5655异常
}</span>
3.系统将刚才读取xml文件内容设置
frameworks/base/core/java/android/app/Activity.java
<span style="font-size:14px;">final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
} </span>
二、可以通过应用程序启动后显示调用设置windowSoftInputMode
因为Activity启动;首先调用attach然后调用onCreate,为了生效、在onCreate后显示调用设置
frameworks/base/core/java/android/view/WindowManager.java
<span style="font-size:14px;">public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
import android.view.WindowManager;
onCreate方法
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
//SOFT_INPUT_STATE_HIDDEN
//SOFT_INPUT_ADJUST_RESIZE</span>
三、关键字imeOptions;设置输入法非全屏显示,上边windowSoftInputMode才起作用
全屏模式下,即使将activity的windowSoftInputMode的属性设置为:adjustResize,在键盘显示时它未将Activity的Screen向上推动,所以你Activity的view的根树的尺寸是没有变化的。在这种情况下,你也就无法得知键盘的尺寸,对根view的作相应的推移。全屏下的键盘无法Resize的问题从2.1就已经存在了,直到现在google还未给予解决。看看EidtText控件的布局
res/layout$ vi activity_main.xml
<span style="font-size:14px;"> <EditText
android:id="@+id/editview1"
android:layout_width="1000px"
android:layout_height="100px"
android:imeOptions="actionSearch|flagNoExtractUi|flagNoFullscreen" //设置输入法“非全屏;没有输入框”
android:singleLine="true"
android:layout_marginLeft="43dp"
android:layout_marginTop="390dp"
/></span>
android:imeOptions="flagNoFullscreen"//很重要
分析:
frameworks/base/core/java/android/widget/EditText.java继承自
frameworks/base/core/java/android/widget/TextView.java
<span style="font-size:14px;"> case com.android.internal.R.styleable.TextView_imeOptions:
if (mInputContentType == null) {
mInputContentType = new InputContentType();
}
//mInputContentType.imeOptions = a.getInt(attr,
mInputContentType.imeOptions);
//修改:mEditor.mInputContentType.imeOptions = EditorInfo.IME_NULL;
//EditorInfo.IME_ACTION_SEARCH;
//editText.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
break;
public void setImeOptions(int imeOptions) {
if (mInputContentType == null) {
mInputContentType = new InputContentType();
}
mInputContentType.imeOptions = imeOptions;
}</span>
framework/base/core/java/android/view/inputmethod/EditorInfo.java
<span style="font-size:14px;">public static final int IME_FLAG_NO_EXTRACT_UI = 0x10000000;</span>
四、分析滚动效果如何实现
我这边初步分析是这样的;当我们的应用程序EidtText控件的imeOptions属性默认设置时,输入法是全屏显示、此时设置getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)无效。
所以,需要在EidtText控件的imeOptions属性添加flagNoFullscreen;这个可以让输入法半屏显示也叫横屏显示。此时设置getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)有效。此时;我们看到的输入法的候选框就变成了一个白框。
具体看frameworks/base/core/java/android/inputmethodservice$ vi InputMethodService.java中的:
<span style="font-size:14px;"> public int getCandidatesHiddenVisibility() {
return /*isExtractViewShown() ?*/ View.GONE;// : View.INVISIBLE; //modify by tank@tcl.com
//View.GONE;直接隐藏候选框
//View.INVISIBLE;候选框显示为白框
}
public boolean isExtractViewShown() {
return mIsFullscreen && !mExtractViewHidden;
}</span>
结果就是:在设置imeOptions属性添加flagNoFullscreen让输入法非全屏显示以后;那个白框其实是输入法的候选框。
另外;对于为什么非要非全屏时那个滚动效果才可以起作用。这个应该Android一直有的问题;上边《三》中已经介绍。
综合这几个方面,我认为从输入法入手、帮忙看下这个输入法的“候选框”的白框能否去掉;是解决问题的办法。
五、解决
目前的解决方法有两个:
方案一:浏览器保持之前对于EidtText控件的imeOptions属性添加flagNoFullscreen;并增加getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE),让浏览器整体上移生效。将输入法候选框在不用时GONE;而不是INVISIBLE。因为一般输入法是继承的InputMethodService;这个需要修改InputMethodService。因为Android里边:如果非全屏,候选框不用时是白框View.INVISIBLE,页面可以整体上移;如果全屏,候选框不用时是全部隐藏View.GONE,页面不可以整体上移。这样效果是:如果存在输入法挡浏览器输入框时;浏览器输入框会被整体上移动。潜在风险是,如果存在向讯飞这些半屏输入法时、浏览器整体上移、讯飞输入法两边出现黑框。
方案二:让浏览器应用把EidtText控件的imeOptions属性flagNoExtractUi去掉(此时输入法的输入框正常存在);此时,对于getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)调用不调用效果一样(因为输入法全屏时,这个参数无效;Android一直都是这样,无法修改)。
这样效果是:如果存在输入法挡浏览器输入框时;浏览器输入框不会被整体上移动,浏览器输入框被输入法挡住。但是,输入法的“输入框”存在;用户输入东西可以在这个框里边看到。
个人建议采用方法二;麻烦浏览器应用修改布局中EidtText控件的imeOptions属性flagNoExtractUi去掉。即可验证。
系统解决(浏览器输入框不能解决;因为不是这个Android标准组件):frameworks/base/core/java/android/widget/TextView.java
<span style="font-size:14px;"> case com.android.internal.R.styleable.TextView_imeOptions:
createEditorIfNeeded();
mEditor.createInputContentTypeIfNeeded();
/*mEditor.mInputContentType.imeOptions = a.getInt(attr,
mEditor.mInputContentType.imeOptions);*/
//add by tank@tcl.com
Log.d("TKTK","TK--------->>>>>none");
mEditor.mInputContentType.imeOptions = EditorInfo.IME_NULL;
//end tank@tcl.com
break;</span>
六、方案一:针对输入法应用修改方法;非全屏+输入法无输入框+禁止候选框白框显示(因为Android原生,在非全屏时、候选框不用时一定是白框;所以,需要修改Android原生Code),此方法验证ok
1.Android继承InputMethodService的输入法布局
<span style="font-size:14px;">frameworks/base/core/res/res/layout/input_method.xml
<FrameLayout android:id="@android:id/extractArea" //输入框
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:visibility="gone">
</FrameLayout>
<FrameLayout android:id="@android:id/candidatesArea" //候选框
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
</FrameLayout>
</LinearLayout>
<FrameLayout android:id="@android:id/inputArea" //软键盘
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
</FrameLayout></span>
frameworks/base/core/java/android/inputmethodservice/InputMethodService.java
<span style="font-size:14px;">//mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea); //modify by tank@tcl.com
//mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea); //modify by tank@tcl.com
mExtractFrame.setVisibility(View.GONE);//隐藏
mExtractFrame.setVisibility(View.INVISIBLE); //白框
mExtractFrame.setVisibility(View.VISIBLE); //正常显示</span>
最终修改
2.去掉候选框白框修改
frameworks/base/core/java/android/view/View.java
<span style="font-size:14px;"> public static final int VISIBLE = 0x00000000; //显示
/**
* This view is invisible, but it still takes up space for layout purposes.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int INVISIBLE = 0x00000004; //隐藏,但是留下白框
/**
* This view is invisible, and it doesn't take any space for layout
* purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int GONE = 0x00000008; //隐藏</span>
frameworks/base/core/java/android/inputmethodservice$ vi InputMethodService.java
<span style="font-size:14px;"> public int getCandidatesHiddenVisibility() {
return /*isExtractViewShown() ?*/ View.GONE;// : View.INVISIBLE; //modify by tank@tcl.com
}</span>
七、方案二:—针对浏览器内核解决方法;全屏+输入法有输入框
1.输入法没有全屏问题——关键字imeOptions
修改方法:
external/chromium_org/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
<span style="font-size:14px;"> AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable,
EditorInfo outAttrs) {
super(view, true);
mInternalView = view;
mImeAdapter = imeAdapter;
mImeAdapter.setInputConnection(this);
mEditable = editable;
// The editable passed in might have been in use by a prior keyboard and could have had
// prior composition spans set. To avoid keyboard conflicts, remove all composing spans
// when taking ownership of an existing Editable.
removeComposingSpans(mEditable);
mSingleLine = true;
outAttrs.imeOptions = EditorInfo.IME_NULL;/*EditorInfo.IME_FLAG_NO_FULLSCREEN
| EditorInfo.IME_FLAG_NO_EXTRACT_UI;*/ //modify by tank@tcl.com
</span>
2.输入法输入框(此时没有焦点;只是更新buffer文字)不能同步输入按键
正确:
D/TKTK ( 8354): TK----->>>>>>>updateExtractedTextD/TKTK ( 8354): TK---->>>>updateSelection isEnabled is true
D/TKTK ( 8354): TK----->>>>>>>updateExtractedText
D/TKTK ( 8354): TK---->>>>updateSelection isEnabled is true
错误:
V/InputMethodService( 7473): showSoftInput()V/InputMethodService( 7473): Showing window: showInput=true mShowInputRequested=false mWindowAdded=true mWindowCreated=true mWindowVisible=false mInputStarted=true
V/InputMethodService( 7473): showWindow: updating UI
V/InputMethodService( 7473): CALL: onStartInputView
D/TKTK ( 7473): TK------>>>>setExtractViewShown true
V/InputMethodService( 7473): showWindow: showing!
///
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags)
startExtractingText
public void updateExtractedText(int token, ExtractedText text)
mExtractedToken = request.token;
//
修改方法:
external/chromium_org/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
<span style="font-size:14px;"> private ExtractedTextRequest mExtracting;//add by tank@tcl.com
private ExtractedText mTmpExtracted = new ExtractedText();//add by tank@tcl.com
public boolean commitText(CharSequence text, int newCursorPosition) {
if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]");
if (maybePerformEmptyCompositionWorkaround(text)) return true;
super.commitText(text, newCursorPosition);
updateExtractedTextIfRequired();//add by tank@tcl.com
updateSelectionIfRequired();
return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition,
text.length() > 0);
}
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
if (DEBUG) {
Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLength + "]");
}
int availableBefore = Selection.getSelectionStart(mEditable);
int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEditable);
beforeLength = Math.min(beforeLength, availableBefore);
afterLength = Math.min(afterLength, availableAfter);
super.deleteSurroundingText(beforeLength, afterLength);
//add by tank@tcl.com
updateExtractedTextIfRequired();
//end tank@tcl.com
updateSelectionIfRequired();
return mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
}
public void updateState(String text, int selectionStart, int selectionEnd, int compositionStart,
int compositionEnd, boolean isNonImeChange) {
if (DEBUG) {
Log.w(TAG, "updateState [" + text + "] [" + selectionStart + " " + selectionEnd + "] ["
+ compositionStart + " " + compositionEnd + "] [" + isNonImeChange + "]");
}
//add by tank@tcl.com
//if(mEditable.length() >= 0) mEditable.replace(mEditable.length(), mEditable.length() + 1, "\0");
//end tank@tcl.com
// If this update is from the IME, no further state modification is necessary because the
// state should have been updated already by the IM framework directly.
if (!isNonImeChange) return;
//add by tank@tcl.com
//updateExtractedTextIfRequired();
//end tank@tcl.com
updateSelectionIfRequired();
}
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
mExtracting = request; //add by tank@tcl.com
if (DEBUG) Log.w(TAG, "getExtractedText");
}
//add by tank@tcl.com
private void updateExtractedTextIfRequired() {
Log.d(TAG,"TK------->>>>>>>updateExtractedTextIfRequired");
if(mExtracting != null){
mTmpExtracted = getExtractedText(mExtracting,1);
getInputMethodManagerWrapper().updateExtractedText(mInternalView,mExtracting.token,mTmpExtracted);
}
}
//end tank@tcl.com</span>
3.del删除不了——输入法输入框(此时没有焦点;只是更新buffer文字)不能同步删除按键
D/TKTK ( 5185): TK--------->>>>>dispatchKeyEventD/TKTK ( 5185): TK--------->>>>>translateAndSendNativeEvents
W/AdapterInputConnection( 5185): updateState [aaaaaa;] [7 7] [-1 -1] [true]
W/AdapterInputConnection( 5185): updateSelectionIfRequired [7 7] [-1 -1]
W/AdapterInputConnection( 5185): getExtractedText
D/TKTK ( 5269): TK----->>>>>>>updateExtractedText
D/TKTK ( 5269): TK---->>>>updateSelection isEnabled is true
D/TKTK ( 5185): TK--------->>>>>dispatchKeyEvent
D/TKTK ( 5185): TK--------->>>>>translateAndSendNativeEvents
正确:
D/TKTK ( 5269): TK----->>>>>>>updateExtractedText
D/TKTK ( 5269): TK---->>>>updateSelection isEnabled is true
D/TKTK ( 5269): TK----->>>>>>>updateCandidatesVisibility
D/TKTK ( 5269): TK----->>>>>>>updateCandidatesVisibility
D/TKTK ( 5269): TK----->>>>>>>updateCandidatesVisibility
错误:
W/AdapterInputConnection( 5185): deleteSurroundingText [1 0]
W/AdapterInputConnection( 5185): beginBatchEdit [true]
W/AdapterInputConnection( 5185): endBatchEdit [true]
W/AdapterInputConnection( 5185): updateSelectionIfRequired [6 6] [-1 -1]
W/AdapterInputConnection( 5185): getExtractedText
D/TKTK ( 5185): TK--------->>>>>deleteSurroundingText
D/TKTK ( 5269): TK----->>>>>>>updateExtractedText
D/TKTK ( 5269): TK---->>>>updateSelection isEnabled is true
W/AdapterInputConnection( 5185): updateState [aaaaaa] [6 6] [-1 -1] [false]
/
修改方法:
external/chromium_org/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
<span style="font-size:14px;"> public boolean deleteSurroundingText(int beforeLength, int afterLength) {
if (DEBUG) {
Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLength + "]");
}
int availableBefore = Selection.getSelectionStart(mEditable);
int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEditable);
beforeLength = Math.min(beforeLength, availableBefore);
afterLength = Math.min(afterLength, availableAfter);
super.deleteSurroundingText(beforeLength, afterLength);
//add by tank@tcl.com
//if(mExtracting.token > 0) mExtracting.token--;
//if(mEditable.length() > 0) mEditable.replace(mEditable.length(), mEditable.length(), "\0");
updateExtractedTextIfRequired();
//end tank@tcl.com
updateSelectionIfRequired();
mImeAdapter.checkCompositionQueueAndCallNative(mEditable.toString(), 1,
mEditable.toString().length() > 0);//add by tank@tcl.com
return mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
}</span>
/frameworks/webview/chromium/
mm -j32
out/target/product/coconut_c1/system/priv-app/webview/webview.apk
///
setprop service.adb.root 1
ime set com.android.inputmethod.pinyin/.PinyinIME
logcat -s AdapterInputConnection TKTK InputMethodService AndroidRunTime