2012年8月1日 星期三

Android – screen compatibility mode


工程師的工作不外乎要 debug, 最近又遇到一個 issue.

WVGA(width=800, height=480) 的平台上, 執行應用程式, 該應用程式卻 allocate(width=533, height=320) graphic buffer. 造成畫面內容顯示不正確.




寫一個應用程式測試 Android平台的display metrics, 程式片段如下:
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
Log.e("DM", "DM : widthPixel "+dm.widthPixels);
Log.e("DM", "DM : heightPixel "+dm.heightPixels);
Log.e("DM", "DM : density "+dm.density);
Log.e("DM", "DM : densityDpi "+dm.densityDpi);
Log.e("DM", "DM : scaledDensity "+dm.scaledDensity);
   Log.e("DM", "DM : xdpi "+dm.xdpi);
   Log.e("DM", "DM : ydpi "+dm.ydpi);

發現在此平台上 可以得到兩個不同的結果. 造成結果不同的原因是在<uses-sdk android:minSdkVersion> 的設定. 這個設定位在 APK AndroidManifest.xml 設定 android:minSdkVersion=3, 得到的log如下(DM 是我加的 Tag, 不用管它)
DM : widthPixel 320
DM : heightPixel 533
DM : density 1.5
DM : densityDpi 240
DM : scaledDensity 1.5
DM : xdpi 217.71428
DM : ydpi 218.49463
若是設定 android:minSdkVersion=4, 得到的log :
DM : widthPixel 480  
DM : heightPixel 800 
DM : density 1.5     
DM : densityDpi 240  
DM : scaledDensity 1.5
DM : xdpi 217.71428  
DM : ydpi 218.49463
很明顯的 <uses-sdk android:minSdkVersion=4> 得到的是正確的結果.
<uses-sdk> 這個 element 的作用是宣告應用程式的 API level, 這是 Android 設計來處理應用程式在不同版本的Android平台上執行時的相容性問題.

下表列出部分的 Android平台的版本和 API level 的對應關係
Platform version
API level
VERSION_CODE
Android 2.2.x
8
FROYO
Android 2.1.x
7
ECLAIR_MR1
Android 2.0.1
6
ECLAIR_0_1
Android 2.0
5
ECLAIR
Android 1.6
4
DONUT
Android 1.5
3
CUPCAKE
Android 1.1
2
BASE_1_1
Android 1.0
1
BASE

順帶補充資料, <uses-sdk> 這個 element 包含有 3 attribute, 分別是
android:minSdkVersion
 應用程式正常執行所需的最小 API level. 在應用程式安裝時,如果Android 平台 的 API level 小於這個 attribute 的數值, 則系統不會允許應用程式被安裝.
若是應用程式沒有指定則default 值是 1, 代表相容於所有的Android 版本.
如果應用程式有使用到 API level 3才支援的APIs 但又沒有指定這個屬性
則在 API level 小於3Android 平台執行時, 此應用程式會 crash.
android:targetSdkVersion
這個 attribute 表示該應用程式已經在 targetsdkVersion所標示API level的平台上測試過. 另外, Android 平台有新的版本時, 應用程式開發者也應該在新的平台上測試應用程式且將 android:targetSdkVersion 屬性更新成該平台的 API level. 若是 應用程式的 android:targetSdkVersion 值小於Android 平台的 API level, 則平台運行該應用程式時不會做 compatibility 的調整.

android:maxSdkVersion
這個 attribute 的設定會決定應用程式是否可以安裝以及Android平台進行 OTA(Over The Air)更新後, 已經安裝的應用程式是否可以執行.


回到我們之前的問題,android:minSdkVersion=4, display metrics 可以得到正確的寬高是因為從 API level 4 (Android 1.6)開始, 才支持不同尺寸的顯示屏. 在此之前都只有320x480一種尺寸, 因此設置成android:minSdkVersion=3的應用程式 要在WVGA(480x800)的平台上運行, Android 平台會做 screen compatibility 調整,因此得到 (320x533)的不正確結果, 為了避免這種情況, 我們要Disable 這個功能.

關閉的方法, 只需要修改一行程式碼, 在檔案
/frameworks/base/services/java/com/android/server/PackageManagerService.java
找到 systemReady() 這是函式, 將其中一行:
          PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
修改成
          PackageParser.setCompatibilityModeEnabled(false);
如此可關閉 compatibility mode, 一律用 WVGA(480x800). 之後應用程式就可以正確allocate(width=800, height=480) graphic buffer.

2 則留言: