Hi, at last I was able to create my own live wallpaper " MATRIX RAIN ".
Download : click here
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,
1. A class which extends WallpaperService and further implements a nested class which extends Engine class.This Class is responsible for calling the draw code.
2. 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
3. XML definition for wallpaper in xml folder.
4. 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
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 ref : 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.xml4. 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
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.
Here the below methods are used to set up the surface
Now you have complete working live wallpaper code.
Get the source form :
https://github.com/sapandang/Matrix-Rain-Live-Wallpaper
download the apk:
https://github.com/sapandang/Matrix-Rain-Live-Wallpaper/blob/master/app/build/outputs/apk/app-debug.apk
Download : click here
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,
1. A class which extends WallpaperService and further implements a nested class which extends Engine class.This Class is responsible for calling the draw code.
2. 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
3. XML definition for wallpaper in xml folder.
4. 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
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; /** * Created by sapan on 1/10/2017. */ public class matrixWall extends WallpaperService { private boolean mVisible; // visible flag Canvas canvas; // canvas reference int Drawspeed=10; // thread call delay time Context mcontext; //reference to the current context @Override public Engine onCreateEngine() { //set the Preference default value mcontext = this; //set the current context //return the Engine Class return new LiveWall(); // this calls contain the wallpaper code } /* * this class extends the engine for the live wallpaper * THis class implements all the draw calls required to draw the wallpaper * This call is to neseted inside the wallpaper service class to function properly * don't know why though :( */ public class LiveWall extends Engine { final Handler mHandler = new Handler(); // this is to handle the thread //the tread responsibe for drawing this thread get calls every time // drawspeed vars set the execution speed private final Runnable mDrawFrame = new Runnable() { public void run() { // This method get called each time to drwaw thw frame // Engine class does not provide any invlidate methods // as used in canvas // set your draw call here drawFrame(); } }; //Called when the surface is created @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); //call the draw method // this is where you must call your draw code drawFrame(); } // remove thread @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mDrawFrame); } //called when varaible changed @Override public void onVisibilityChanged(boolean visible) { mVisible = visible; if (visible) { //call the drawFunction drawFrame(); } else { //this is necessay to remove the call back mHandler.removeCallbacks(mDrawFrame); } } //called when surface destroyed @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); mVisible = false; //this is necessay to remove the call back mHandler.removeCallbacks(mDrawFrame); } // my function which contain the code to draw //this function contain the the main draw call /// this function need to call every time the code is executed // the thread call this functioin with some delay "drawspeed" public void drawFrame() { //getting the surface holder final SurfaceHolder holder = getSurfaceHolder(); canvas = null; // canvas try { canvas = holder.lockCanvas(); //get the canvas if (canvas != null) { // draw something // my draw code } } finally { if (canvas != null) holder.unlockCanvasAndPost(canvas); } // Reschedule the next redraw // this is the replacement for the invilidate funtion // every time call the drawFrame to draw the matrix mHandler.removeCallbacks(mDrawFrame); if (mVisible) { // set the execution delay mHandler.postDelayed(mDrawFrame, Drawspeed); } } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.onSurfaceChanged(holder, format, width, height); // update when surface changed } } } |
2. Creating xml definition.
As the for the wallpaper service a xml file must be created in xml folder like mywallpaper.xml
1 2 3 4 5 6 |
<?xml version="1.0" encoding="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.
a. Set the features
1 <uses-feature android:name="android.software.live_wallpaper" />
b. Add the service for the wallpaper and the resource xml file.
1 2 3 4 5 6 7 8 9 10 11 12 13 <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>
c. Add the settings activity
1 2 3 4 5 6 7 8 9 10 11 <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 button3. 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 ref : 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.xml4. 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
// ======== MATRIX LIVE WALLPAPER VARS int background_color= Color.parseColor("#FF000000"); int text_color=Color.parseColor("#FF8BFF4A"); int width = 1000000; //default initial width int height = 100; //default initial height int fontSize = 15; //font size of the text which will fall int columnSize = width/fontSize; //column size ; no of digit required to fill the screen int parentWidth; String text = "MATRIXRAIN"; // Text which need to be drawn char[] textChar = text.toCharArray(); // split the character of the text int textLength = textChar.length; //length of the length text Random rand = new Random(); //random generater int[] textPosition; // contain the position which will help to draw the text //====================== //old matrix effect code void drawText() { //Set up the paint Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(text_color); paint.setTextSize(15); //loop and paint for(int i =0 ;i<textPosition.length;i++) { // draw the text at the random position canvas.drawText(""+textChar[rand.nextInt(textLength)+0],i*fontSize,textPosition[i]*fontSize,paint); // check if text has reached bottom or not if(textPosition[i]*fontSize > height && Math.random() > 0.975) textPosition[i] = 0; // change text position to zero when 0 when text is at the bottom textPosition[i]++; //increment the position array } } //old martix effect code public void canvasDraw() { Log.d("canvas ","drawing"); //set the paint for the canvas Paint paint = new Paint(); paint.setColor(background_color); paint.setAlpha(5); paint.setStyle(Paint.Style.FILL); canvas.drawRect(0, 0, width, height, paint);//draw rect to clear the canvas drawText(); // draw the canvas } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
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; /** * Created by sapan on 1/10/2017. */ public class matrixWall extends WallpaperService { private boolean mVisible; // visible flag Canvas canvas; // canvas reference int Drawspeed=10; // thread call delay time Context mcontext; //reference to the current context // ======== MATRIX LIVE WALLPAPER VARS int background_color= Color.parseColor("#FF000000"); int text_color=Color.parseColor("#FF8BFF4A"); int width = 1000000; //default initial width int height = 100; //default initial height int fontSize = 15; //font size of the text which will fall int columnSize = width/fontSize; //column size ; no of digit required to fill the screen int parentWidth; String text = "MATRIXRAIN"; // Text which need to be drawn char[] textChar = text.toCharArray(); // split the character of the text int textLength = textChar.length; //length of the length text Random rand = new Random(); //random generater int[] textPosition; // contain the position which will help to draw the text //====================== @Override public Engine onCreateEngine() { //set the Preference default value mcontext = this; //set the current context //Initalise and read the preference 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); //Some loggers Commnet or remove if you want Log.d("back_color",""+background_color); Log.d("text_color",""+text_color); textChar = text.toCharArray(); // split the character of the text textLength = textChar.length; columnSize = width/fontSize; //return the Engine Class return new LiveWall(); // this calls contain the wallpaper code } /* * this class extends the engine for the live wallpaper * THis class implements all the draw calls required to draw the wallpaper * This call is to neseted inside the wallpaper service class to function properly * don't know why though :( */ public class LiveWall extends Engine { final Handler mHandler = new Handler(); // this is to handle the thread //the tread responsibe for drawing this thread get calls every time // drawspeed vars set the execution speed private final Runnable mDrawFrame = new Runnable() { public void run() { //Matrix code to the color when changed // callback can also be used but I havent background_color = colorDialog.getPickerColor(getBaseContext(), 1); text_color =colorDialog.getPickerColor(getBaseContext(), 2); // ^^^^^^^^ // This method get called each time to drwaw thw frame // Engine class does not provide any invlidate methods // as used in canvas // set your draw call here drawFrame(); } }; //Called when the surface is created @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); //update the matrix variables width = getDesiredMinimumWidth(); height = getDesiredMinimumHeight(); columnSize = width/fontSize; //initalise the textposiotn to zero textPosition = new int[columnSize+1]; //add one more drop for(int x = 0; x < columnSize; x++) { textPosition[x] = 1; } //^^^^^^^^^^^^^^^ //call the draw method // this is where you must call your draw code drawFrame(); } // remove thread @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mDrawFrame); } //called when varaible changed @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(); // split the character of the text 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(); // split the character of the text textLength = textChar.length; columnSize = width/fontSize; //this is necessay to remove the call back mHandler.removeCallbacks(mDrawFrame); } } //called when surface destroyed @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); mVisible = false; //this is necessay to remove the call back mHandler.removeCallbacks(mDrawFrame); } //this function contain the the main draw call /// this function need to call every time the code is executed // the thread call this functioin with some delay "drawspeed" public void drawFrame() { //getting the surface holder final SurfaceHolder holder = getSurfaceHolder(); canvas = null; // canvas try { canvas = holder.lockCanvas(); //get the canvas if (canvas != null) { // draw something // canvas matrix draw code canvasDraw(); //^^^^ } } finally { if (canvas != null) holder.unlockCanvasAndPost(canvas); } // Reschedule the next redraw // this is the replacement for the invilidate funtion // every time call the drawFrame to draw the matrix mHandler.removeCallbacks(mDrawFrame); if (mVisible) { // set the execution delay mHandler.postDelayed(mDrawFrame, Drawspeed); } } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.onSurfaceChanged(holder, format, width, height); // some matrix variable // though not needed Paint paint = new Paint(); paint.setColor(background_color); paint.setAlpha(255); //set the alpha paint.setStyle(Paint.Style.FILL); canvas.drawRect(0, 0, width, height, paint); } } //old matrix effect code void drawText() { //Set up the paint Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(text_color); paint.setTextSize(15); //loop and paint for(int i =0 ;i<textPosition.length;i++) { // draw the text at the random position canvas.drawText(""+textChar[rand.nextInt(textLength)+0],i*fontSize,textPosition[i]*fontSize,paint); // check if text has reached bottom or not if(textPosition[i]*fontSize > height && Math.random() > 0.975) textPosition[i] = 0; // change text position to zero when 0 when text is at the bottom textPosition[i]++; //increment the position array } } //old martix effect code public void canvasDraw() { Log.d("canvas ","drawing"); //set the paint for the canvas Paint paint = new Paint(); paint.setColor(background_color); paint.setAlpha(5); paint.setStyle(Paint.Style.FILL); canvas.drawRect(0, 0, width, height, paint);//draw rect to clear the canvas drawText(); // draw the canvas } } |
Here the below methods are used to set up the surface
1 2 3 4 |
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:
https://github.com/sapandang/Matrix-Rain-Live-Wallpaper/blob/master/app/build/outputs/apk/app-debug.apk
Nice tutorial, thanks for it. Very helpful
ReplyDeleteThanks for the live wallpaper tutorial.
ReplyDeleteNice post. I like this yugen manga website
ReplyDelete