主要是注意平板和手机之间布局的区别:
几个关键的java类
SystemUIService
PhoneWindowManager
WindowManagerPolicy
PhoneStatusBar
TabletStatusBar
NavigationBar
SystemUIService-->onCreate中判断加载平板布局还是手机布局
// Pick status bar or system bar.
IWindowManager wm = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
try {
SERVICES[0] = wm.canStatusBarHide()
? R.string.config_statusBarComponent
: R.string.config_systemBarComponent;
} catch (RemoteException e) {
Slog.w(TAG, "Failing checking whether status bar can hide", e);
}
然后在frameworks\base\packages\systemui\res\values\config.xml中
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
<string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
然后通过类加载器加载PhoneStatusBar或者TabletStatusBar。也就是手机的状态栏还是平板的状态栏。
判断的关键就在
wm.canStatusBarHide()这个方法里面。
我们跳过几个类后最后跟进到PhoneWindowManager中:
public boolean canStatusBarHide() {
return mStatusBarCanHide;
}
mStatusBarCanHide是一个成员变量,修改它值得地方在:
public void setInitialDisplaySize(int width, int height) {...}中。
int shortSizeDp = shortSize
* DisplayMetrics.DENSITY_DEFAULT
/ DisplayMetrics.DENSITY_DEVICE;
mStatusBarCanHide = shortSizeDp < 600;
mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
mStatusBarCanHide
? com.android.internal.R.dimen.status_bar_height
: com.android.internal.R.dimen.system_bar_height);
mHasNavigationBar = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_showNavigationBar);
// Allow a system property to override this. Used by the emulator.
// See also hasNavigationBar().
String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
if (! "".equals(navBarOverride)) {
if (navBarOverride.equals("1")) mHasNavigationBar = false;
else if (navBarOverride.equals("0")) mHasNavigationBar = true;
}
这个方法略微有点长,绕过前面的判断,取上面一部分来分析。大致的意思是:
首先取shortSize,shortSize指的是屏幕最短的像素,比如1024*600,那么值就是600。 shortSizeDp是把pix单位转化成dip单位。 DisplayMetrics.DENSITY_DEFAULT的值是固定死的160,在更具手机的密度算出shortSizeDp。突出标记的地方就是平板和手机状态栏切换的关键了。
只有最短屏幕dp大于600的设备才会加载平板布局。
剩下的代码用来判断底部虚拟按键是否显示的关键。首先是去读取frameworks\base\core\res\res\values\config.xml中config_showNavigationBar这个key,下面 SystemProperties.get("qemu.hw.mainkeys")这个属性主要是给模拟器使用,可以直接忽略掉。
分析完毕!
现在如何切换平板和手机状态栏布局已经很明了了,就是让
shortSizeDp 的值>=600。以1024*600为例,因为DisplayMetrics.DENSITY_DEFAULT的值已经固定死是160,所以只要把DisplayMetrics.DENSITY_DEVICE的值<=160即可。修改屏幕密度的方法:
/build/tools/buildinfo.sh
中设定 ro.sf.lcd_density=160,
当然MTK自己定义了一套属性,MTK项目中可以通过这个属性来设置,比较保险
/mediatek/config/[Project_name]/system.prop
中设定该属性的值
如此基本大功告成。mm编译,然后报错。。。。
错误定位到TabletStatusBar的makeStatusBarView()中,代码如下:
try {
// Sanity-check that someone hasn't set up the config wrong and asked for a navigation
// bar on a tablet that has only the system bar
if (mWindowManager.hasNavigationBar()) {
throw new RuntimeException(
"Tablet device cannot show navigation bar and system bar");
}
} catch (RemoteException ex) {
}
问题很明显,平板设备中不需要NavigationBar,因为NavigationBar的东西已经全部合并到StatusBar里面了。修改方法:
frameworks\base\core\res\res\values\config.xml中config_showNavigationBar修改为false
啰嗦半天,其实就两个问题:
一。虚拟按键的隐藏和显示:
修改frameworks\base\core\res\res\values\config.xml中config_showNavigationBar
二。状态栏平板和手机之间的切换:
1. /build/tools/buildinfo.sh中设定 ro.sf.lcd_density=160,
当然MTK自己定义了一套属性,MTK项目中可以通过这个属性来设置,比较保险
/mediatek/config/[Project_name]/system.prop中设定该属性的值
2. frameworks\base\core\res\res\values\config.xml中config_showNavigationBar修改为false