对Android4.0中Launcher2一些调试记录
最近项目打板了,板子跑起来后发现Launcher的所有程序界面不能全屏(两边有黑框,只在中上部显示),但是主界面看上去是全屏显示的(后面证实也非全屏显示。)
我们的屏是21寸的,分辨率为1980*1080。
最开始以为是uboot里的屏幕参数没设置好,后面check之后发现没问题。没办法,只有去看Launcher的代码。
首先,在我最开始就有一个误解,这个误解浪费我很多时间。由于最开始的时候主界面(也就是workspace)是没有黑框的,所以我一直认为workspace的代码是没问题的。
后面经验证主界面也没有按屏幕的实际分辨率显示!Workspace.java中构造函数有如下代码:
1 final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp;
2 cellCountX = 1;
3 while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) {
4
5 cellCountX++;
6 }
7
8 cellCountY = 1;
9 while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
10 <= smallestScreenDim - systemBarHeight) {
11 cellCountY++;
12 }
13 }
smallestScreenDim 按字面理解意思应该是屏幕宽度的最小值(以DP为单位),cellCountX初始化为1,然后通过一个while循环去计算X、Y方向各能放多少个应用。
我们看看widthInPortrait方法:
1 static int widthInPortrait(Resources r, int numCells) {
2 // We use this method from Workspace to figure out how many rows/columns Launcher should
3 // have. We ignore the left/right padding on CellLayout because it turns out in our design
4 // the padding extends outside the visible screen size, but it looked fine anyway.
5 int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
6 int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
7 r.getDimensionPixelSize(R.dimen.workspace_height_gap));
8 return minGap * (numCells - 1) + cellHeight * numCells;
9 }
getDimensionPixelSize方法实际上是把dimens.xml中设置的cellWidth大小由dp转换成px!
widthInPortrait计算后的返回值会与smallestScreenDim进行比较,如果比smallestScreenDim 小,那么说明能够再放一个APP,cellCount进行加一。
循环比较之后就会得出在该屏幕上能放多少行,多少列个应用。
既然cellWidth的单位为px,那与通过他计算后得到的值进行比较的smallestScreenDim单位应该也是px,而不是像他字面所说的dp!
通过加log进一步确认,我发现android4.0默认的smallestScreenDim为720!也就是720px,而我的屏实际像素宽度为1920!
将smallestScreenDim强制设置为1920后all apps界面能全屏了,主界面的workspace也大了很多!说明之前主界面的全屏都是假象。。。
我们可以在代码里得到屏幕的宽度,然后赋值给smallestScreenDim以便于支持更多的屏幕。
至于之前的主界面为什么没有黑色的边框,我估计是壁纸设置的原因,具体细节没去深究了。
后面发现系统默认的图标在大屏幕上显示效果不太好,有点偏小,直接修改res/values-sw600dp/dimens.xml中的app_icon_size。
改完make之后发现图标并没有变大。。。
跟踪代码Launcher.java[onCreate]--->[setLauncher]--->LauncherApplication[onCreate]--->[new LauncherModel]--->[createIconBitmap]
1 static Bitmap createIconBitmap(Drawable icon, Context context) {
2 synchronized (sCanvas) { // we share the statics :-(
3 if (sIconWidth == -1) {
4 initStatics(context);
5 }
6
7 int width = sIconWidth;
8 int height = sIconHeight;
9
10 Log.i("Info","In createIconBitmap width is: "+width);
11 Log.i("Info","In createIconBitmap height is: "+height);
12 if (icon instanceof PaintDrawable) {
13 Log.i("Info","Icon type is PaintDrawable" );
14 PaintDrawable painter = (PaintDrawable) icon;
15 painter.setIntrinsicWidth(width);
16 painter.setIntrinsicHeight(height);
17 } else if (icon instanceof BitmapDrawable) {
18 // Ensure the bitmap has a density.
19 Log.i("Info","Icon type is BitmapDrawable" );
20 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
21 Bitmap bitmap = bitmapDrawable.getBitmap();
22 if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
23 bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
24 }
25 }
26 int sourceWidth = icon.getIntrinsicWidth();
27 int sourceHeight = icon.getIntrinsicHeight();
28 Log.i("Info","IntrinsicWidth is: "+sourceWidth);
29 Log.i("Info","IntrinsicHeight is: "+sourceHeight);
30 if (sourceWidth > 0 && sourceHeight > 0) {
31 // There are intrinsic sizes.
32 if (width < sourceWidth || height < sourceHeight) {
33 // It's too big, scale it down.
34 final float ratio = (float) sourceWidth / sourceHeight;
35 if (sourceWidth > sourceHeight) {
36 height = (int) (width / ratio);
37 } else if (sourceHeight > sourceWidth) {
38 width = (int) (height * ratio);
39 }
40 } else if (sourceWidth < width && sourceHeight < height) {
41 // Don't scale up the icon
42 //width = sourceWidth;
43 //height = sourceHeight;
44 width = sIconWidth;
45 height = sIconHeight;
46 }
47 }
48
49 // no intrinsic size --> use default size
50 int textureWidth = sIconTextureWidth;
51 int textureHeight = sIconTextureHeight;
52 Log.i("Info","textureWidth is: "+textureWidth);
53 Log.i("Info","textureHeight is: "+textureHeight);
54
55 final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
56 Bitmap.Config.ARGB_8888);
57 final Canvas canvas = sCanvas;
58 canvas.setBitmap(bitmap);
59
60 final int left = (textureWidth-width) / 2;
61 final int top = (textureHeight-height) / 2;
62
63 if (false) {
64 // draw a big box for the icon for debugging
65 canvas.drawColor(sColors[sColorIndex]);
66 if (++sColorIndex >= sColors.length) sColorIndex = 0;
67 Paint debugPaint = new Paint();
68 debugPaint.setColor(0xffcccc00);
69 canvas.drawRect(left, top, left+width, top+height, debugPaint);
70 }
71
72 sOldBounds.set(icon.getBounds());
73 icon.setBounds(left, top, left+width, top+height);
74 icon.draw(canvas);
75 icon.setBounds(sOldBounds);
76 canvas.setBitmap(null);
77
78 return bitmap;
79 }
80 }
81 private static void initStatics(Context context) {
82 final Resources resources = context.getResources();
83 final DisplayMetrics metrics = resources.getDisplayMetrics();
84 final float density = metrics.density;
85
86 //default is 72*density
87 sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
88 sIconTextureWidth = sIconTextureHeight = sIconWidth;
89
90 sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
91 sGlowColorPressedPaint.setColor(0xffffc300);
92 sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
93 sGlowColorFocusedPaint.setColor(0xffff8e00);
94 sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
95
96 ColorMatrix cm = new ColorMatrix();
97 cm.setSaturation(0.2f);
98 sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
99 sDisabledPaint.setAlpha(0x88);
100 }
经过分析,发现在这个方法里对图片大小进行了判断,如果大于默认的图片大小96dp,那么强制将图片大小设置为96dp!
稍作修改图标就能放大了,细节不说了,大家看看代码就知道了。
最近项目打板了,板子跑起来后发现Launcher的所有程序界面不能全屏(两边有黑框,只在中上部显示),但是主界面看上去是全屏显示的(后面证实也非全屏显示。)
我们的屏是21寸的,分辨率为1980*1080。
最开始以为是uboot里的屏幕参数没设置好,后面check之后发现没问题。没办法,只有去看Launcher的代码。
首先,在我最开始就有一个误解,这个误解浪费我很多时间。由于最开始的时候主界面(也就是workspace)是没有黑框的,所以我一直认为workspace的代码是没问题的。
后面经验证主界面也没有按屏幕的实际分辨率显示!Workspace.java中构造函数有如下代码:
1 final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp;
2 cellCountX = 1;
3 while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) {
4
5 cellCountX++;
6 }
7
8 cellCountY = 1;
9 while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
10 <= smallestScreenDim - systemBarHeight) {
11 cellCountY++;
12 }
13 }
smallestScreenDim 按字面理解意思应该是屏幕宽度的最小值(以DP为单位),cellCountX初始化为1,然后通过一个while循环去计算X、Y方向各能放多少个应用。
我们看看widthInPortrait方法:
1 static int widthInPortrait(Resources r, int numCells) {
2 // We use this method from Workspace to figure out how many rows/columns Launcher should
3 // have. We ignore the left/right padding on CellLayout because it turns out in our design
4 // the padding extends outside the visible screen size, but it looked fine anyway.
5 int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
6 int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
7 r.getDimensionPixelSize(R.dimen.workspace_height_gap));
8 return minGap * (numCells - 1) + cellHeight * numCells;
9 }
getDimensionPixelSize方法实际上是把dimens.xml中设置的cellWidth大小由dp转换成px!
widthInPortrait计算后的返回值会与smallestScreenDim进行比较,如果比smallestScreenDim 小,那么说明能够再放一个APP,cellCount进行加一。
循环比较之后就会得出在该屏幕上能放多少行,多少列个应用。
既然cellWidth的单位为px,那与通过他计算后得到的值进行比较的smallestScreenDim单位应该也是px,而不是像他字面所说的dp!
通过加log进一步确认,我发现android4.0默认的smallestScreenDim为720!也就是720px,而我的屏实际像素宽度为1920!
将smallestScreenDim强制设置为1920后all apps界面能全屏了,主界面的workspace也大了很多!说明之前主界面的全屏都是假象。。。
我们可以在代码里得到屏幕的宽度,然后赋值给smallestScreenDim以便于支持更多的屏幕。
至于之前的主界面为什么没有黑色的边框,我估计是壁纸设置的原因,具体细节没去深究了。
后面发现系统默认的图标在大屏幕上显示效果不太好,有点偏小,直接修改res/values-sw600dp/dimens.xml中的app_icon_size。
改完make之后发现图标并没有变大。。。
跟踪代码Launcher.java[onCreate]--->[setLauncher]--->LauncherApplication[onCreate]--->[new LauncherModel]--->[createIconBitmap]
1 static Bitmap createIconBitmap(Drawable icon, Context context) {
2 synchronized (sCanvas) { // we share the statics :-(
3 if (sIconWidth == -1) {
4 initStatics(context);
5 }
6
7 int width = sIconWidth;
8 int height = sIconHeight;
9
10 Log.i("Info","In createIconBitmap width is: "+width);
11 Log.i("Info","In createIconBitmap height is: "+height);
12 if (icon instanceof PaintDrawable) {
13 Log.i("Info","Icon type is PaintDrawable" );
14 PaintDrawable painter = (PaintDrawable) icon;
15 painter.setIntrinsicWidth(width);
16 painter.setIntrinsicHeight(height);
17 } else if (icon instanceof BitmapDrawable) {
18 // Ensure the bitmap has a density.
19 Log.i("Info","Icon type is BitmapDrawable" );
20 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
21 Bitmap bitmap = bitmapDrawable.getBitmap();
22 if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
23 bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
24 }
25 }
26 int sourceWidth = icon.getIntrinsicWidth();
27 int sourceHeight = icon.getIntrinsicHeight();
28 Log.i("Info","IntrinsicWidth is: "+sourceWidth);
29 Log.i("Info","IntrinsicHeight is: "+sourceHeight);
30 if (sourceWidth > 0 && sourceHeight > 0) {
31 // There are intrinsic sizes.
32 if (width < sourceWidth || height < sourceHeight) {
33 // It's too big, scale it down.
34 final float ratio = (float) sourceWidth / sourceHeight;
35 if (sourceWidth > sourceHeight) {
36 height = (int) (width / ratio);
37 } else if (sourceHeight > sourceWidth) {
38 width = (int) (height * ratio);
39 }
40 } else if (sourceWidth < width && sourceHeight < height) {
41 // Don't scale up the icon
42 //width = sourceWidth;
43 //height = sourceHeight;
44 width = sIconWidth;
45 height = sIconHeight;
46 }
47 }
48
49 // no intrinsic size --> use default size
50 int textureWidth = sIconTextureWidth;
51 int textureHeight = sIconTextureHeight;
52 Log.i("Info","textureWidth is: "+textureWidth);
53 Log.i("Info","textureHeight is: "+textureHeight);
54
55 final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
56 Bitmap.Config.ARGB_8888);
57 final Canvas canvas = sCanvas;
58 canvas.setBitmap(bitmap);
59
60 final int left = (textureWidth-width) / 2;
61 final int top = (textureHeight-height) / 2;
62
63 if (false) {
64 // draw a big box for the icon for debugging
65 canvas.drawColor(sColors[sColorIndex]);
66 if (++sColorIndex >= sColors.length) sColorIndex = 0;
67 Paint debugPaint = new Paint();
68 debugPaint.setColor(0xffcccc00);
69 canvas.drawRect(left, top, left+width, top+height, debugPaint);
70 }
71
72 sOldBounds.set(icon.getBounds());
73 icon.setBounds(left, top, left+width, top+height);
74 icon.draw(canvas);
75 icon.setBounds(sOldBounds);
76 canvas.setBitmap(null);
77
78 return bitmap;
79 }
80 }
81 private static void initStatics(Context context) {
82 final Resources resources = context.getResources();
83 final DisplayMetrics metrics = resources.getDisplayMetrics();
84 final float density = metrics.density;
85
86 //default is 72*density
87 sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
88 sIconTextureWidth = sIconTextureHeight = sIconWidth;
89
90 sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
91 sGlowColorPressedPaint.setColor(0xffffc300);
92 sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
93 sGlowColorFocusedPaint.setColor(0xffff8e00);
94 sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
95
96 ColorMatrix cm = new ColorMatrix();
97 cm.setSaturation(0.2f);
98 sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
99 sDisabledPaint.setAlpha(0x88);
100 }
经过分析,发现在这个方法里对图片大小进行了判断,如果大于默认的图片大小96dp,那么强制将图片大小设置为96dp!
稍作修改图标就能放大了,细节不说了,大家看看代码就知道了。