I\'m new to Android platform. I wish to develop a live wallpaper application. When i was searched regarding this in search Engine\'s, many of them created a
See this article: How to set gif as android live wallpaper - techprpr - Medium
Jens answer use "Movie" class, but Movie class is deprecated in android api 28
so when api >= 28, I use AnimatedImageDrawable instead
Setup live wallpaper like Jens answer, and I change wallpaper service code:
wallpaper service: AnimWallpaper
public class AnimWallpaper extends WallpaperService {
@Override
public Engine onCreateEngine() {
return new CustomEngine();
}
class CustomEngine extends Engine {
UseAnim useAnim;
public CustomEngine() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
useAnim = new UseAnim(getApplicationContext(), getSurfaceHolder(), R.raw.gif2);
}
}
@Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
useAnim.restart();
} else {
useAnim.stop();
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
useAnim.updateScaleAndPadding2(width, height);
useAnim.restart();
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) {
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset);
useAnim.restart();
}
@Override
public void onDestroy() {
super.onDestroy();
useAnim.stop();
}
}
}
UseAnim
class UseAnim {
SurfaceHolder holder;
Runnable startRunnable;
AnimatedImageDrawable gif;
float fps = 60;
Handler handler = new Handler();
@RequiresApi(api = Build.VERSION_CODES.P)
public UseAnim(Context ctx, SurfaceHolder holder, int gifResId) {
this.holder = holder;
final ImageDecoder.Source src = ImageDecoder.createSource(ctx.getResources(), gifResId);
startRunnable = new Runnable() {
@Override
public void run() {
start();
}
};
new Handler().post(new Runnable() {
@Override
public void run() {
try {
UseAnim.this.gif = (AnimatedImageDrawable) ImageDecoder.decodeDrawable(src);
} catch (IOException e) {
throw new RuntimeException(e);
}
UseAnim.this.gif.start();
}
});
}
public void restart() {
stop();
start();
}
float scale = -1;
public void start() {
// since get gif with AnimatedImageDrawable must be in handler.post, so gif maybe null
if (gif != null) {
Canvas canvas = null;
try {
if (scale == -1) {
updateScaleAndPadding();
}
canvas = holder.lockCanvas();
if (canvas != null) {
canvas.translate(horiPadding, vertiPadding);
canvas.scale(scale, scale);
gif.draw(canvas);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
handler.removeCallbacks(startRunnable);
handler.postDelayed(startRunnable, (long) (1000L / fps));
}
public void stop() {
handler.removeCallbacks(startRunnable);
}
int horiPadding;
int vertiPadding;
private void updateScaleAndPadding() {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
int cw = canvas.getWidth();
int ch = canvas.getHeight();
updateScaleAndPadding2(cw, ch);
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
public void updateScaleAndPadding2(int cw, int ch) {
if (gif != null) {
int gifW = gif.getIntrinsicWidth();
int gifH = gif.getIntrinsicHeight();
if (gifW * 1f / gifH > cw * 1f / ch) {
scale = ch * 1f / gifH;
} else {
scale = cw * 1f / gifW;
}
horiPadding = (int) ((cw - gifW * scale) / 2);
vertiPadding = (int) ((ch - gifH * scale) / 2);
}
}
}