WallpaperService.java revision 8df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bd
16034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty/* 26034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * Copyright (C) 2009 The Android Open Source Project 36034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * 46034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * Licensed under the Apache License, Version 2.0 (the "License"); 56034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * you may not use this file except in compliance with the License. 66034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * You may obtain a copy of the License at 76034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * 86034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * http://www.apache.org/licenses/LICENSE-2.0 96034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * 106034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * Unless required by applicable law or agreed to in writing, software 116034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * distributed under the License is distributed on an "AS IS" BASIS, 126034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * See the License for the specific language governing permissions and 146034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * limitations under the License. 156034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty */ 166034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 176034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertypackage android.service.wallpaper; 186034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 196034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport com.android.internal.os.HandlerCaller; 206034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport com.android.internal.view.BaseIWindow; 216034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport com.android.internal.view.BaseSurfaceHolder; 226034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 236034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.app.Service; 246034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.app.WallpaperManager; 256034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.content.Intent; 266034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.graphics.Rect; 276034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.os.IBinder; 286034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.os.Message; 296034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.os.RemoteException; 306034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.util.Log; 316034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.Gravity; 326034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.IWindowSession; 336034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.MotionEvent; 346034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.SurfaceHolder; 356034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.View; 366034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.ViewGroup; 376034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.ViewRoot; 386034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.WindowManager; 396034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.WindowManagerImpl; 406034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 416034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty/** 426034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * A wallpaper service is responsible for showing a live wallpaper behind 436034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * applications that would like to sit on top of it. 446034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * @hide Live Wallpaper 456034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty */ 466034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertypublic abstract class WallpaperService extends Service { 476034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty /** 486034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * The {@link Intent} that must be declared as handled by the service. 496034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty */ 506034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty public static final String SERVICE_INTERFACE = 516034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty "android.service.wallpaper.WallpaperService"; 526034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 536034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty static final String TAG = "WallpaperService"; 546034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty static final boolean DEBUG = false; 556034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 566034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int DO_ATTACH = 10; 576034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int DO_DETACH = 20; 586034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 596034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int MSG_UPDATE_SURFACE = 10000; 606034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int MSG_VISIBILITY_CHANGED = 10010; 616034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int MSG_WALLPAPER_OFFSETS = 10020; 626034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int MSG_WINDOW_RESIZED = 10030; 636034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty private static final int MSG_TOUCH_EVENT = 10040; 646034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 656034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty /** 666034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * The actual implementation of a wallpaper. A wallpaper service may 676034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * have multiple instances running (for example as a real wallpaper 686034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * and as a preview), each of which is represented by its own Engine 696034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * instance. You must implement {@link WallpaperService#onCreateEngine()} 706034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * to return your concrete Engine implementation. 716034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty */ 726034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty public class Engine { 736034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty IWallpaperEngineWrapper mIWallpaperEngine; 746034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 756034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty // Copies from mIWallpaperEngine. 766034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty HandlerCaller mCaller; 776034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty IWallpaperConnection mConnection; 786034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty IBinder mWindowToken; 796034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 806034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty boolean mInitializing = true; 816034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 826034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty // Current window state. 836034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty boolean mCreated; 846034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty boolean mIsCreating; 856034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty boolean mDrawingAllowed; 866034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mWidth; 876034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mHeight; 886034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mFormat; 896034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mType; 906034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mCurWidth; 916034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mCurHeight; 926034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 936034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty int mCurWindowFlags = mWindowFlags; 946034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty boolean mDestroyReportNeeded; 956034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty final Rect mVisibleInsets = new Rect(); 966034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty final Rect mWinFrame = new Rect(); 976034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty final Rect mContentInsets = new Rect(); 986034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 996034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty final WindowManager.LayoutParams mLayout 1006034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty = new WindowManager.LayoutParams(); 1016034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty IWindowSession mSession; 1026034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 1036034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty final Object mLock = new Object(); 1046034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty boolean mOffsetMessageEnqueued; 1056034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty float mPendingXOffset; 1066034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty float mPendingYOffset; 1076034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty MotionEvent mPendingMove; 1086034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 1096034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { 1106034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 1116034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty @Override 1126034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty public boolean onAllowLockCanvas() { 1136034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty return mDrawingAllowed; 1146034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty } 1156034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 1166034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty @Override 1176034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty public void onRelayoutContainer() { 1186034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 1196034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty mCaller.sendMessage(msg); 1206034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty } 1216034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty 1226034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty @Override 123 public void onUpdateSurface() { 124 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 125 mCaller.sendMessage(msg); 126 } 127 128 public boolean isCreating() { 129 return mIsCreating; 130 } 131 132 public void setKeepScreenOn(boolean screenOn) { 133 // Ignore. 134 } 135 136 }; 137 138 final BaseIWindow mWindow = new BaseIWindow() { 139 @Override 140 public boolean onDispatchPointer(MotionEvent event, long eventTime, 141 boolean callWhenDone) { 142 synchronized (mLock) { 143 if (event.getAction() == MotionEvent.ACTION_MOVE) { 144 if (mPendingMove != null) { 145 mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove); 146 mPendingMove.recycle(); 147 } 148 mPendingMove = event; 149 } else { 150 mPendingMove = null; 151 } 152 Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, 153 event); 154 mCaller.sendMessage(msg); 155 } 156 return false; 157 } 158 159 @Override 160 public void resized(int w, int h, Rect coveredInsets, 161 Rect visibleInsets, boolean reportDraw) { 162 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED, 163 reportDraw ? 1 : 0); 164 mCaller.sendMessage(msg); 165 } 166 167 @Override 168 public void dispatchAppVisibility(boolean visible) { 169 Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED, 170 visible ? 1 : 0); 171 mCaller.sendMessage(msg); 172 } 173 174 @Override 175 public void dispatchWallpaperOffsets(float x, float y) { 176 synchronized (mLock) { 177 mPendingXOffset = x; 178 mPendingYOffset = y; 179 if (!mOffsetMessageEnqueued) { 180 mOffsetMessageEnqueued = true; 181 Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS); 182 mCaller.sendMessage(msg); 183 } 184 } 185 } 186 187 }; 188 189 /** 190 * Provides access to the surface in which this wallpaper is drawn. 191 */ 192 public SurfaceHolder getSurfaceHolder() { 193 return mSurfaceHolder; 194 } 195 196 /** 197 * Convenience for {@link WallpaperManager#getDesiredMinimumWidth() 198 * WallpaperManager.getDesiredMinimumWidth()}, returning the width 199 * that the system would like this wallpaper to run in. 200 */ 201 public int getDesiredMinimumWidth() { 202 return mIWallpaperEngine.mReqWidth; 203 } 204 205 /** 206 * Convenience for {@link WallpaperManager#getDesiredMinimumHeight() 207 * WallpaperManager.getDesiredMinimumHeight()}, returning the height 208 * that the system would like this wallpaper to run in. 209 */ 210 public int getDesiredMinimumHeight() { 211 return mIWallpaperEngine.mReqHeight; 212 } 213 214 /** 215 * Control whether this wallpaper will receive raw touch events 216 * from the window manager as the user interacts with the window 217 * that is currently displaying the wallpaper. By default they 218 * are turned off. If enabled, the events will be received in 219 * {@link #onTouchEvent(MotionEvent)}. 220 */ 221 public void setTouchEventsEnabled(boolean enabled) { 222 mWindowFlags = enabled 223 ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) 224 : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); 225 if (mCreated) { 226 updateSurface(false); 227 } 228 } 229 230 /** 231 * Called once to initialize the engine. After returning, the 232 * engine's surface will be created by the framework. 233 */ 234 public void onCreate(SurfaceHolder surfaceHolder) { 235 } 236 237 /** 238 * Called right before the engine is going away. After this the 239 * surface will be destroyed and this Engine object is no longer 240 * valid. 241 */ 242 public void onDestroy() { 243 } 244 245 /** 246 * Called to inform you of the wallpaper becoming visible or 247 * hidden. <em>It is very important that a wallpaper only use 248 * CPU while it is visible.</em>. 249 */ 250 public void onVisibilityChanged(boolean visible) { 251 } 252 253 /** 254 * Called as the user performs touch-screen interaction with the 255 * window that is currently showing this wallpaper. Note that the 256 * events you receive here are driven by the actual application the 257 * user is interacting with, so if it is slow you will get viewer 258 * move events. 259 */ 260 public void onTouchEvent(MotionEvent event) { 261 } 262 263 /** 264 * Called to inform you of the wallpaper's offsets changing 265 * within its contain, corresponding to the container's 266 * call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float) 267 * WallpaperManager.setWallpaperOffsets()}. 268 */ 269 public void onOffsetsChanged(float xOffset, float yOffset, 270 int xPixelOffset, int yPixelOffset) { 271 } 272 273 /** 274 * Convenience for {@link SurfaceHolder.Callback#surfaceChanged 275 * SurfaceHolder.Callback.surfaceChanged()}. 276 */ 277 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 278 } 279 280 /** 281 * Convenience for {@link SurfaceHolder.Callback#surfaceCreated 282 * SurfaceHolder.Callback.surfaceCreated()}. 283 */ 284 public void onSurfaceCreated(SurfaceHolder holder) { 285 } 286 287 /** 288 * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed 289 * SurfaceHolder.Callback.surfaceDestroyed()}. 290 */ 291 public void onSurfaceDestroyed(SurfaceHolder holder) { 292 } 293 294 void updateSurface(boolean force) { 295 int myWidth = mSurfaceHolder.getRequestedWidth(); 296 if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT; 297 int myHeight = mSurfaceHolder.getRequestedHeight(); 298 if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.FILL_PARENT; 299 300 final boolean creating = !mCreated; 301 final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat(); 302 boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; 303 final boolean typeChanged = mType != mSurfaceHolder.getRequestedType(); 304 final boolean flagsChanged = mCurWindowFlags != mWindowFlags; 305 if (force || creating || formatChanged || sizeChanged || typeChanged 306 || flagsChanged) { 307 308 if (DEBUG) Log.i(TAG, "Changes: creating=" + creating 309 + " format=" + formatChanged + " size=" + sizeChanged); 310 311 try { 312 mWidth = myWidth; 313 mHeight = myHeight; 314 mFormat = mSurfaceHolder.getRequestedFormat(); 315 mType = mSurfaceHolder.getRequestedType(); 316 317 mLayout.x = 0; 318 mLayout.y = 0; 319 mLayout.width = myWidth; 320 mLayout.height = myHeight; 321 322 mLayout.format = mFormat; 323 324 mCurWindowFlags = mWindowFlags; 325 mLayout.flags = mWindowFlags 326 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 327 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 328 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 329 ; 330 331 mLayout.memoryType = mType; 332 mLayout.token = mWindowToken; 333 334 if (!mCreated) { 335 mLayout.type = WindowManager.LayoutParams.TYPE_WALLPAPER; 336 mLayout.gravity = Gravity.LEFT|Gravity.TOP; 337 mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets); 338 } 339 340 mSurfaceHolder.mSurfaceLock.lock(); 341 mDrawingAllowed = true; 342 343 final int relayoutResult = mSession.relayout( 344 mWindow, mLayout, mWidth, mHeight, 345 View.VISIBLE, false, mWinFrame, mContentInsets, 346 mVisibleInsets, mSurfaceHolder.mSurface); 347 348 if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface 349 + ", frame=" + mWinFrame); 350 351 int w = mWinFrame.width(); 352 if (mCurWidth != w) { 353 sizeChanged = true; 354 mCurWidth = w; 355 } 356 int h = mWinFrame.height(); 357 if (mCurHeight != h) { 358 sizeChanged = true; 359 mCurHeight = h; 360 } 361 362 mSurfaceHolder.mSurfaceLock.unlock(); 363 364 try { 365 mDestroyReportNeeded = true; 366 367 SurfaceHolder.Callback callbacks[] = null; 368 synchronized (mSurfaceHolder.mCallbacks) { 369 final int N = mSurfaceHolder.mCallbacks.size(); 370 if (N > 0) { 371 callbacks = new SurfaceHolder.Callback[N]; 372 mSurfaceHolder.mCallbacks.toArray(callbacks); 373 } 374 } 375 376 if (!mCreated) { 377 mIsCreating = true; 378 onSurfaceCreated(mSurfaceHolder); 379 if (callbacks != null) { 380 for (SurfaceHolder.Callback c : callbacks) { 381 c.surfaceCreated(mSurfaceHolder); 382 } 383 } 384 } 385 if (force || creating || formatChanged || sizeChanged) { 386 onSurfaceChanged(mSurfaceHolder, mFormat, 387 mCurWidth, mCurHeight); 388 if (callbacks != null) { 389 for (SurfaceHolder.Callback c : callbacks) { 390 c.surfaceChanged(mSurfaceHolder, mFormat, 391 mCurWidth, mCurHeight); 392 } 393 } 394 } 395 } finally { 396 mIsCreating = false; 397 mCreated = true; 398 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { 399 mSession.finishDrawing(mWindow); 400 } 401 } 402 } catch (RemoteException ex) { 403 } 404 if (DEBUG) Log.v( 405 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + 406 " w=" + mLayout.width + " h=" + mLayout.height); 407 } 408 } 409 410 void attach(IWallpaperEngineWrapper wrapper) { 411 mIWallpaperEngine = wrapper; 412 mCaller = wrapper.mCaller; 413 mConnection = wrapper.mConnection; 414 mWindowToken = wrapper.mWindowToken; 415 // XXX temp -- should run in size from layout (screen) mode. 416 mSurfaceHolder.setFixedSize(mIWallpaperEngine.mReqWidth, 417 mIWallpaperEngine.mReqHeight); 418 //mSurfaceHolder.setSizeFromLayout(); 419 mInitializing = true; 420 mSession = ViewRoot.getWindowSession(getMainLooper()); 421 mWindow.setSession(mSession); 422 423 onCreate(mSurfaceHolder); 424 425 mInitializing = false; 426 updateSurface(false); 427 } 428 429 void detach() { 430 onDestroy(); 431 if (mDestroyReportNeeded) { 432 mDestroyReportNeeded = false; 433 SurfaceHolder.Callback callbacks[]; 434 synchronized (mSurfaceHolder.mCallbacks) { 435 callbacks = new SurfaceHolder.Callback[ 436 mSurfaceHolder.mCallbacks.size()]; 437 mSurfaceHolder.mCallbacks.toArray(callbacks); 438 } 439 for (SurfaceHolder.Callback c : callbacks) { 440 c.surfaceDestroyed(mSurfaceHolder); 441 } 442 } 443 if (mCreated) { 444 try { 445 mSession.remove(mWindow); 446 } catch (RemoteException e) { 447 } 448 mSurfaceHolder.mSurface.clear(); 449 mCreated = false; 450 } 451 } 452 } 453 454 class IWallpaperEngineWrapper extends IWallpaperEngine.Stub 455 implements HandlerCaller.Callback { 456 private final HandlerCaller mCaller; 457 458 final IWallpaperConnection mConnection; 459 final IBinder mWindowToken; 460 int mReqWidth; 461 int mReqHeight; 462 463 Engine mEngine; 464 465 IWallpaperEngineWrapper(WallpaperService context, 466 IWallpaperConnection conn, IBinder windowToken, 467 int reqWidth, int reqHeight) { 468 mCaller = new HandlerCaller(context, this); 469 mConnection = conn; 470 mWindowToken = windowToken; 471 mReqWidth = reqWidth; 472 mReqHeight = reqHeight; 473 474 try { 475 conn.attachEngine(this); 476 } catch (RemoteException e) { 477 destroy(); 478 } 479 480 Message msg = mCaller.obtainMessage(DO_ATTACH); 481 mCaller.sendMessage(msg); 482 } 483 484 public void destroy() { 485 Message msg = mCaller.obtainMessage(DO_DETACH); 486 mCaller.sendMessage(msg); 487 } 488 489 public void executeMessage(Message message) { 490 switch (message.what) { 491 case DO_ATTACH: { 492 Engine engine = onCreateEngine(); 493 mEngine = engine; 494 engine.attach(this); 495 return; 496 } 497 case DO_DETACH: { 498 mEngine.detach(); 499 return; 500 } 501 case MSG_UPDATE_SURFACE: 502 mEngine.updateSurface(false); 503 break; 504 case MSG_VISIBILITY_CHANGED: 505 if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine 506 + ": " + message.arg1); 507 mEngine.onVisibilityChanged(message.arg1 != 0); 508 break; 509 case MSG_WALLPAPER_OFFSETS: { 510 float xOffset; 511 float yOffset; 512 synchronized (mEngine.mLock) { 513 xOffset = mEngine.mPendingXOffset; 514 yOffset = mEngine.mPendingYOffset; 515 mEngine.mOffsetMessageEnqueued = false; 516 } 517 if (DEBUG) Log.v(TAG, "Offsets change in " + mEngine 518 + ": " + xOffset + "," + yOffset); 519 final int availw = mReqWidth-mEngine.mCurWidth; 520 final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0; 521 final int availh = mReqHeight-mEngine.mCurHeight; 522 final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0; 523 mEngine.onOffsetsChanged(xOffset, yOffset, xPixels, yPixels); 524 } break; 525 case MSG_WINDOW_RESIZED: { 526 final boolean reportDraw = message.arg1 != 0; 527 mEngine.updateSurface(true); 528 if (reportDraw) { 529 try { 530 mEngine.mSession.finishDrawing(mEngine.mWindow); 531 } catch (RemoteException e) { 532 } 533 } 534 } break; 535 case MSG_TOUCH_EVENT: { 536 MotionEvent ev = (MotionEvent)message.obj; 537 synchronized (mEngine.mLock) { 538 if (mEngine.mPendingMove == ev) { 539 mEngine.mPendingMove = null; 540 } 541 } 542 mEngine.onTouchEvent(ev); 543 ev.recycle(); 544 } break; 545 default : 546 Log.w(TAG, "Unknown message type " + message.what); 547 } 548 } 549 } 550 551 /** 552 * Implements the internal {@link IWallpaperService} interface to convert 553 * incoming calls to it back to calls on an {@link WallpaperService}. 554 */ 555 class IWallpaperServiceWrapper extends IWallpaperService.Stub { 556 private final WallpaperService mTarget; 557 558 public IWallpaperServiceWrapper(WallpaperService context) { 559 mTarget = context; 560 } 561 562 public void attach(IWallpaperConnection conn, 563 IBinder windowToken, int reqWidth, int reqHeight) { 564 new IWallpaperEngineWrapper( 565 mTarget, conn, windowToken, reqWidth, reqHeight); 566 } 567 } 568 569 /** 570 * Implement to return the implementation of the internal accessibility 571 * service interface. Subclasses should not override. 572 */ 573 @Override 574 public final IBinder onBind(Intent intent) { 575 return new IWallpaperServiceWrapper(this); 576 } 577 578 public abstract Engine onCreateEngine(); 579} 580