首页 > Android, System > Android中的墙纸Wallpaper代码简析

Android中的墙纸Wallpaper代码简析

2012-11-27 21:05 星期二    浏览: 4,059    绿 发表评论 阅读评论

Android的背景墙纸功能的实现主要由散布在下面几个文件中的类来完成:

(1)frameworks/base/core/java/android/app/WallpaperManager.java

提供了API类,类WallpaperManager的各种函数接口为应用开发者所使用。

(2)frameworks/base/services/java/com/android/server/WallpaperManagerService.java

上述的API类将跨进程调用到system_server进程中的服务类WallpaperManagerService

(3)frameworks/base/core/java/android/service/wallpaper/WallpaperService.java

定义了抽象类WallpaperServic以及内嵌的墙纸绘制引擎基类Engine(子类用于实现墙纸的绘制渲染,若需preview则需创建多个引擎子类实例)。另外,该文件所在文件夹中还定义了几个AIDL接口文件,用于跨进程的调用。

(4)frameworks/base/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java

类ImageWallpaper实现了上面的WallpaperServic,同时其里面嵌套类DrawableEngine作为一个引擎子类,用于HomeScreen状态下的墙纸的渲染绘制(见其drawFrameLocked函数以及drawWallpaperWithCanvas和drawWallpaperWithOpenGL,后者用于当机器的内存有512MB时采用硬件加速的OpenGL进行绘制渲染,因为其更耗内存)。在drawFrameLocked中 ,是否真的要绘制更新,则由是否可见(变量mVisible)、是否需要绘制更新(mRedrawNeeded)和位置偏移有改变(mOffsetsChanged)来控制。

背景图片的绘制区域,则在updateWallpaperLocked中通过WallpaperManager获取背景图的位图来得到:
mBackground = mWallpaperManager.getBitmap();

注意:所得到的位图的尺寸则在WallpaperManagerService.java中确定,见WallpaperManagerService的两个函数getWidthHint和getHeightHint。而后两者中的背景图片中的高和寬的值则由WallpaperManagerService.loadSettingsLocked装载手机中的/data/system/wallpaer_info.xml得到(当刷机第一次重启或恢复出厂设置后重启时,该文件被生成,其中的值来自调用者对WallpaperManagerService.setDimensionHints的调用)。但是,第一次启动时,wallpaer_info.xml不存在,也就不采用其里面的值。这时,则采用的是getMaximumSizeDimension,也就是背景图的宽和高由getMaximumSizeDimension决定,代码如下:

// We always want to have some reasonable width hint.
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
int baseSize = d.getMaximumSizeDimension();
if (mWidth < baseSize) {
mWidth = baseSize;
}
if (mHeight < baseSize) {
mHeight = baseSize;
}

这有可能带来背景图不能充满整个屏幕的问题,因为ImageWallpaper.drawFrameLocked会根据surface大小来确定绘制背景:

SurfaceHolder sh = getSurfaceHolder();
final Rect frame = sh.getSurfaceFrame();
final int dw = frame.width();
final int dh = frame.height();
final int availw = dw - mBackgroundWidth;
final int availh = dh - mBackgroundHeight;
int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2);
int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2);

其中mBackgroundWidth和mBackgroundHeight来自WallpaperManagerService中的两个函数getWidthHint和getHeightHint中的变量的值。笔者的一个工程样机的调试log输出如下:
11-27 09:43:20.030 2041 2041 D ImageWallpaper: dw=1080,dh=960,mBackgroundWidth=960,mBackgroundHeight=960,availw=120,availh=0,xPixels=60,yPixels=0,mXOffset=0.0,mYOffset=0.0
通过在WallpaperManagerService.loadSettingsLocked中改变其值的方式可以解决这一问题,但只能针对该产品,不具有普遍性:

diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4925a4e..79cb8b8 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -388,7 +388,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {

public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
-
+ Slog.d(“@BillYang_ycg”, “setDimensionHints: width=”+width+”,height=”+height);
if (width }
@@ -809,7 +809,12 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
Display d = wm.getDefaultDisplay();
int baseSize = d.getMaximumSizeDimension();
if (mWidth < baseSize) {
– mWidth = baseSize;
+ //The width of background paper is not correct if use getMaximumSizeDimension
+ // when first time boot after factory reset: wallpaper dose not cover the whole screen
+ //Here I hacked it to correct this issue. Added by @BillYang_ycg, Nov 27 2012
+ int w = d.getRawWidth()*2;
+ Slog.d(“@BillYang_ycg”,”mWidth=”+w);
+ mWidth = w;
}
if (mHeight < baseSize) {
mHeight = baseSize;

以上代码基于Android 4.0.4,4.x其它版本如4.1.2应该亦适用。

本文链接地址: http://blog.redwolf-soft.com/?p=1882

原创文章,版权©红狼博客所有, 转载随意,但请注明出处。

    分享到:

相关文章:

  • 无相关文章
分类: Android, System 标签: , ,
  1. chengbom
    2013年1月29日20:40 | #1

    请问,发现,系统开机后设置了两次壁纸,理论上是一次。为何出现两次呢?又如何来杜绝出现2次设置壁纸呢?等待您的回复。

  2. BillYANG
    2013年1月30日09:40 | #2

    在系统中,不仅仅是壁纸的设置,经常会有被多次调用的情况。它们多是在不同的判断条件下,去做某个动作。第一次做完后,第二次又因为某种条件,再作一次,可能是因为这两种条件有交集,也可能是一种改善性的调用。若真正需保证调用一次,简单的方式是加一个变量进行控制。

  3. chengbom
    2013年2月2日11:48 | #3

    能 不能详细说一下,开机后是如何调用的壁纸设置,是什么导致了ImageWallpaper的绘图?如何在源头控制变化,而不是去设置变量。如果有出现情况导致开机后调用了三次,岂不每次都要更改这个变量。谢谢您的答复,请帮忙解释下。

  4. BillYang
    2013年2月4日11:09 | #4

    你可以自己去跟一下代码,看哪些地方导致了壁纸设置。变量控制的方式,如通过一个全局变量isCalled,一旦第一次调用后将变量比如设置为true,当每次调用时都检查isCalled的值,为true则直接跳过。另外,一般来说,底层的代码是允许多次被调用的,这是正常的设计原则;若有特殊需求,可以借用singleton单件模式的设计思想,如通过全局变量来控制只被调用执行一次;让使用者只调用某个函数一次,系统不能这么设计。也就是说,从源头上控制,是不好的设计思想。

订阅评论
  欢迎参与讨论,请在这里发表您的看法、交流您的观点。