I was working on my first ever android project, which is a live wallpaper, and I managed to get ti work through tutorials, examples, and even codes found in here, but I still have an issue that is keeping from finishing it. I want my live wallpaper using images to parallax scroll when he user switches home screens.
Here is my code::
package com.livewallpaper.mw3lwp;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.WindowManager;
public class ModernWarfare3LiveWallpaper extends WallpaperService {
private final Handler mHandler = new Handler();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public Engine onCreateEngine() {
return new CubeEngine();
}
class CubeEngine extends Engine {
private final Paint mPaint = new Paint();
private float mPosY;
private float mPosX;
//private float mPosYBackup;
private boolean mAnime = true;
private Matrix mMatrix = new Matrix();
public int bgcycle = 0;
public Bitmap myBg;
public int idx = 0;
private float mPixels;
private final Runnable mDrawAnim = new Runnable() {
public void run() {
drawFrame();
}
};
private boolean mVisible;
private static final int NUM_RES = 50;
//private final Bitmap[] mPics = new Bitmap[NUM_RES];
public int getScreenOrientation() {
Display screen= ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int orientation = getResources().getConfiguration().orientation;
// UNDEFINED
if(orientation==Configuration.ORIENTATION_UNDEFINED){
//Configuration config = getResources().getConfiguration();
if(orientation==Configuration.ORIENTATION_UNDEFINED){
//if height and widht of screen are equal then
// it is square orientation
if(screen.getWidth()==screen.getHeight()){
orientation = Configuration.ORIENTATION_SQUARE;
}else{ //if widht is less than height than it is portrait
if(screen.getWidth() < screen.getHeight()){
orientation = Configuration.ORIENTATION_PORTRAIT;
}else{ // if it is not any of the above it will defineitly be landscape
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
}
}
//
// Query what the orientation currently really is.
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
// The following message is only displayed once.
return orientation/*= 1*/; // Portrait Mode
}else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
// The following message is only displayed once.
return orientation/*= 2*/; // Landscape mode
}
return orientation;
}
public void updateBG() {
idx += 1;
if (idx == NUM_RES) {idx = 0;}
Resources res = getResources();
int id = res.getIdentifier("n" + (idx + 1), "drawable", "com.livewallpaper.mw3lwp");
myBg = BitmapFactory.decodeResource(res, id);
}
CubeEngine() {
Resources res = getResources();
//for (int i = 0; i< NUM_RES; i++) {
int id = res.getIdentifier("n" + (idx + 1), "drawable", "com.livewallpaper.mw3lwp");
myBg = BitmapFactory.decodeResource(res, id);
// if (i==NUM_RES) i=0;
// }
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
setTouchEventsEnabled(false);
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawAnim);
}
@Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
drawFrame();
} else {
mHandler.removeCallbacks(mDrawAnim);
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//if landscape
if (getScreenOrientation() == 2){
super.onSurfaceChanged(holder, format, width, height);
float w = myBg.getWidth();
float h = myBg.getHeight();
float s = width / (float)w;
mMatrix.reset();
mMatrix.setScale(s, s);
mPosY = (height - (h * s)) / 2f;
//mPixels= 0;
//mPosYBackup= mPosY;
drawFrame();
}
//
//if portrait
else {
super.onSurfaceChanged(holder, format, width, height);
float w = myBg.getWidth();
float h = myBg.getHeight();
float s = height / (float)h;
mMatrix.reset();
mMatrix.setScale(s, s);
//mMatrix.postScale(s, s, 0, 0);
// mPosY = 0f;
mPosX= (width - (w * s)) / 2f;
drawFrame();
}
//
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawAnim);
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xStep, float yStep, int xPixels, int yPixels) {
// Agregado recien
//if landscape
if (getScreenOrientation() == 2){
super.onOffsetsChanged(xOffset, yOffset, xStep, yStep, xPixels, yPixels);
//mPosY= mPosYBackup;
drawFrame();
}
//if portrait
else{
super.onOffsetsChanged(xOffset, yOffset, xStep, yStep, xPixels, yPixels);
mPixels = xPixels;
//mPosY=0f;
drawFrame();
}
// Fin Agregado
}
@Override
public void onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
mAnime = !mAnime;
}
super.onTouchEvent(event);
}
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// draw something
drawAnim(c);
//drawTouchPoint(c);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawAnim);
if (mVisible && mAnime) {
mHandler.postDelayed(mDrawAnim, 0);
}
}
void drawAnim(Canvas c) {
// if portrait
if(getScreenOrientation() == 1){
c.save();
//if (this.isPreview()) {
//c.translate(/*(float)*/mPosX, 0f);
//}
// MY PROBLEM HEREEEEE!!!! IM NOT USING BOTH
c.translate(/*(float)*/mPosX, 0f);
c.translate((float)mPixels, 0f);
updateBG();
c.drawBitmap(myBg, mMatrix, mPaint);
//c.drawBitmap(myBg, 0, 0, mPaint);
if (mAnime) ++idx;
if (idx == NUM_RES) idx = 0;
c.restore();
}
//end if portrait
// if landscape
if(getScreenOrientation() == 2){
c.save();
c.translate(0, mPosY);
updateBG();
c.drawBitmap(myBg, mMatrix, mPaint);
if (mAnime) ++idx;
if (idx == NUM_RES) idx = 0;
c.restore();
}
// end if landscape
//c.drawBitmap(mPics[idx], mMatrix, mPaint);
}
}
}
}
I pointed where I believe the error is with a “MY PROBLEM IS HEREEEE!!!” in the code. Thing is on the canvas.translate();
If I use c.translate(mPosX, 0f); mPosX gotten from onSurfacedChanged, the center part of the images in the wallpaper are showed, the way I want, but it won’t scroll through the whole background.
If I use c.translate((float)mPixels, 0f); where mPixels is gotten from onOffSetChanged, it only shows the left part/zone of the wallpaper.
ANd finally if I change mPosX name to mPixels, c.translate((float)mPixels, 0f); gets the value from both, onSurfacedChanged and from onOffSetChanged. It does not work on the first execution. You can see the wallpaper centered first and then back to only showing the left part of the wallpaper. If I run it a second time on eclipse and set it again on my phone, then it would work how i want, the center part of the image on the middle home screen, and scrolling the background as switching home screens. But the thing is it does not work at first execution, which leads to not working when exported as the apk.
So can anybody help me to get my live wallpaper images shown centered and scrolling when switching home screens please. Thank you in advance.
Well, I still do not know why sometimes the xPixelOffset value (xPixel on my code) from onOffsetChanged is returning 0, but I managed to get an alternative solution for devices where this anomality may occur.
If this is happening to someone else I realized that the xPixelOffset can also be obtained by getting the device screen width and multiply it time the xOffset from onOffsetChanged. Width can be obtained and stored in a new variable from OnSurfaceChanged, where the device screen width and height can be obtained.
EX:
Where mPixels should be getting the value from xPixelOffset (xPixel on my code), and screenWidth is obtained from OnSurfaceChanged through: