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