android - How to make a Live Wallpaper

GradientLiveWallPaperService.java
 package com.cfsuman.me.gradientlivewallpaper;  import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.os.Handler; import android.service.wallpaper.WallpaperService; import android.view.SurfaceHolder; import java.util.Random;  /*     WallpaperService         A wallpaper service is responsible for showing a live wallpaper behind applications that         would like to sit on top of it. This service object itself does very little -- its only         purpose is to generate instances of WallpaperService.Engine as needed. Implementing a         wallpaper thus involves subclassing from this, subclassing an Engine implementation, and         implementing onCreateEngine() to return a new instance of your engine. */ public class GradientLiveWallPaperService extends WallpaperService {     private Context mContext;     /*         Handler             A Handler allows you to send and process Message and Runnable objects associated with a             thread's MessageQueue. Each Handler instance is associated with a single thread and that             thread's message queue. When you create a new Handler, it is bound to the thread / message             queue of the thread that is creating it -- from that point on, it will deliver messages             and runnables to that message queue and execute them as they come out of the message queue.     */     private Handler mHandler = new Handler();     private Random mRandom = new Random();     private Point mSize = new Point();      private int mInterval = 50;      private int mIndicator;     private boolean mRegenerateTopLayerPaint = true;     private boolean mRegenerateBottomLayerPaint = true;     private int mPaintTopLayerAlpha = 0;     private Paint mPaintTopLayer = new Paint();     private Paint mPaintBottomLayer = new Paint();      private GradientManager mGradientManager;       /*         WallpaperService.Engine             The actual implementation of a wallpaper. A wallpaper service may have multiple instances             running (for example as a real wallpaper and as a preview), each of which is represented             by its own Engine instance. You must implement onCreateEngine() to return your concrete             Engine implementation.          public abstract WallpaperService.Engine onCreateEngine ()             Must be implemented to return a new instance of the wallpaper's engine. Note that             multiple instances may be active at the same time, such as when the wallpaper is             currently set as the active wallpaper and the user is in the wallpaper picker viewing             a preview of it as well.     */     public Engine onCreateEngine(){         return new GradientLiveWallpaperEngine();     }      // New private WallpaperService.Engine class started     private class GradientLiveWallpaperEngine extends Engine{         // To determine whether live wallpaper is visible state         boolean mVisible = true;          /*             Runnable                 Represents a command that can be executed. Often used to run code in a different Thread.         */         Runnable mRunnable = new Runnable() {             /*                 public abstract void run ()                     Starts executing the active part of the class' code. This method is called when                     a thread is started that has been created with a class which implements Runnable.             */             @Override             public void run() {                 drawGradient();             }         };          public GradientLiveWallpaperEngine(){         }          /*             public void onDestroy ()                 Called right before the engine is going away. After this the surface will be                 destroyed and this Engine object is no longer valid.         */         @Override         public void onDestroy() {             super.onDestroy();             mHandler.removeCallbacks(mRunnable);           }          /*             public void onVisibilityChanged (boolean visible)                 Called to inform you of the wallpaper becoming visible or hidden. It is very                 important that a wallpaper only use CPU while it is visible..         */         @Override         public void onVisibilityChanged(boolean visible){             mVisible = visible;             if (visible) {                 drawGradient();             } else {                 mHandler.removeCallbacks(mRunnable);             }         }          /*             public void onSurfaceDestroyed (SurfaceHolder holder)                 Convenience for SurfaceHolder.Callback.surfaceDestroyed().              public abstract void surfaceDestroyed (SurfaceHolder holder)                 This is called immediately before a surface is being destroyed. After returning from                 this call, you should no longer try to access this surface. If you have a rendering                 thread that directly accesses the surface, you must ensure that thread is no longer                 touching the Surface before returning from this function.         */         @Override         public void onSurfaceDestroyed(SurfaceHolder holder){             super.onSurfaceDestroyed(holder);             mVisible = false;             mHandler.removeCallbacks(mRunnable);         }          // Custom method to draw a color pallet         void drawGradient(){             /*                 SurfaceHolder                     Abstract interface to someone holding a display surface. Allows you to control                     the surface size and format, edit the pixels in the surface, and monitor changes                     to the surface. This interface is typically available through the SurfaceView class.             */             // Get the SurfaceHolder object             SurfaceHolder holder = getSurfaceHolder();              /*                 Canvas                     The Canvas class holds the "draw" calls. To draw something, you need 4 basic                     components: A Bitmap to hold the pixels, a Canvas to host the draw calls                     (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap),                     and a paint (to describe the colors and styles for the drawing).             */             /*                 public abstract Canvas lockCanvas ()                     Start editing the pixels in the surface. The returned Canvas can be used to draw                     into the surface's bitmap. A null is returned if the surface has not been                     created or otherwise cannot be edited. You will usually need to implement                     Callback.surfaceCreated to find out when the Surface is available for use.             */             // Initialize the Canvas to draw something             Canvas canvas = holder.lockCanvas();              // Get the application context             mContext = getApplicationContext();              // Set the point x y values             mSize.x = canvas.getWidth();             mSize.y = canvas.getHeight();              // Initialize a new instance of GradientManager class             mGradientManager = new GradientManager(mContext,mSize);              try{                 /*                     We will draw canvas with two layers, top and bottom                     Top layer continuously change its transparency                     Top layer transparency cycle is 0 > 255 > 0                      When top layer transparency reach 255                         then we will convert it again zero                         Replace the bottom layer shader with top layer shader                         Regenerate the top layer shader                 */                  // If required regenerate the top layer shader                 if(mRegenerateTopLayerPaint){                     /*                         setDither(boolean dither)                             Helper for setFlags(), setting or clearing the DITHER_FLAG bit Dithering                             affects how colors that are higher precision than the device are down-sampled.                     */                     mPaintTopLayer.setDither(true);                     mIndicator = mRandom.nextInt(3);                     // Assign the random gradient type gradient                     if(mIndicator == 0){                         mPaintTopLayer.setShader(mGradientManager.getRandomLinearGradient());                     }else if(mIndicator == 1){                         mPaintTopLayer.setShader(mGradientManager.getRandomRadialGradient());                     }else {                         mPaintTopLayer.setShader(mGradientManager.getRandomSweepGradient());                     }                 }                  // If required regenerate the bottom layer shader                 if(mRegenerateBottomLayerPaint){                     mPaintBottomLayer.setDither(true);                     mIndicator = mRandom.nextInt(3);                     // Assign the random gradient type gradient                     if(mIndicator == 0){                         /*                             Paint                                 The Paint class holds the style and color information about how to                                 draw geometries, text and bitmaps.                              setShader(Shader shader)                                 Set or clear the shader object.                              Shader                                 Shader is the based class for objects that return horizontal spans                                 of colors during drawing. A subclass of Shader is installed in a                                 Paint calling paint.setShader(shader). After that any object                                 (other than a bitmap) that is drawn with that paint will get its                                 color(s) from the shader.                         */                         mPaintBottomLayer.setShader(mGradientManager.getRandomLinearGradient());                     }else if(mIndicator == 1){                         mPaintBottomLayer.setShader(mGradientManager.getRandomRadialGradient());                     }else {                         mPaintBottomLayer.setShader(mGradientManager.getRandomSweepGradient());                     }                 }                   /*                     setAlpha(int a)                         Helper to setColor(), that only assigns the color's alpha value, leaving                         its r,g,b values unchanged.                 */                 // Set the top layer alpha                 mPaintTopLayer.setAlpha(mPaintTopLayerAlpha);                  if(mPaintTopLayerAlpha <256){                     mPaintTopLayerAlpha ++;                     mRegenerateTopLayerPaint = false;                     mRegenerateBottomLayerPaint = false;                 }                  /*                     drawRect(float left, float top, float right, float bottom, Paint paint)                         Draw the specified Rect using the specified paint.                 */                 // Finally, draw the canvas with two layer                 canvas.drawRect(0,0,mSize.x,mSize.y,mPaintBottomLayer);                 canvas.drawRect(0,0,mSize.x,mSize.y,mPaintTopLayer);                  if (mPaintTopLayerAlpha == 256)                 {                     /*                         Rule - To generate continuous animation                              top layer alpha = 0 (full transparent)                             top layer = null (regenerate)                             bottom layer shader = top layer shader                     */                     mPaintTopLayerAlpha = 0;                     mPaintBottomLayer.setShader(mPaintTopLayer.getShader());                     mRegenerateTopLayerPaint = true;                 }              }finally{                 if (canvas != null){                     /*                         public abstract void unlockCanvasAndPost (Canvas canvas)                             Finish editing pixels in the surface. After this call, the surface's                             current pixels will be shown on the screen, but its content is lost, in                             particular there is no guarantee that the content of the Surface will                             remain unchanged when lockCanvas() is called again.                              Parameters                                 canvas : The Canvas previously returned by lockCanvas().                     */                     holder.unlockCanvasAndPost(canvas);                 }             }              /*                 removeCallbacks(Runnable r)                     Remove any pending posts of Runnable r that are in the message queue.             */             // Now remove the call backs from handler             mHandler.removeCallbacks(mRunnable);              // If visible continue the animation             if(mVisible){                 /*                     postDelayed(Runnable r, long delayMillis)                         Causes the Runnable r to be added to the message queue, to be run after the                         specified amount of time elapses.                 */                 mHandler.postDelayed(mRunnable, mInterval);             }         }     } // WallpaperService.Engine class end }// WallpaperService class end 
GradientManager.java
 package com.cfsuman.me.gradientlivewallpaper;  import android.content.Context; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Point; import android.graphics.RadialGradient; import android.graphics.Shader; import android.graphics.SweepGradient; import java.util.Random;   public class GradientManager {     private Random mRandom = new Random();     private Context mContext;     private Point mSize;      public GradientManager(Context context, Point size){         this.mContext = context;         this.mSize = size;     }      // Custom method to generate a random LinearGradient     protected LinearGradient getRandomLinearGradient(){         /*             public LinearGradient (float x0, float y0, float x1, float y1, int[] colors, float[]                 positions, Shader.TileMode tile)                  Create a shader that draws a linear gradient along a line.                  Parameters                 x0 : The x-coordinate for the start of the gradient line                 y0 : The y-coordinate for the start of the gradient line                 x1 : The x-coordinate for the end of the gradient line                 y1 : The y-coordinate for the end of the gradient line                 colors : The colors to be distributed along the gradient line                 positions : May be null. The relative positions [0..1] of each corresponding color                     in the colors array. If this is null, the the colors are distributed evenly                     along the gradient line.                 tile : The Shader tiling mode         */          LinearGradient gradient = new LinearGradient(                 0,                 0,                 mSize.x,                 mSize.y,                 getRandomColorArray(), // Colors to draw the gradient                 null, // No position defined                 getRandomShaderTileMode() // Shader tiling mode         );         // Return the LinearGradient         return gradient;     }      // Custom method to generate a random RadialGradient     protected RadialGradient getRandomRadialGradient(){         /*             public RadialGradient (float centerX, float centerY, float radius, int[] colors,                 float[] stops, Shader.TileMode tileMode)                  Create a shader that draws a radial gradient given the center and radius.                  Parameters                     centerX : The x-coordinate of the center of the radius                     centerY : The y-coordinate of the center of the radius                     radius : Must be positive. The radius of the circle for this gradient.                     colors : The colors to be distributed between the center and edge of the circle                     stops : May be null. Valid values are between 0.0f and 1.0f. The relative                         position of each corresponding color in the colors array. If null, colors                         are distributed evenly between the center and edge of the circle.                     tileMode : The Shader tiling mode         */         RadialGradient gradient = new RadialGradient(             mRandom.nextInt(mSize.x),                 mRandom.nextInt(mSize.y),                 mRandom.nextInt(mSize.x),                 getRandomColorArray(),                 null, // Stops position is undefined                 getRandomShaderTileMode() // Shader tiling mode          );         // Return the RadialGradient         return gradient;     }      // Custom method to generate a random SweepGradient     protected SweepGradient getRandomSweepGradient(){         /*             public SweepGradient (float cx, float cy, int[] colors, float[] positions)                 A subclass of Shader that draws a sweep gradient around a center point.                  Parameters                 cx : The x-coordinate of the center                 cy : The y-coordinate of the center                 colors : The colors to be distributed between around the center. There must be at                     least 2 colors in the array.                 positions : May be NULL. The relative position of each corresponding color in the                     colors array, beginning with 0 and ending with 1.0. If the values are not                     monotonic, the drawing may produce unexpected results. If positions is NULL,                     then the colors are automatically spaced evenly.         */         SweepGradient gradient = new SweepGradient(                 mRandom.nextInt(mSize.x),                 mRandom.nextInt(mSize.y),                 getRandomColorArray(), // Colors to draw gradient                 null // Position is undefined         );         // Return the SweepGradient         return gradient;     }      // Custom method to generate random Shader TileMode     protected Shader.TileMode getRandomShaderTileMode(){         /*             Shader                 Shader is the based class for objects that return horizontal spans of colors during                 drawing. A subclass of Shader is installed in a Paint calling paint.setShader(shader).                 After that any object (other than a bitmap) that is drawn with that paint will get                 its color(s) from the shader.         */         Shader.TileMode mode;         int indicator = mRandom.nextInt(3);         if(indicator==0){             /*                 Shader.TileMode : CLAMP                     replicate the edge color if the shader draws outside of its original bounds             */             mode = Shader.TileMode.CLAMP;         }else if(indicator==1){             /*                 Shader.TileMode : MIRROR                     repeat the shader's image horizontally and vertically, alternating mirror images                     so that adjacent images always seam             */             mode = Shader.TileMode.MIRROR;         }else {             /*                 Shader.TileMode : REPEAT                     repeat the shader's image horizontally and vertically             */             mode = Shader.TileMode.REPEAT;         }         // Return the random Shader TileMode         return mode;     }      // Custom method to generate random color array     protected int[] getRandomColorArray(){         int length = mRandom.nextInt(16-3)+3;         int[] colors = new int[length];         for (int i=0; i<length;i++){             colors[i]=getRandomHSVColor();         }         // Return the color array         return colors;     }      // Custom method to generate random HSV color     protected int getRandomHSVColor(){         /*             Hue is the variation of color             Hue range 0 to 360              Saturation is the depth of color             Range is 0.0 to 1.0 float value             1.0 is 100% solid color              Value/Black is the lightness of color             Range is 0.0 to 1.0 float value             1.0 is 100% bright less of a color that means black         */          // Generate a random hue value between 0 to 360         int hue = mRandom.nextInt(361);          // We make the color depth full         float saturation = 1.0f;          // We make a full bright color         float value = 1.0f;          // We avoid color transparency         int alpha = 255;          // Finally, generate the color         int color = Color.HSVToColor(alpha,new float[]{hue,saturation,value});          // Return the color         return color;     }      /*         Another way to generate a random color         Custom method to generate a random color     */     protected int getRandomRGBColor(){         // 256 is excluded, so random number is between 0 to 255         int red = mRandom.nextInt(256);         int green = mRandom.nextInt(256);         int blue = mRandom.nextInt(256);         int color = Color.argb(255, red, green, blue);          // Return the random argb color         return color;     } } 
xml/colored_live_wallpaper.xml
 <?xml version="1.0" encoding="utf-8"?> <wallpaper     xmlns:android="http://schemas.android.com/apk/res/android"     android:label="Gradient Live Wallpaper"     android:thumbnail="@drawable/preview"     /> 
AndroidManifest.xml
 <manifest     xmlns:android="http://schemas.android.com/apk/res/android"     package="com.cfsuman.me.gradientlivewallpaper"     >      <application         android:allowBackup="true"         android:label="@string/app_name"         android:icon="@mipmap/ic_launcher"         android:supportsRtl="true"         android:theme="@style/AppTheme">          <service             android:name=".GradientLiveWallPaperService"             android:label="Gradient Live Wallpaper"             android:enabled="true"             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/colored_live_wallpaper"                 >             </meta-data>         </service>      </application>      <uses-feature         android:name="android.software.live_wallpaper"         android:required="true"         />  </manifest> 
More android examples

Komentar