./frameworks/base/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
./frameworks/base/core/java/android/service/wallpaper/WallpaperService.java
-
ImageWallpaper是Android的默认壁纸服务
-
ImageWallpaper集成了WallpaperService,WallpaperService是所有壁纸服务的基类,使用模板模式定义了壁纸服务的主要相关流程,子类根据自身需要去实现具体的自己特有的方法部分
-
壁纸服务的基本功能无外乎两点,一是获取壁纸;另一个是绘制壁纸。WallpaperService定义了一个内部类Engine,将壁纸的获取和绘制都委托给了它,所以具体的壁纸服务子类的主要任务就是实现该类
- ImageWallpaper的Engine
@Override public Engine onCreateEngine() { return new CanvasEngine(); }
- 该方法创建一个CanvasEngine实例,并将其返回,父类WallpaperService通过该方法拿到子类具体的Engine,然后实现壁纸的自定义获取和显示
1、CanvasEngine介绍
./frameworks/base/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
集成自WallpaperService.Engine
class CanvasEngine extends WallpaperService.Engine implements DisplayListener {
private WallpaperManager mWallpaperManager;
private final WallpaperLocalColorExtractor mWallpaperLocalColorExtractor;
private SurfaceHolder mSurfaceHolder;
}
CanvasEngine是ImageWallpaper实现的用于执行具体的壁纸绘制相关逻辑的执行者。其重写了父类Engine的一些方法来实现自定义的行为。
按照顺序执行,CanvasEngine先执行onCreate方法,并在改方法内部根据设备的相关信息初始化相关参数
//在WallpaperService的onBind方法执行时,会触发改方法的执行。
//用于获取设备尺寸,然后根据该信息更新相关尺寸参数
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
Trace.beginSection("ImageWallpaper.CanvasEngine#onCreate");
if (DEBUG) {
Log.d(TAG, "onCreate");
}
mWallpaperManager = getDisplayContext().getSystemService(WallpaperManager.class);
mIsLockscreenLiveWallpaperEnabled = mWallpaperManager
.isLockscreenLiveWallpaperEnabled();
//mSurfaceHolder 赋值
mSurfaceHolder = surfaceHolder;
Rect dimensions = mIsLockscreenLiveWallpaperEnabled
? mWallpaperManager.peekBitmapDimensions(getSourceFlag(), true)
: mWallpaperManager.peekBitmapDimensions();
int width = Math.max(MIN_SURFACE_WIDTH, dimensions.width());
int height = Math.max(MIN_SURFACE_HEIGHT, dimensions.height());
//使用上面获得的尺寸来更新SurfaceHolder
mSurfaceHolder.setFixedSize(width, height);
getDisplayContext().getSystemService(DisplayManager.class)
.registerDisplayListener(this, null);
getDisplaySizeAndUpdateColorExtractor();
Trace.endSection();
}
drawFrame方法
private void drawFrame() {
MyLog.d("drawFrame");
mLongExecutor.execute(this::drawFrameSynchronized);
}
private void drawFrameSynchronized() {
synchronized (mLock) {
drawFrameInternal();
}
}
private void drawFrameInternal() {
MyLog.d("drawFrameInternal");
if (mSurfaceHolder == null) {
Log.e(TAG, "attempt to draw a frame without a valid surface");
return;
}
// load the wallpaper if not already done
if (!isBitmapLoaded()) {
//加载壁纸
loadWallpaperAndDrawFrameInternal();
} else {
mBitmapUsages++;
//绘制壁纸
drawFrameOnCanvas(mBitmap);
reportEngineShown(false);
//清空壁纸
unloadBitmapIfNotUsedInternal();
}
}
loadWallpaperAndDrawFrameInternal,该方法会首先尝试通过WallpaperManager来获取壁纸,如果获取失败,则在清空壁纸缓存后再次尝试,如果依然失败,则返回null
private void loadWallpaperAndDrawFrameInternal() {
Trace.beginSection("ImageWallpaper.CanvasEngine#loadWallpaper");
boolean loadSuccess = false;
Bitmap bitmap;
try {
bitmap = mIsLockscreenLiveWallpaperEnabled
? mWallpaperManager.getBitmapAsUser(
mUserTracker.getUserId(), false, getSourceFlag(), true)
: mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
if (bitmap != null
&& bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
throw new RuntimeException("Wallpaper is too large to draw!");
}
} catch (RuntimeException | OutOfMemoryError exception) {
// Note that if we do fail at this, and the default wallpaper can't
// be loaded, we will go into a cycle. Don't do a build where the
// default wallpaper can't be loaded.
Log.w(TAG, "Unable to load wallpaper!", exception);
if (mIsLockscreenLiveWallpaperEnabled) {
mWallpaperManager.clearWallpaper(getWallpaperFlags(), mUserTracker.getUserId());
} else {
mWallpaperManager.clearWallpaper(
WallpaperManager.FLAG_SYSTEM, mUserTracker.getUserId());
}
try {
bitmap = mIsLockscreenLiveWallpaperEnabled
? mWallpaperManager.getBitmapAsUser(
mUserTracker.getUserId(), false, getSourceFlag(), true)
: mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
} catch (RuntimeException | OutOfMemoryError e) {
Log.w(TAG, "Unable to load default wallpaper!", e);
bitmap = null;
}
}
if (bitmap == null) {
Log.w(TAG, "Could not load bitmap");
} else if (bitmap.isRecycled()) {
Log.e(TAG, "Attempt to load a recycled bitmap");
} else if (mBitmap == bitmap) {
Log.e(TAG, "Loaded a bitmap that was already loaded");
} else {
// at this point, loading is done correctly.
loadSuccess = true;
// recycle the previously loaded bitmap
if (mBitmap != null) {
mBitmap.recycle();
}
mBitmap = bitmap;
mWideColorGamut = mIsLockscreenLiveWallpaperEnabled
? mWallpaperManager.wallpaperSupportsWcg(getSourceFlag())
: mWallpaperManager.wallpaperSupportsWcg(WallpaperManager.FLAG_SYSTEM);
// +2 usages for the color extraction and the delayed unload.
mBitmapUsages += 2;
recomputeColorExtractorMiniBitmap();
drawFrameInternal();
/*
* after loading, the bitmap will be unloaded after all these conditions:
* - the frame is redrawn
* - the mini bitmap from color extractor is recomputed
* - the DELAY_UNLOAD_BITMAP has passed
*/
mLongExecutor.executeDelayed(
this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP);
}
// even if the bitmap cannot be loaded, call reportEngineShown
if (!loadSuccess) rep