I recently posted a question about screen rotation in my live wallpaper. To test why I was having these problems, I created the simple program below:
package com.live.waller;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class LiveWallpaperService extends WallpaperService {
/** Called when the activity is first created. */
@Override
public Engine onCreateEngine() {
// TODO Auto-generated method stub
return new LiveWallerEngine();
}
class LiveWallerEngine extends Engine {
SurfaceHolder holder;
private Handler mHandle;
LiveWallerEngine() {
mHandle = new Handler();
holder = getSurfaceHolder();
}
private Runnable runner = new Runnable() {
public void run() {
// TODO Auto-generated method stub
drawFrame();
}
};
public void drawFrame() {
while(isVisible()) {
if(!holder.getSurface().isValid())
continue;
Canvas c = null;
try{
c = holder.lockCanvas();
drawSurface(c);
} finally {
if(c != null) holder.unlockCanvasAndPost(c);
}
}
}
public void drawSurface(Canvas c) {
c.save();
c.drawColor(Color.argb(255, 100, 200, 124));
c.restore();
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
// TODO Auto-generated method stub
super.onCreate(surfaceHolder);
setTouchEventsEnabled(true);
mHandle.post(runner);
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep, int xPixelOffset,
int yPixelOffset) {
// TODO Auto-generated method stub
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,
xPixelOffset, yPixelOffset);
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
super.onSurfaceChanged(holder, format, width, height);
mHandle.post(runner);
}
@Override
public void onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
super.onTouchEvent(event);
}
@Override
public void onVisibilityChanged(boolean visible) {
// TODO Auto-generated method stub
super.onVisibilityChanged(visible);
}
@Override
public void setTouchEventsEnabled(boolean enabled) {
// TODO Auto-generated method stub
super.setTouchEventsEnabled(enabled);
}
}
}
And when I rotate my wallpaper, I am greeted with a blank screen. Does anyone know what is wrong with my code?
When I run the wallpaper, I get these errors in logcat:
ActivityManager: force stopping package com.live.waller uid=10046
PackageManager: Not granting permission android.permission.BIND_WALLPAPER to package com.live.waller (protectionLevel=3 flags=0xbe46)
dalvikvm: GC_CONCURRENT freed 609K, 43% free 4604K/8071K, external 904K/1222K, paused 6ms+7ms
dalvikvm: GC_EXPLICIT freed 320K, 44% free 4561K/8071K, external 904K/1222K, paused 138ms
dalvikvm: GC_EXTERNAL_ALLOC freed 197K, 51% free 2955K/6023K, external 1736K/1742K, paused 78ms
What’s strange is that I get a force stop message in logcat but not on the emulator when I set my wallpaper.
Your drawFrame()-method will be stuck in an infinite loop, as long as isVisible() returns true. There is no need for a while-statement to loop through the locking and posting of your freshly painted Canvas, when you got a Runnable with a Handler.
A better implementation of drawFrame() can be found in the Cube Live Wallpaper example in the SDK.
Now, we use Engine.onVisibilityChanged() to decide whether or not the wallpaper is visible.
If the Surface we paint to somehow gets destroyed (Ex.: If the user sets a new background), we also want to remove any pending posts. So in Engine.onSurfaceDestroyed(), we do
Regarding the force close issue:
What API-level are your trying to run the Wallpaper on?