问题描述
设置壁纸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);
}
}
...
}