Hi, at last I was able to create my own live wallpaper " MATRIX RAIN." The matrix rain effect which I am using is the same which I created in canvas.
Ref: http://www.androidlearner.com/2016/09/create-custom-view-in-android-matrix.html
I this post I will describe how I put together the live wallpaper.
To create live wallpaper you need to set the following things
- A class which extends
WallpaperService
and further implements a nested class which extends Engine
class. This Class is responsible for calling the draw code. - A activity which displays list of settings for the wallpaper.(optional). Here I discovered android Preference API which easily enable to create setting for applications
- XML definition for wallpaper in xml folder.
- AndroidManifest.xml entry for the live-wallpaper and the preference activity.
Getting Started
1. For creating the Live wallpaper you must class which extends class WallpaperService
find more info about class at https://developer.android.com/reference/android/service/wallpaper/WallpaperService.html
This class must override method onCreateEngine()
method which return Engine
class object
Further this class must have a nested class which extends Engine
class. (I don’t know why)
To create the falling animation I need to draw the surface continuously. Earlier in the when using canvas view invalidate()
method was called to update the view. However in case of Engine
class there is no such method. To draw the effect first you need to get the canvas from the getSurfaceHolder();
After that a thread is runned at specific interval to update the draw surface.
Below is the skeleton
class from the live wallpaper.
package matrixlw.app.skd.wa;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;
import com.enrico.colorpicker.colorDialog;
import java.util.Random;
public class matrixWall extends WallpaperService {
private boolean mVisible;
Canvas canvas;
int Drawspeed=10;
Context mcontext;
@Override
public Engine onCreateEngine() {
mcontext = this;
return new LiveWall();
}
public class LiveWall extends Engine
{
final Handler mHandler = new Handler();
private final Runnable mDrawFrame = new Runnable() {
public void run() {
drawFrame();
}
};
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
drawFrame();
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawFrame);
}
@Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
drawFrame();
} else {
mHandler.removeCallbacks(mDrawFrame);
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawFrame);
}
public void drawFrame()
{
final SurfaceHolder holder = getSurfaceHolder();
canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
}
} finally {
if (canvas != null)
holder.unlockCanvasAndPost(canvas);
}
mHandler.removeCallbacks(mDrawFrame);
if (mVisible) {
mHandler.postDelayed(mDrawFrame, Drawspeed);
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
}
}
}
2. Creating xml definition.
As the for the wallpaper service a xml file must be created in xml folder like mywallpaper.xml
="1.0"="UTF-8"
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:thumbnail="@mipmap/ic_launcher"
android:settingsActivity="matrixlw.app.skd.wa.SettingsActivity"/>
here android:settingsActivity="matrixlw.app.skd.wa.SettingsActivity"/>
points to the settings activity which get called when setting button is clicked at the live wallpaper preview screen
3. Setting up the android AndroidManifest.xml to get the live wallpaper running this file must be set properly.
- Set the features
<uses-feature android:name="android.software.live_wallpaper" />
- Add the service for the wallpaper and the resource xml file.
<service
android:name=".matrixWall"
android:enabled="true"
android:label="MATRIX RAIN"
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/mywallpaper"></meta-data>
</service>
- Add the settings activity
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Here android:exported="true"
must be set else this activity will not open when clicking setting button
3. Creating the Setting activity
The Settings activity Contains the UI for customize the property of the live wallpaper. The preference activity is created using android preference API this provides a easy way to created the preference API
For more info refer to: https://developer.android.com/guide/topics/ui/settings.html
Color Picker is created using library by enricocid
Ref: https://github.com/enricocid/Color-picker-library
I am skipping about the setting activity. The files and layout for the setting activity is SettingsActivity.java and xml/preferences.
4. Putting together the Live wallpaper:
The matrix rain effect is going to be my live wallpaper which I have explained in my previous article.
ref - below is the draw code from that project
int background_color= Color.parseColor("#FF000000");
int text_color=Color.parseColor("#FF8BFF4A");
int width = 1000000;
int height = 100;
int fontSize = 15;
int columnSize = width/fontSize;
int parentWidth;
String text = "MATRIXRAIN";
char[] textChar = text.toCharArray();
int textLength = textChar.length;
Random rand = new Random();
int[] textPosition;
void drawText()
{
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(text_color);
paint.setTextSize(15);
for(int i =0 ;i<textPosition.length;i++)
{
canvas.drawText(""+textChar[rand.nextInt(textLength)+0],i*fontSize,textPosition[i]*fontSize,paint);
if(textPosition[i]*fontSize > height && Math.random() > 0.975)
textPosition[i] = 0;
textPosition[i]++;
}
}
public void canvasDraw()
{
Log.d("canvas ","drawing");
Paint paint = new Paint();
paint.setColor(background_color);
paint.setAlpha(5);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, width, height, paint);
drawText();
}
Now the above code is need to be inserted into the skeleton wallpaper Service code. In the skeleton class DrawFrame()
method is used to call the draw statements.
package matrixlw.app.skd.wa;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;
import com.enrico.colorpicker.colorDialog;
import java.util.Random;
public class matrixWall extends WallpaperService {
private boolean mVisible;
Canvas canvas;
int Drawspeed=10;
Context mcontext;
int background_color= Color.parseColor("#FF000000");
int text_color=Color.parseColor("#FF8BFF4A");
int width = 1000000;
int height = 100;
int fontSize = 15;
int columnSize = width/fontSize;
int parentWidth;
String text = "MATRIXRAIN";
char[] textChar = text.toCharArray();
int textLength = textChar.length;
Random rand = new Random();
int[] textPosition;
@Override
public Engine onCreateEngine() {
mcontext = this;
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
text = sharedPref.getString("matrix_scroll_text", "MATRIX");
Drawspeed = Integer.parseInt(sharedPref.getString("matrix_falling_speed","10"));
fontSize = Integer.parseInt(sharedPref.getString("matrix_font_size","15"));
background_color = colorDialog.getPickerColor(getBaseContext(), 1);
text_color =colorDialog.getPickerColor(getBaseContext(), 2);
Log.d("back_color",""+background_color);
Log.d("text_color",""+text_color);
textChar = text.toCharArray();
textLength = textChar.length;
columnSize = width/fontSize;
return new LiveWall();
}
public class LiveWall extends Engine
{
final Handler mHandler = new Handler();
private final Runnable mDrawFrame = new Runnable() {
public void run() {
background_color = colorDialog.getPickerColor(getBaseContext(), 1);
text_color =colorDialog.getPickerColor(getBaseContext(), 2);
drawFrame();
}
};
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
width = getDesiredMinimumWidth();
height = getDesiredMinimumHeight();
columnSize = width/fontSize;
textPosition = new int[columnSize+1];
for(int x = 0; x < columnSize; x++) {
textPosition[x] = 1;
}
drawFrame();
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawFrame);
}
@Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mcontext);
text = sharedPref.getString("matrix_scroll_text", "MATRIX");
Drawspeed = Integer.parseInt(sharedPref.getString("matrix_falling_speed","10"));
fontSize = Integer.parseInt(sharedPref.getString("matrix_font_size","15"));
background_color = colorDialog.getPickerColor(getBaseContext(), 1);
text_color =colorDialog.getPickerColor(getBaseContext(), 2);
textChar = text.toCharArray();
textLength = textChar.length;
columnSize = width/fontSize;
drawFrame();
} else {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mcontext);
text = sharedPref.getString("matrix_scroll_text", "MATRIX");
Drawspeed = Integer.parseInt(sharedPref.getString("matrix_falling_speed","10"));
fontSize = Integer.parseInt(sharedPref.getString("matrix_font_size","15"));
background_color = colorDialog.getPickerColor(getBaseContext(), 1);
text_color =colorDialog.getPickerColor(getBaseContext(), 2);
textChar = text.toCharArray();
textLength = textChar.length;
columnSize = width/fontSize;
mHandler.removeCallbacks(mDrawFrame);
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawFrame);
}
public void drawFrame()
{
final SurfaceHolder holder = getSurfaceHolder();
canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
canvasDraw();
}
} finally {
if (canvas != null)
holder.unlockCanvasAndPost(canvas);
}
mHandler.removeCallbacks(mDrawFrame);
if (mVisible) {
mHandler.postDelayed(mDrawFrame, Drawspeed);
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
Paint paint = new Paint();
paint.setColor(background_color);
paint.setAlpha(255);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, width, height, paint);
}
}
void drawText()
{
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(text_color);
paint.setTextSize(15);
for(int i =0 ;i<textPosition.length;i++)
{
canvas.drawText(""+textChar[rand.nextInt(textLength)+0],i*fontSize,textPosition[i]*fontSize,paint);
if(textPosition[i]*fontSize > height && Math.random() > 0.975)
textPosition[i] = 0;
textPosition[i]++;
}
}
public void canvasDraw()
{
Log.d("canvas ","drawing");
Paint paint = new Paint();
paint.setColor(background_color);
paint.setAlpha(5);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, width, height, paint);
drawText();
}
}
Here the below methods are used to set up the surface
public void onSurfaceCreated(SurfaceHolder holder)
public void onVisibilityChanged(boolean visible)
public void onSurfaceDestroyed(SurfaceHolder holder)
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)
Now you have complete working live wallpaper code.
Get the source form: https://github.com/sapandang/Matrix-Rain-Live-Wallpaper
Download the apk: Play Store