ImageWallpaper.java revision ba39839444532af0ed3766f736582413f6d7a40b
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.systemui; 18 19import java.io.IOException; 20 21import android.app.WallpaperManager; 22import android.graphics.Canvas; 23import android.graphics.Rect; 24import android.graphics.Region.Op; 25import android.graphics.drawable.Drawable; 26import android.os.Handler; 27import android.service.wallpaper.WallpaperService; 28import android.util.Log; 29import android.util.Slog; 30import android.view.MotionEvent; 31import android.view.SurfaceHolder; 32import android.content.Context; 33import android.content.IntentFilter; 34import android.content.Intent; 35import android.content.BroadcastReceiver; 36 37/** 38 * Default built-in wallpaper that simply shows a static image. 39 */ 40public class ImageWallpaper extends WallpaperService { 41 private static final String TAG = "ImageWallpaper"; 42 private static final boolean DEBUG = false; 43 44 static final boolean FIXED_SIZED_SURFACE = true; 45 46 WallpaperManager mWallpaperManager; 47 private Handler mHandler; 48 49 @Override 50 public void onCreate() { 51 super.onCreate(); 52 mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE); 53 mHandler = new Handler(); 54 } 55 56 public Engine onCreateEngine() { 57 return new DrawableEngine(); 58 } 59 60 class DrawableEngine extends Engine { 61 private final Object mLock = new Object(); 62 private WallpaperObserver mReceiver; 63 Drawable mBackground; 64 int mBackgroundWidth = -1, mBackgroundHeight = -1; 65 float mXOffset; 66 float mYOffset; 67 68 boolean mVisible = true; 69 boolean mRedrawNeeded; 70 boolean mOffsetsChanged; 71 int mLastXTranslation; 72 int mLastYTranslation; 73 74 class WallpaperObserver extends BroadcastReceiver { 75 public void onReceive(Context context, Intent intent) { 76 if (DEBUG) { 77 Log.d(TAG, "onReceive"); 78 } 79 80 synchronized (mLock) { 81 mBackgroundWidth = mBackgroundHeight = -1; 82 mBackground = null; 83 mRedrawNeeded = true; 84 drawFrameLocked(); 85 } 86 } 87 } 88 89 @Override 90 public void onCreate(SurfaceHolder surfaceHolder) { 91 if (DEBUG) { 92 Log.d(TAG, "onCreate"); 93 } 94 95 super.onCreate(surfaceHolder); 96 IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); 97 mReceiver = new WallpaperObserver(); 98 registerReceiver(mReceiver, filter, null, mHandler); 99 100 updateSurfaceSize(surfaceHolder); 101 } 102 103 @Override 104 public void onDestroy() { 105 super.onDestroy(); 106 unregisterReceiver(mReceiver); 107 } 108 109 @Override 110 public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { 111 super.onDesiredSizeChanged(desiredWidth, desiredHeight); 112 SurfaceHolder surfaceHolder = getSurfaceHolder(); 113 if (surfaceHolder != null) { 114 updateSurfaceSize(surfaceHolder); 115 } 116 } 117 118 void updateSurfaceSize(SurfaceHolder surfaceHolder) { 119 if (FIXED_SIZED_SURFACE) { 120 // Used a fixed size surface, because we are special. We can do 121 // this because we know the current design of window animations doesn't 122 // cause this to break. 123 surfaceHolder.setFixedSize(getDesiredMinimumWidth(), getDesiredMinimumHeight()); 124 } else { 125 surfaceHolder.setSizeFromLayout(); 126 } 127 } 128 129 @Override 130 public void onVisibilityChanged(boolean visible) { 131 if (DEBUG) { 132 Log.d(TAG, "onVisibilityChanged: visible=" + visible); 133 } 134 135 synchronized (mLock) { 136 if (mVisible != visible) { 137 if (DEBUG) { 138 Log.d(TAG, "Visibility changed to visible=" + visible); 139 } 140 mVisible = visible; 141 drawFrameLocked(); 142 } 143 } 144 } 145 146 @Override 147 public void onTouchEvent(MotionEvent event) { 148 super.onTouchEvent(event); 149 } 150 151 @Override 152 public void onOffsetsChanged(float xOffset, float yOffset, 153 float xOffsetStep, float yOffsetStep, 154 int xPixels, int yPixels) { 155 if (DEBUG) { 156 Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset 157 + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep 158 + ", xPixels=" + xPixels + ", yPixels=" + yPixels); 159 } 160 161 synchronized (mLock) { 162 if (mXOffset != xOffset || mYOffset != yOffset) { 163 if (DEBUG) { 164 Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ")."); 165 } 166 mXOffset = xOffset; 167 mYOffset = yOffset; 168 mOffsetsChanged = true; 169 } 170 drawFrameLocked(); 171 } 172 } 173 174 @Override 175 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 176 if (DEBUG) { 177 Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height); 178 } 179 180 super.onSurfaceChanged(holder, format, width, height); 181 182 synchronized (mLock) { 183 mRedrawNeeded = true; 184 drawFrameLocked(); 185 } 186 } 187 188 void drawFrameLocked() { 189 if (!mVisible) { 190 if (DEBUG) { 191 Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible."); 192 } 193 return; 194 } 195 if (!mRedrawNeeded && !mOffsetsChanged) { 196 if (DEBUG) { 197 Log.d(TAG, "Suppressed drawFrame since redraw is not needed " 198 + "and offsets have not changed."); 199 } 200 return; 201 } 202 203 if (mBackgroundWidth < 0 || mBackgroundHeight < 0) { 204 // If we don't yet know the size of the wallpaper bitmap, 205 // we need to get it now. 206 updateWallpaperLocked(); 207 } 208 209 SurfaceHolder sh = getSurfaceHolder(); 210 final Rect frame = sh.getSurfaceFrame(); 211 final int dw = frame.width(); 212 final int dh = frame.height(); 213 final int availw = dw - mBackgroundWidth; 214 final int availh = dh - mBackgroundHeight; 215 int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2); 216 int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2); 217 218 mOffsetsChanged = false; 219 if (!mRedrawNeeded 220 && xPixels == mLastXTranslation && yPixels == mLastYTranslation) { 221 if (DEBUG) { 222 Log.d(TAG, "Suppressed drawFrame since the image has not " 223 + "actually moved an integral number of pixels."); 224 } 225 return; 226 } 227 mRedrawNeeded = false; 228 mLastXTranslation = xPixels; 229 mLastYTranslation = yPixels; 230 231 if (mBackground == null) { 232 // If we somehow got to this point after we have last flushed 233 // the wallpaper, well we really need it to draw again. So 234 // seems like we need to reload it. Ouch. 235 updateWallpaperLocked(); 236 } 237 238 //Slog.i(TAG, "************** DRAWING WALLAPER ******************"); 239 Canvas c = sh.lockCanvas(); 240 if (c != null) { 241 try { 242 if (DEBUG) { 243 Log.d(TAG, "Redrawing: xPixels=" + xPixels + ", yPixels=" + yPixels); 244 } 245 246 c.translate(xPixels, yPixels); 247 if (availw < 0 || availh < 0) { 248 c.save(Canvas.CLIP_SAVE_FLAG); 249 c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE); 250 c.drawColor(0xff000000); 251 c.restore(); 252 } 253 if (mBackground != null) { 254 mBackground.draw(c); 255 } 256 } finally { 257 sh.unlockCanvasAndPost(c); 258 } 259 } 260 261 if (FIXED_SIZED_SURFACE) { 262 // If the surface is fixed-size, we should only need to 263 // draw it once and then we'll let the window manager 264 // position it appropriately. As such, we no longer needed 265 // the loaded bitmap. Yay! 266 mBackground = null; 267 mWallpaperManager.forgetLoadedWallpaper(); 268 } 269 } 270 271 void updateWallpaperLocked() { 272 //Slog.i(TAG, "************** LOADING WALLAPER ******************"); 273 Throwable exception = null; 274 try { 275 mBackground = mWallpaperManager.getFastDrawable(); 276 } catch (RuntimeException e) { 277 exception = e; 278 } catch (OutOfMemoryError e) { 279 exception = e; 280 } 281 if (exception != null) { 282 mBackground = null; 283 // Note that if we do fail at this, and the default wallpaper can't 284 // be loaded, we will go into a cycle. Don't do a build where the 285 // default wallpaper can't be loaded. 286 Log.w(TAG, "Unable to load wallpaper!", exception); 287 try { 288 mWallpaperManager.clear(); 289 } catch (IOException ex) { 290 // now we're really screwed. 291 Log.w(TAG, "Unable reset to default wallpaper!", ex); 292 } 293 } 294 mBackgroundWidth = mBackground != null ? mBackground.getIntrinsicWidth() : 0; 295 mBackgroundHeight = mBackground != null ? mBackground.getIntrinsicHeight() : 0; 296 } 297 } 298} 299