* Default built-in wallpaper that simply shows a static image.
*/
public class ImageWallpaper extends WallpaperService {
+ private static final String TAG = "ImageWallpaper";
+ private static final boolean DEBUG = false;
+
WallpaperManager mWallpaperManager;
private HandlerThread mThread;
float mXOffset;
float mYOffset;
+ boolean mVisible = true;
+ boolean mRedrawNeeded;
+ boolean mOffsetsChanged;
+ int mLastXTranslation;
+ int mLastYTranslation;
+
class WallpaperObserver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
- updateWallpaper();
- drawFrame();
+ synchronized (mLock) {
+ updateWallpaperLocked();
+ drawFrameLocked(true, false);
+ }
+
// Assume we are the only one using the wallpaper in this
// process, and force a GC now to release the old wallpaper.
System.gc();
IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
mReceiver = new WallpaperObserver();
registerReceiver(mReceiver, filter);
- updateWallpaper();
+
+ synchronized (mLock) {
+ updateWallpaperLocked();
+ }
surfaceHolder.setSizeFromLayout();
}
@Override
public void onVisibilityChanged(boolean visible) {
- drawFrame();
+ synchronized (mLock) {
+ mVisible = visible;
+ drawFrameLocked(false, false);
+ }
}
-
+
@Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep,
int xPixels, int yPixels) {
- mXOffset = xOffset;
- mYOffset = yOffset;
- drawFrame();
+ synchronized (mLock) {
+ if (mXOffset != xOffset || mYOffset != yOffset) {
+ if (DEBUG) {
+ Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ").");
+ }
+ mXOffset = xOffset;
+ mYOffset = yOffset;
+ drawFrameLocked(false, true);
+ } else {
+ drawFrameLocked(false, false);
+ }
+ }
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
- drawFrame();
+
+ synchronized (mLock) {
+ drawFrameLocked(true, false);
+ }
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
}
-
- void drawFrame() {
+
+ void drawFrameLocked(boolean redrawNeeded, boolean offsetsChanged) {
+ mRedrawNeeded |= redrawNeeded;
+ mOffsetsChanged |= offsetsChanged;
+
+ if (!mVisible) {
+ if (DEBUG) {
+ Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible.");
+ }
+ return;
+ }
+ if (!mRedrawNeeded && !mOffsetsChanged) {
+ if (DEBUG) {
+ Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
+ + "and offsets have not changed.");
+ }
+ return;
+ }
+
SurfaceHolder sh = getSurfaceHolder();
Canvas c = sh.lockCanvas();
if (c != null) {
- final Rect frame = sh.getSurfaceFrame();
- synchronized (mLock) {
+ try {
+ final Rect frame = sh.getSurfaceFrame();
final Drawable background = mBackground;
final int dw = frame.width();
final int dh = frame.height();
int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2);
int yPixels = availh < 0 ? (int)(availh*mYOffset+.5f) : (availh/2);
+ mOffsetsChanged = false;
+ if (!mRedrawNeeded) {
+ if (xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
+ if (DEBUG) {
+ Log.d(TAG, "Suppressed drawFrame since the image has not "
+ + "actually moved an integral number of pixels.");
+ }
+ return;
+ }
+ }
+ mRedrawNeeded = false;
+ mLastXTranslation = xPixels;
+ mLastYTranslation = yPixels;
+
c.translate(xPixels, yPixels);
- if (availw<0 || availh<0) {
+ if (availw < 0 || availh < 0) {
c.save(Canvas.CLIP_SAVE_FLAG);
c.clipRect(0, 0, bw, bh, Op.DIFFERENCE);
c.drawColor(0xff000000);
if (background != null) {
background.draw(c);
}
+ } finally {
+ sh.unlockCanvasAndPost(c);
}
- sh.unlockCanvasAndPost(c);
}
}
- void updateWallpaper() {
- synchronized (mLock) {
- Throwable exception = null;
+ void updateWallpaperLocked() {
+ Throwable exception = null;
+ try {
+ mBackground = mWallpaperManager.getFastDrawable();
+ } catch (RuntimeException e) {
+ exception = e;
+ } catch (OutOfMemoryError e) {
+ exception = e;
+ }
+ if (exception != null) {
+ mBackground = null;
+ // Note that if we do fail at this, and the default wallpaper can't
+ // be loaded, we will go into a cycle. Don't do a build where the
+ // default wallpaper can't be loaded.
+ Log.w(TAG, "Unable to load wallpaper!", exception);
try {
- mBackground = mWallpaperManager.getFastDrawable();
- } catch (RuntimeException e) {
- exception = e;
- } catch (OutOfMemoryError e) {
- exception = e;
- }
- if (exception != null) {
- mBackground = null;
- // Note that if we do fail at this, and the default wallpaper can't
- // be loaded, we will go into a cycle. Don't do a build where the
- // default wallpaper can't be loaded.
- Log.w("ImageWallpaper", "Unable to load wallpaper!", exception);
- try {
- mWallpaperManager.clear();
- } catch (IOException ex) {
- // now we're really screwed.
- Log.w("ImageWallpaper", "Unable reset to default wallpaper!", ex);
- }
+ mWallpaperManager.clear();
+ } catch (IOException ex) {
+ // now we're really screwed.
+ Log.w(TAG, "Unable reset to default wallpaper!", ex);
}
}
+ mRedrawNeeded = true;
}
}
}