android壁纸设置bug(一)

本文探讨了如何修改WallpaperPicker应用,实现默认壁纸同时设置为桌面和锁屏,避免耗时问题。讨论了两种思路,包括细分设置逻辑和修改framework层。重点在于解决锁屏与桌面壁纸同步的问题,以及发现并修复实际应用中的显示bug。
摘要由CSDN通过智能技术生成
问题描述

设置壁纸A为桌面和锁屏壁纸,设置默认壁纸为桌面壁纸,锁屏壁纸也变为默认壁纸A。

问题分析

设置默认壁纸为桌面壁纸时
vendor/mediatek/proprietary/packages/apps/WallpaperPicker/src/com/android/wallpaperpicker/tileinfo/DefaultWallpaperInfo.java

@Override
    public void onSave(final WallpaperPickerActivity a) {
        CropAndSetWallpaperTask.OnEndCropHandler onEndCropHandler
                = new CropAndSetWallpaperTask.OnEndCropHandler() {
            @Override
            public void run(boolean cropSucceeded) {
                if (cropSucceeded) {
                    a.setResult(Activity.RESULT_OK);
                }
                a.finish();
            }
        };
        CropAndSetWallpaperTask setWallpaperTask = new CropAndSetWallpaperTask(
                null, a, null, -1, -1, -1, onEndCropHandler) {
            @Override
            protected Boolean doInBackground(Integer... params) {
                int whichWallpaper = params[0];
                boolean succeeded;
                //当设置默认壁纸为锁屏壁纸时,走setDefaultOnLock
                //设置默认壁纸为桌面壁纸或者桌面和锁屏壁纸都走的是clearWallpaper,传入whichWallpaper参数
                if (whichWallpaper == WallpaperManagerCompat.FLAG_SET_LOCK) {
                    succeeded = setDefaultOnLock(a);
                } else {
                    succeeded = clearWallpaper(a, whichWallpaper);
                }
                return succeeded;
            }
        };

        DialogUtils.executeCropTaskAfterPrompt(a, setWallpaperTask, a.getOnDialogCancelListener());
    }
思路1

修改wallpaperPick应用,细分默认壁纸设置。
优势:只需要修改app,不需要修改framework层逻辑。
缺点:单独设置默认壁纸为桌面或者锁屏壁纸时,耗时严重

@Override
protected Boolean doInBackground(Integer... params) {
    int whichWallpaper = params[0];
    boolean succeeded;
    if (whichWallpaper == WallpaperManagerCompat.FLAG_SET_LOCK || whichWallpaper == WallpaperManagerCompat.FLAG_SET_SYSTEM) {
        succeeded = setDefaultOnLockOrHome(a,whichWallpaper);
    } else {
        succeeded = clearWallpaper(a, whichWallpaper);
    }
    return succeeded;
}
//这里设置默认壁纸为锁屏壁纸,操作的时候界面会卡很久
//如果我们把FLAG_SET_LOCK换为FLAG_SET_SYSTEM,就是设置主屏幕壁纸
//我们可以添加一个int whichWallpaper参数,决定设置为哪一个
private boolean setDefaultOnLock(WallpaperPickerActivity a) {
        boolean succeeded = true;
        try {
            Bitmap defaultWallpaper = ((BitmapDrawable) WallpaperManager.getInstance(
                    a.getApplicationContext()).getBuiltInDrawable()).getBitmap();
            ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
            if (defaultWallpaper.compress(Bitmap.CompressFormat.PNG, 100, tmpOut)) {
                byte[] outByteArray = tmpOut.toByteArray();
                WallpaperManagerCompat.getInstance(a.getApplicationContext())
                        .setStream(new ByteArrayInputStream(outByteArray), null,
                                true, WallpaperManagerCompat.FLAG_SET_LOCK);
            }
        } catch (IOException e) {
            Log.w(TAG, "Setting wallpaper to default threw exception", e);
            succeeded = false;
        }
        return succeeded;
    }

对setDefaultOnLock方法进行改造,修改后

private boolean setDefaultOnLockOrHome(WallpaperPickerActivity a,int whichWallpaper) {
        boolean succeeded = true;
        try {
            Bitmap defaultWallpaper = ((BitmapDrawable) WallpaperManager.getInstance(
                    a.getApplicationContext()).getBuiltInDrawable()).getBitmap();
            ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
            if (defaultWallpaper.compress(Bitmap.CompressFormat.PNG, 100, tmpOut)) {
                byte[] outByteArray = tmpOut.toByteArray();
                WallpaperManagerCompat.getInstance(a.getApplicationContext())
                        .setStream(new ByteArrayInputStream(outByteArray), null,
                                true, whichWallpaper);
            }
        } catch (IOException e) {
            Log.w(TAG, "Setting wallpaper to default threw exception", e);
            succeeded = false;
        }
        return succeeded;
    }
思路2

我们注意到,clearWallpaper(a, whichWallpaper);其实是有传入参数的,那么按照这个逻辑,应该是可以分别对锁屏或者桌面壁纸进行清除,使它显示默认壁纸,而不影响另一个。

frameworks/base/core/java/android/app/WallpaperManager.java

//可以看到,判断当clear参数为FLAG_SYSTEM的时候走了clear,而不是clearWallpaper
public void clear(@SetWallpaperFlags int which) throws IOException {
    if ((which & FLAG_SYSTEM) != 0) {
        clear();
    }
    if ((which & FLAG_LOCK) != 0) {
        clearWallpaper(FLAG_LOCK, mContext.getUserId());
    }
}

修改为:

public void clear(@SetWallpaperFlags int which) throws IOException {
	//如果清除桌面和锁屏壁纸
    if ((which & FLAG_SYSTEM) != 0 && (which & FLAG_LOCK) != 0){
        clear();
    }
    //如果只清除桌面
    if ((which & FLAG_SYSTEM) != 0) {
        clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
    }
    //如果只清除锁屏壁纸
    if ((which & FLAG_LOCK) != 0) {
        clearWallpaper(FLAG_LOCK, mContext.getUserId());
    }
}

按照理解,这样就可以了。但是实际上测下来还是没有效果。
原因
1、桌面壁纸显示为:vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/ImageWallpaper.java
当桌面和锁屏显示不同的壁纸,锁屏壁纸显示为:
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java中的private ImageView mBackdropFront;

2、桌面和锁屏显示同一张壁纸的时候,锁屏其实不显示壁纸,透明过去显示桌面壁纸。
直接清除桌面壁纸,从效果上来说,锁屏不显示壁纸,透过去看到桌面壁纸,所以看上去桌面壁纸和锁屏壁纸都变了。

我们需要在清除壁纸之前,把桌面壁纸设置为锁屏壁纸,再去清除桌面壁纸。

这个思想来自于WallpaperManagerService的setWallpaper。见下文↓

frameworks/base/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java

//桌面壁纸
private final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
//锁屏壁纸
private final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();

//当我们设置壁纸时,如果上一次桌面和锁屏壁纸相同,如果直接设置下一张壁纸为桌面壁纸,那么锁屏壁纸会跟着变。
//这时候有一个特殊处理:::
//判断是设置桌面壁纸并且锁屏没有单独设置,先把当前壁纸设置为锁屏壁纸。
//migrateSystemToLockWallpaperLocked
//再把要设置的壁纸设置为桌面壁纸
public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
        Rect cropHint, boolean allowBackup, Bundle extras, int which,
        IWallpaperManagerCallback completion, int userId) {
	...
    synchronized (mLock) {
        if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
        WallpaperData wallpaper;

        /* If we're setting system but not lock, and lock is currently sharing the system
         * wallpaper, we need to migrate that image over to being lock-only before
         * the caller here writes new bitmap data.
         */
        if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
            Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
                    + "updating system wallpaper");
            migrateSystemToLockWallpaperLocked(userId);
        }
		...
        wallpaper = getWallpaperSafeLocked(userId, which); 
    }
}

//那么,clearWallpaper的时候,我们也这样设计一下
@Override
public void clearWallpaper(String callingPackage, int which, int userId) {
    if (DEBUG) Slog.v(TAG, "clearWallpaper");
    ...
    synchronized (mLock) {
    	//add start如果清除的是桌面壁纸,并且之前锁屏没有壁纸,先把桌面壁纸复制到锁屏壁纸
        if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
            Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
                    + "clear system wallpaper");
            migrateSystemToLockWallpaperLocked(userId);
        }
        //add end再进行清除系统壁纸
        clearWallpaperLocked(false, which, userId, null);

        if (which == FLAG_LOCK) {
            data = mLockWallpaperMap.get(userId);
        }
        if (which == FLAG_SYSTEM || data == null) {
            data = mWallpaperMap.get(userId);
        }
    }
    ...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值