Android WallpaperManager解析及BUG解决

Android系统的壁纸是其核心模块之一,但是一直以来壁纸Android的壁纸又有其一直的BUG。例如使用单屏的图片作为壁纸,在手机重启后,会自动拉伸图片变为随桌面一起滑动的桌面。还有就是在这种情况下使用桌面,壁纸后面会有恼人的黑色,在壁纸的开始、结束部分会有一部分黑屏,再次启动后黑条会消失,但壁纸还是处于拉伸状态。

近期对该问题通过学习WallpaperManager的相关机制,解决了上述问题,先特分享出来。

1.WallpaperManager的使用,WallpaperManager在使用时通过Context的getSystemService来获取,通过WallpaperManager我们可以实现设置壁纸,获取壁纸的宽度、高度、设置所需壁纸的宽度高度。这里需要说明的是,对于类似于Launcher一类的桌面应用来说,一般对壁纸的要求都是高度全屏,宽度为屏幕宽度的两倍。这个数值基本是系统的标准数值。从一定程度上来说也是标准。我们知道在Android手机中,桌面滑动时,每次壁纸进行的滑动与桌面实际滑动距离不一样,相差很多的,会根据桌面的宽度,滑动响应的距离。正因为如此,对壁纸的实际宽度的指定就变得没有那么重要了,因为本来桌面的滑动跟后面壁纸的滑动二者没有数值上的对应关系,所以各家桌面基本都遵守Android标准的规定,使用壁纸时指定壁纸宽度为屏幕宽度的两倍。同样的,桌面也可以不指定,在滑动时壁纸由系统自动绘制。

WallpaperManager采用的标准的AIDL服务的形式实现,其实现代码

通过阅读WallpaperManagerService会发现WallpaperManager中进行壁纸切换的方式,简单来说在我们设置壁纸时,WallpaperManager把壁纸以文件的形式保存在/data/data/com.android.settings/files/WallpaperManager。同时还有一个关键的文件,/data/system/wallpaper_info.xml,发现该配置文件中保存有壁纸的期望宽度与高度。但是阅读WallpaperManager并没有发现壁纸真正绘制的地方,仔细阅读后,发现Android中的壁纸管理与壁纸绘制同样通过ServiceBind的方式来通知绘制壁纸,在Android中默认的绘制方式SystemUI的ImageWallpaper,通过阅读该部分代码,可以发现壁纸的真正绘制通过Surfice上使用Canvas,或硬件加速的方式实现绘制。了解到这里基本就可以解释、解决WallpaperManager的问题了。

1.WallpaperManager的问题一:

指定竖屏、单屏壁纸后,开机壁纸被拉伸。这个主要是在WallpaperManagerService中load配置文件的问题,在Android中,设置壁纸后,直接会将壁纸的宽度、高度保存在配置文件中,在启动时,读取配置文件,指导绘制方进行绘制。问题就出在读取配置文件的时候,在Android中,不允许壁纸的宽度比高度小,具体的原因没有看明白,系统中在发现保存的宽度比高度小后,会对其宽度进行拉伸,拉到与高度一样高,这就是为什么原来竖屏、单屏的壁纸重启后变成可以滑动的了。主要问题代码如下:

private void loadSettingsLocked() {
        if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
       
        JournaledFile journal = makeJournaledFile();
        FileInputStream stream = null;
        File file = journal.chooseForRead();
        boolean success = false;
        try {
            stream = new FileInputStream(file);
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(stream, null);

int type;
            do {
                type = parser.next();
                if (type == XmlPullParser.START_TAG) {
                    String tag = parser.getName();
                    if ("wp".equals(tag)) {
                        mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
                        mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
                        mName = parser.getAttributeValue(null, "name");
                        String comp = parser.getAttributeValue(null, "component");
                        mNextWallpaperComponent = comp != null
                                ? ComponentName.unflattenFromString(comp)
                                : null;
                        if (mNextWallpaperComponent == null ||
                                "android".equals(mNextWallpaperComponent.getPackageName())) {
                            mNextWallpaperComponent = mImageWallpaperComponent;
                        }
                         
                        if (DEBUG) {
                            Slog.v(TAG, "mWidth:" + mWidth);
                            Slog.v(TAG, "mHeight:" + mHeight);
                            Slog.v(TAG, "mName:" + mName);
                            Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
                        }
                    }
                }
            } while (type != XmlPullParser.END_DOCUMENT);
            success = true;
        } catch (NullPointerException e) {
            Slog.w(TAG, "failed parsing " + file + " " + e);
        } catch (NumberFormatException e) {
            Slog.w(TAG, "failed parsing " + file + " " + e);
        } catch (XmlPullParserException e) {
            Slog.w(TAG, "failed parsing " + file + " " + e);
        } catch (IOException e) {
            Slog.w(TAG, "failed parsing " + file + " " + e);
        } catch (IndexOutOfBoundsException e) {
            Slog.w(TAG, "failed parsing " + file + " " + e);
        }
        try {
            if (stream != null) {
                stream.close();
            }
        } catch (IOException e) {
            // Ignore
        }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/c4b914d63fdae1ca73abdf4f0d3d6676.html