Android浏览器应用搜索输入框被输入法遮挡问题

现象:

浏览器页面搜索框比较靠下时;无法看到输入内容。

当加入页面滚动效果以后;由于输入法上边有一个白框,这个白框影响了页面的整体上移、挡住了部分页面输入框。

第一部分:如何增加页面滚动上移效果

一、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----->>>>>>>updateExtractedText
D/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--------->>>>>dispatchKeyEvent
D/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










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值