Android wallpapermanager parsing and bug solving

Source: Internet
Author: User

Wallpaper of Android is one of its core modules, but wallpaper of Android has always been a bug. For example, if a single-screen image is used as a wallpaper, after the mobile phone is restarted, the image is automatically stretched to a desktop that slides along with the desktop. In this case, the desktop is used. There will be annoying black behind the wallpaper, and some black screens at the beginning and end of the wallpaper. After the wallpaper is started again, the black bars will disappear, however, the wallpaper is still stretched.

I recently learned the relevant mechanisms of wallpapermanager to solve this problem.

1. The use of wallpapermanager is obtained through getsystemservice of context when using wallpapermanager. Through wallpapermanager, we can set the wallpaper to get the width, height, and width and height of the wallpaper. It should be noted that for desktop applications similar to launcher, the requirements for wallpaper are generally high-screen, and the width is twice the screen width. This value is basically the standard value of the system. To a certain extent, it is also a standard. We know that in Android phones, when the desktop slides, the moving distance between the wallpaper and the actual sliding distance on the desktop varies a lot, and the sliding response distance varies according to the desktop width. Because of this, the actual width of the wallpaper becomes less important, because the original sliding of the desktop and the sliding of the background wallpaper do not have a numerical correspondence between them, therefore, various desktops basically follow the android standard. When using wallpapers, specify the wallpaper width to double the screen width. Similarly, the desktop can be left unspecified. The wallpaper is automatically drawn by the system when sliding.

Wallpapermanager is implemented in the form of standard aidl services, and its implementation code

By reading wallpapermanagerservice, you will find the wallpaper switching method in wallpapermanager. in simple words, when we set the wallpaper, wallpapermanager saves the wallpaper in/data/COM as a file. android. settings/files/wallpapermanager. There is also a key file,/data/system/wallpaper_info.xml. It is found that the configuration file contains the expected width and height of the wallpaper. However, reading wallpapermanager did not find the place where the wallpaper was actually drawn. After reading it carefully, I found that the wallpaper Management in Android and wallpaper painting are also notified by servicebind to draw the wallpaper, in Android, the default rendering method is systemui's imagewallpaper. by reading this part of the code, you can find that the actual wallpaper is drawn by using canvas on surfice or hardware acceleration. After learning about this, you can basically explain and solve the problems of wallpapermanager.

1. Question 1 of wallpapermanager:

After the portrait and single-screen wallpapers are specified, the wallpaper is stretched. This is mainly because of the load configuration file problem in wallpapermanagerservice. In Android, after setting the wallpaper, the width and height of the wallpaper are directly saved in the configuration file. at startup, read the configuration file and instruct the painter to draw the file. The problem is that when reading the configuration file, in Android, the width of the wallpaper is not allowed to be smaller than the height. The specific reason is not clear. After the system finds that the saved width is smaller than the height, it will stretch its width to the same height as the height, which is why the original landscape and single screen wallpaper become slide after restarting. The main problem code is as follows:

    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        }        if (!success) {            mWidth = -1;            mHeight = -1;            mName = "";        }        // 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;        }    }

 

Question 2 of wallpapermanager: Black borders on both sides of the portrait wallpaper. This problem is the problem of wallpaper painting. Simply put, the wallpaper itself is not stretched to the width required by the desktop. When painting in imagewallpaper, the width and width of the wallpaper are used to specify the location of the wallpaper. The black side is caused by the fact that the canvas is too wide and the black side is used to draw the wallpaper.

        void drawFrameLocked() {            if (!mVisible) {                if (DEBUG) {                    Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible.");                }                return;            }            if (!mRedrawNeeded && !mOffsetsChanged) {                if (DEBUG) {                    Log.d(TAG, "Suppressed drawFrame since redraw is not needed "                            + "and offsets have not changed.");                }                return;            }            if (mBackgroundWidth < 0 || mBackgroundHeight < 0) {                // If we don't yet know the size of the wallpaper bitmap,                // we need to get it now.                updateWallpaperLocked();            }            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);            mOffsetsChanged = false;            if (!mRedrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {                if (DEBUG) {                    Log.d(TAG, "Suppressed drawFrame since the image has not "                            + "actually moved an integral number of pixels.");                }                return;            }            mRedrawNeeded = false;            mLastXTranslation = xPixels;            mLastYTranslation = yPixels;            if (mBackground == null) {                // If we somehow got to this point after we have last flushed                // the wallpaper, well we really need it to draw again.  So                // seems like we need to reload it.  Ouch.                updateWallpaperLocked();            }            if (mIsHwAccelerated) {                if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {                    drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);                }            } else {                drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);            }            if (FIXED_SIZED_SURFACE) {                // If the surface is fixed-size, we should only need to                // draw it once and then we'll let the window manager                // position it appropriately.  As such, we no longer needed                // the loaded bitmap.  Yay!                mBackground = null;                mWallpaperManager.forgetLoadedWallpaper();            }        }

 

The last thought is why there is no Black edge after it is restarted?

This requires a comprehensive view of the wallpaper management and rendering methods.

1. First, after setting a wallpaper,/data/system/wallpaper_info.xml saves the wallpaper width and height.

2. After the wallpaper is turned on, when loading the wallpaper information, it is found that the width is smaller than the height, so the width and height of the wallpaper are modified, and the returned width is equal to the height. For example, if the image size is 800, the image is returned to imagewallpaper. The image size is 800x800.

3. In the standard desktop, if the width is 480*2 = 960, The imagewallpaper is required to be stretched and drawn. After calculation, the imagewallpaper sets aside enough black borders to draw the wallpaper and black edges appear. At the same time, wallpapermanager saves the width to wallpaper_info.xml, that is, the width in wallpaper_info is changed to 960.

4. After the app is started again, the returned wallpaper width will change to 960 and the image will be stretched according to 960 in imagewallpaper. Therefore, after the app is started again, there will be no black borders and it will be displayed in full screen.

 

-- Welcome to reprint, please indicate the source of http://blog.csdn.net/zyplus --

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.