• [Android] 关于Window Overscan


    Overscan的概念

    对于电视机,有一个Overscan的概念,如下图,所谓Overscan区域,就是电视机屏幕四周某些不可见的区域,这是电视机的特性。并且,Overscan的具体值也没有一个明确的标准,不同的电视机厂家的Overscan的值也各不相同。

    而对于普通的LCD,由于并没有Overscan的概念,所以设想,将一块没有设置Overscan的Framebuffer显示到有Overscan的电视机上,必定四周有一部分Overscan的区域被切除到无法显示出来。

    所以在Android 4.3以后,Google加入了Overscan的API,并且提供了wm工具,可以让用户设定Overscan的值,来满足不同的电视机。

    上图中,包含了Overscan的整个区域我们称之为Overscan Screen;

    去处Overscan区域后称之为 Unrestricted Area,由绿色和紫色区域组成,绿色区域用于显示Status Bar和Navigation Bar;

    剩下的紫色区域为 Restricted Area,这里显示的为mContentFrame。

    关于WM Tool

    Android 4.3之后,加入了Overscan的概念,并且提供了wm工具来设定Overscan的值。(参考git commit:c652de8141f5b8e3c6bcf8916842b6e106413b1a)

    代码调用流程:

    简单来讲就是,当我们设置了Overscan值后,WindowManagerService、PhoneWindowManager等会对当前显示的View的参数做重新计算,将计算完的数值会传给View,让其重新Layout。

    关于输入法的Bug

    一个存在的Bug是,当我们设置完Overscan后,google 的虚拟键盘并没有跟着Overscan的变化而缩放,虚拟键盘的一部分会被Overscan的区域遮挡无法显示。

    原因:虚拟键盘是通过Canvas绘制到屏幕上,而虚拟键盘上每一个组件的大小是根据屏幕的实际像素和深度来计算的,代码:

    packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java

    final Resources res = mThemeContext.getResources();
    builder.setScreenGeometry(res.getInteger(R.integer.config_device_form_factor),
         res.getConfiguration().orientation, res.getDisplayMetrics().widthPixels);

    所以,Keyboard会撑满Overscan Screen,而我们期望的是让Keyboard撑满Unrestricted Area,故我们做以下修改:

    1. 让Display.java中的getWidth方法返回除去Overscan长度后的值。

    frameworks/base/core/java/android/view/Display.java

         public int getWidth() {
        synchronized (this) {
          updateCachedAppSizeIfNeededLocked();
          updateDisplayInfoLocked();
          return mCachedAppWidthCompat - mDisplayInfo.overscanLeft - mDisplayInfo.overscanRight ;
             }
         }

    2. 在LatinIME中添加mWidth变量,用于存放Keyboard宽度。

    packages/inputmethods/LatinIME/java/src/com/android/inputmethod/latin/SettingsValues.java

      public static int mWidth;
      
      public SettingsValues(final SharedPreferences prefs, final InputAttributes inputAttributes, final Context context) {
        if(mWidth == 0){
          mWidth = res.getDisplayMetrics().widthPixels;
        }
      }

    3. 每次虚拟键盘弹出前,比较当前的Width和设定Width是否相同,不同和替代,并重新初始化Keyboard。注,此处InputManagerService的getMaxWidth方法最终会调用Step1的getWidth方法。

    packages/inputmethods/LatinIME/java/src/com/android/inputmethod/latin/LatinIME.java

        private void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restarting) {
            super.onStartInputView(editorInfo, restarting);
    // Deal with overscan area
            if(mCurrentSettings.mWidth != getMaxWidth()){
                mCurrentSettings.mWidth = getMaxWidth();
                loadKeyboard();
            }
     }       

    4.将初始化键盘宽度的值从res.getDisplayMetrics().widthPixels改成settingsValues.mWidth。

    packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java

        public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) {
            final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
                    mThemeContext, editorInfo);
            final Resources res = mThemeContext.getResources();
    //      builder.setScreenGeometry(res.getInteger(R.integer.config_device_form_factor),
    //              res.getConfiguration().orientation, res.getDisplayMetrics().widthPixels);
            builder.setScreenGeometry(res.getInteger(R.integer.config_device_form_factor),
                    res.getConfiguration().orientation, settingsValues.mWidth);
    
        }

     参考

    http://blog.csdn.net/cjj7905150/article/details/17888377

  • 相关阅读:
    第四十一节 jQuery之bootstrap文档
    第四十节 jQuery之bootstrap简介
    Redis 如何实现查询附近的距离
    线上日志快速定位-grep
    Java字符串操作工具类
    JAVA批量插入数据操作+事务提交
    java开发需求中技术常见名称
    MySQL Binlog--MIXED模式下数据更新
    MySQL Replication--修改主键为NULL导致的异常
    MySQL Replication--复制异常1
  • 原文地址:https://www.cnblogs.com/all-for-fiona/p/4054527.html
Copyright © 2020-2023  润新知