Is it possible to set an animated gif file as live wallpaper in android?
This is the basic wallpaper service (as supplied in the Live Wallpaper Tutorial) hacked to display an animated gif.
First - create a project & set up your manifest as a Live wallpaper.
Then - download a gif, like this one
Save that gif in res/raw/nyan.gif
in your project.
Create a live wallpaper service, like shown in this example.
public class NyanNyanService extends WallpaperService {
static final String TAG = "NYAN";
static final Handler mNyanHandler = new Handler();
/**
* @see android.service.wallpaper.WallpaperService#onCreate()
*/
@Override
public void onCreate() {
super.onCreate();
}
/**
* @see android.service.wallpaper.WallpaperService#onCreateEngine()
*/
@Override
public Engine onCreateEngine() {
try {
return new NyanEngine();
} catch (IOException e) {
Log.w(TAG, "Error creating NyanEngine", e);
stopSelf();
return null;
}
}
class NyanEngine extends Engine {
private final Movie mNyan;
private final int mNyanDuration;
private final Runnable mNyanNyan;
float mScaleX;
float mScaleY;
int mWhen;
long mStart;
NyanEngine() throws IOException {
InputStream is = getResources().openRawResource(R.raw.nyan);
if (is != null) {
try {
mNyan = Movie.decodeStream(is);
mNyanDuration = mNyan.duration();
} finally {
is.close();
}
} else {
throw new IOException("Unable to open R.raw.nyan");
}
mWhen = -1;
mNyanNyan = new Runnable() {
public void run() {
nyan();
}
};
}
@Override
public void onDestroy() {
super.onDestroy();
mNyanHandler.removeCallbacks(mNyanNyan);
}
@Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
nyan();
} else {
mNyanHandler.removeCallbacks(mNyanNyan);
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
mScaleX = width / (1f * mNyan.width());
mScaleY = height / (1f * mNyan.height());
nyan();
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep,
float yOffsetStep, int xPixelOffset, int yPixelOffset) {
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset);
nyan();
}
void nyan() {
tick();
SurfaceHolder surfaceHolder = getSurfaceHolder();
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
nyanNyan(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
mNyanHandler.removeCallbacks(mNyanNyan);
if (isVisible()) {
mNyanHandler.postDelayed(mNyanNyan, 1000L/25L);
}
}
void tick() {
if (mWhen == -1L) {
mWhen = 0;
mStart = SystemClock.uptimeMillis();
} else {
long mDiff = SystemClock.uptimeMillis() - mStart;
mWhen = (int) (mDiff % mNyanDuration);
}
}
void nyanNyan(Canvas canvas) {
canvas.save();
canvas.scale(mScaleX, mScaleY);
mNyan.setTime(mWhen);
mNyan.draw(canvas, 0, 0);
canvas.restore();
}
}
}
This will basically scale the nyan-nyan cat to fit the screen and animate it perpetually.
A Live wallpaper manifest looks sort-of-like this (this example does not contain a configuration activity):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.nyan.nyan.package"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/application_nyan" >
<service
android:label="@string/wallpaper_nyan"
android:name=".NyanNyanService"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<meta-data android:name="android.service.wallpaper" android:resource="@xml/nyan" />
</service>
</application>
</manifest>
The AndroidManifest.xml has a reference to a file in res/xml
, in this case named "nyan.xml":
<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" />
Live wallpaper using animated gif ( with centercrop scaletype)
Your activity file
public class GIFWallpaperService extends WallpaperService {
@Override
public WallpaperService.Engine onCreateEngine() {
try {
Movie movie = Movie.decodeStream(
getResources().getAssets().open("owlinsnow.gif"));
return new GIFWallpaperEngine(movie);
}catch(IOException e){
Log.d("GIF", "Could not load asset");
return null;
}
}
private class GIFWallpaperEngine extends WallpaperService.Engine {
private final int frameDuration = 20;
private SurfaceHolder holder;
private Movie movie;
private boolean visible;
private Handler handler;
public GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
private Runnable drawGIF = new Runnable() {
public void run() {
draw();
}
};
private void draw() {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
// Adjust size and position so that
// the image looks good on your screen
canvas.scale(2f, 2f);
movie.draw(canvas, -100, 0);
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
}
@Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
Manifest file
<application android:allowBackup="true" android:label="@string/app_name"
android:icon="@drawable/owl" android:theme="@style/AppTheme">
<service
android:name=".GIFWallpaperService"
android:enabled="true"
android:label="Owl in Snow"
android:permission="android.permission.BIND_WALLPAPER" >
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/wallpaper" >
</meta-data>
</service>
</application>
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true" >
</uses-feature>
Create xml directory under res and wallpaper.xml inside it.
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="GIF Wallpaper"
android:thumbnail="@drawable/owl">
</wallpaper>
Make sure you place the gif image inside assets folder. To create an asset folder click on file->New->Folder->assets
How to fit content of GIF animation in View and in live wallpaper?
OK I think I got how to scale the content. Not sure though why the app still crashes upon orientation change sometimes, and why the app doesn't show the preview right away sometimes.
Project is available here.
For center-inside, the code is:
private fun draw() {
if (!isVisible)
return
val canvas = holder!!.lockCanvas() ?: return
canvas.save()
//center-inside
val scale = Math.min(canvas.width.toFloat() / movie.width().toFloat(), canvas.height.toFloat() / movie.height().toFloat());
val x = (canvas.width.toFloat() / 2f) - (movie.width().toFloat() / 2f) * scale;
val y = (canvas.height.toFloat() / 2f) - (movie.height().toFloat() / 2f) * scale;
canvas.translate(x, y)
canvas.scale(scale, scale)
movie.draw(canvas, 0f, 0f)
canvas.restore()
holder!!.unlockCanvasAndPost(canvas)
movie.setTime((System.currentTimeMillis() % movie.duration()).toInt())
handler.removeCallbacks(drawGIF)
handler.postDelayed(drawGIF, frameDuration.toLong())
}
For center-crop, the code is:
private fun draw() {
if (!isVisible)
return
val canvas = holder!!.lockCanvas() ?: return
canvas.save()
//center crop
val scale = Math.max(canvas.width.toFloat() / movie.width().toFloat(), canvas.height.toFloat() / movie.height().toFloat());
val x = (canvas.width.toFloat() / 2f) - (movie.width().toFloat() / 2f) * scale;
val y = (canvas.height.toFloat() / 2f) - (movie.height().toFloat() / 2f) * scale;
canvas.translate(x, y)
canvas.scale(scale, scale)
movie.draw(canvas, 0f, 0f)
canvas.restore()
holder!!.unlockCanvasAndPost(canvas)
movie.setTime((System.currentTimeMillis() % movie.duration()).toInt())
handler.removeCallbacks(drawGIF)
handler.postDelayed(drawGIF, frameDuration.toLong())
}
for fit-center, I can use this:
val canvasWidth = canvas.width.toFloat()
val canvasHeight = canvas.height.toFloat()
val bitmapWidth = curBitmap.width.toFloat()
val bitmapHeight = curBitmap.height.toFloat()
val scaleX = canvasWidth / bitmapWidth
val scaleY = canvasHeight / bitmapHeight
scale = if (scaleX * curBitmap.height > canvas.height) scaleY else scaleX
x = (canvasWidth / 2f) - (bitmapWidth / 2f) * scale
y = (canvasHeight / 2f) - (bitmapHeight / 2f) * scale
...
Set Animated .GIF As Background Android
As Martin says, Android does not support GIFs. As a workaround, Android offers Animation List/AnimationDrawable. You will need to convert the GIF into individual frames [.png files]. I use GIMP for the conversion
This GIF can be broken down into its frames:
Save them as frame01.png, frame02.png, and so on, and create an animation-list XML file, say, progress_animation.xml
<animation-list android:id="@+id/selected" android:oneshot="false">
<item android:drawable="@drawable/frame01" android:duration="50" />
<item android:drawable="@drawable/frame02" android:duration="50" />
<item android:drawable="@drawable/frame03" android:duration="50" />
....
<item android:drawable="@drawable/frameN" android:duration="50" />
To begin the animation, you need to cast the image to an AnimationDrawable, and call start() on it
AnimationDrawable progressAnimation = (AnimationDrawable) yourImageView.getBackground();
progressAnimation.start();
Using .gif file in android live wallpaper
I have tried the example it works for me. Also i have tried this with different .gif images and it doesn't seems that their is any problem. My code for that is .
{
/**
* Method to init suitable wallpaper according to time.
*/
private void initWallpaperAccordingtoTime(InputStream inputStream) {
if (inputStream != null) {
try {
wallpaperGifStream = Movie.decodeStream(inputStream);
if (wallpaperGifStream != null) {
duration = wallpaperGifStream.duration();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Call to this method will be as follows.
initWallpaperAccordingtoTime(getResources().openRawResource(
R.raw.android_apple));
}
Related Topics
Android Emulator Not Receiving Push Notifications
Android - Margins Specified in Custom Style Not Taking Effect
Which Port and Protocol Does Google Cloud Messaging (Gcm) Use
Cordova - Error: Failed to Fetch Platform Android
How to Detect App Removed from the Recent List
Android Options Menu Icon Won't Display
Android 2.1 View's Getdrawingcache() Method Always Returns Null
Sending Intent with Bundle Using Console
Scrolling Edittext Inside Scrollview
Ask for Password Before Uninstalling Application
Extracting Information from a Scanned Gs1-Type Barcode
Cannot Resolve Mapactivity Class on Android
Handling Keepsynced() While on Background on Android and with Fcm
How to Get Meid and Imei Information Using Adb Commands on Android 5.0
"File Not Found" Exception in Dexdebug Task of Build
Live-Stream Video from One Android Phone to Another Over Wifi
Android - Build Separate APKs for Different Processor Architectures