WallpaperService.java revision bcbcaa7edd32ba67c6290d79f7e7821c4b5b39ac
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 android.service.wallpaper; 18 19import com.android.internal.os.HandlerCaller; 20import com.android.internal.view.BaseIWindow; 21import com.android.internal.view.BaseSurfaceHolder; 22 23import android.app.Service; 24import android.app.WallpaperManager; 25import android.content.BroadcastReceiver; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.graphics.Rect; 30import android.os.IBinder; 31import android.os.Message; 32import android.os.RemoteException; 33import android.util.Log; 34import android.view.Gravity; 35import android.view.IWindowSession; 36import android.view.MotionEvent; 37import android.view.SurfaceHolder; 38import android.view.View; 39import android.view.ViewGroup; 40import android.view.ViewRoot; 41import android.view.WindowManager; 42import android.view.WindowManagerImpl; 43 44/** 45 * A wallpaper service is responsible for showing a live wallpaper behind 46 * applications that would like to sit on top of it. 47 * @hide Live Wallpaper 48 */ 49public abstract class WallpaperService extends Service { 50 /** 51 * The {@link Intent} that must be declared as handled by the service. 52 */ 53 public static final String SERVICE_INTERFACE = 54 "android.service.wallpaper.WallpaperService"; 55 56 /** 57 * Name under which a WallpaperService component publishes information 58 * about itself. This meta-data must reference an XML resource containing 59 * a <code><{@link android.R.styleable#Wallpaper wallpaper}></code> 60 * tag. 61 */ 62 public static final String SERVICE_META_DATA = "android.service.wallpaper"; 63 64 static final String TAG = "WallpaperService"; 65 static final boolean DEBUG = false; 66 67 private static final int DO_ATTACH = 10; 68 private static final int DO_DETACH = 20; 69 private static final int DO_SET_DESIRED_SIZE = 30; 70 71 private static final int MSG_UPDATE_SURFACE = 10000; 72 private static final int MSG_VISIBILITY_CHANGED = 10010; 73 private static final int MSG_WALLPAPER_OFFSETS = 10020; 74 private static final int MSG_WINDOW_RESIZED = 10030; 75 private static final int MSG_TOUCH_EVENT = 10040; 76 77 /** 78 * The actual implementation of a wallpaper. A wallpaper service may 79 * have multiple instances running (for example as a real wallpaper 80 * and as a preview), each of which is represented by its own Engine 81 * instance. You must implement {@link WallpaperService#onCreateEngine()} 82 * to return your concrete Engine implementation. 83 */ 84 public class Engine { 85 IWallpaperEngineWrapper mIWallpaperEngine; 86 87 // Copies from mIWallpaperEngine. 88 HandlerCaller mCaller; 89 IWallpaperConnection mConnection; 90 IBinder mWindowToken; 91 92 boolean mInitializing = true; 93 boolean mVisible; 94 boolean mScreenOn = true; 95 boolean mReportedVisible; 96 boolean mDestroyed; 97 98 // Current window state. 99 boolean mCreated; 100 boolean mIsCreating; 101 boolean mDrawingAllowed; 102 int mWidth; 103 int mHeight; 104 int mFormat; 105 int mType; 106 int mCurWidth; 107 int mCurHeight; 108 int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 109 int mCurWindowFlags = mWindowFlags; 110 boolean mDestroyReportNeeded; 111 final Rect mVisibleInsets = new Rect(); 112 final Rect mWinFrame = new Rect(); 113 final Rect mContentInsets = new Rect(); 114 115 final WindowManager.LayoutParams mLayout 116 = new WindowManager.LayoutParams(); 117 IWindowSession mSession; 118 119 final Object mLock = new Object(); 120 boolean mOffsetMessageEnqueued; 121 float mPendingXOffset; 122 float mPendingYOffset; 123 MotionEvent mPendingMove; 124 125 final BroadcastReceiver mReceiver = new BroadcastReceiver() { 126 @Override 127 public void onReceive(Context context, Intent intent) { 128 if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { 129 mScreenOn = true; 130 reportVisibility(); 131 } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { 132 mScreenOn = false; 133 reportVisibility(); 134 } 135 } 136 }; 137 138 final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { 139 140 @Override 141 public boolean onAllowLockCanvas() { 142 return mDrawingAllowed; 143 } 144 145 @Override 146 public void onRelayoutContainer() { 147 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 148 mCaller.sendMessage(msg); 149 } 150 151 @Override 152 public void onUpdateSurface() { 153 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 154 mCaller.sendMessage(msg); 155 } 156 157 public boolean isCreating() { 158 return mIsCreating; 159 } 160 161 @Override 162 public void setFixedSize(int width, int height) { 163 throw new UnsupportedOperationException( 164 "Wallpapers currently only support sizing from layout"); 165 } 166 167 public void setKeepScreenOn(boolean screenOn) { 168 throw new UnsupportedOperationException( 169 "Wallpapers do not support keep screen on"); 170 } 171 172 }; 173 174 final BaseIWindow mWindow = new BaseIWindow() { 175 @Override 176 public boolean onDispatchPointer(MotionEvent event, long eventTime, 177 boolean callWhenDone) { 178 synchronized (mLock) { 179 if (event.getAction() == MotionEvent.ACTION_MOVE) { 180 if (mPendingMove != null) { 181 mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove); 182 mPendingMove.recycle(); 183 } 184 mPendingMove = event; 185 } else { 186 mPendingMove = null; 187 } 188 Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, 189 event); 190 mCaller.sendMessage(msg); 191 } 192 return false; 193 } 194 195 @Override 196 public void resized(int w, int h, Rect coveredInsets, 197 Rect visibleInsets, boolean reportDraw) { 198 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED, 199 reportDraw ? 1 : 0); 200 mCaller.sendMessage(msg); 201 } 202 203 @Override 204 public void dispatchAppVisibility(boolean visible) { 205 // We don't do this in preview mode; we'll let the preview 206 // activity tell us when to run. 207 if (!mIWallpaperEngine.mIsPreview) { 208 Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED, 209 visible ? 1 : 0); 210 mCaller.sendMessage(msg); 211 } 212 } 213 214 @Override 215 public void dispatchWallpaperOffsets(float x, float y) { 216 synchronized (mLock) { 217 mPendingXOffset = x; 218 mPendingYOffset = y; 219 if (!mOffsetMessageEnqueued) { 220 mOffsetMessageEnqueued = true; 221 Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS); 222 mCaller.sendMessage(msg); 223 } 224 } 225 } 226 227 }; 228 229 /** 230 * Provides access to the surface in which this wallpaper is drawn. 231 */ 232 public SurfaceHolder getSurfaceHolder() { 233 return mSurfaceHolder; 234 } 235 236 /** 237 * Convenience for {@link WallpaperManager#getDesiredMinimumWidth() 238 * WallpaperManager.getDesiredMinimumWidth()}, returning the width 239 * that the system would like this wallpaper to run in. 240 */ 241 public int getDesiredMinimumWidth() { 242 return mIWallpaperEngine.mReqWidth; 243 } 244 245 /** 246 * Convenience for {@link WallpaperManager#getDesiredMinimumHeight() 247 * WallpaperManager.getDesiredMinimumHeight()}, returning the height 248 * that the system would like this wallpaper to run in. 249 */ 250 public int getDesiredMinimumHeight() { 251 return mIWallpaperEngine.mReqHeight; 252 } 253 254 /** 255 * Return whether the wallpaper is currently visible to the user, 256 * this is the last value supplied to 257 * {@link #onVisibilityChanged(boolean)}. 258 */ 259 public boolean isVisible() { 260 return mReportedVisible; 261 } 262 263 /** 264 * Returns true if this engine is running in preview mode -- that is, 265 * it is being shown to the user before they select it as the actual 266 * wallpaper. 267 */ 268 public boolean isPreview() { 269 return mIWallpaperEngine.mIsPreview; 270 } 271 272 /** 273 * Control whether this wallpaper will receive raw touch events 274 * from the window manager as the user interacts with the window 275 * that is currently displaying the wallpaper. By default they 276 * are turned off. If enabled, the events will be received in 277 * {@link #onTouchEvent(MotionEvent)}. 278 */ 279 public void setTouchEventsEnabled(boolean enabled) { 280 mWindowFlags = enabled 281 ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) 282 : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); 283 if (mCreated) { 284 updateSurface(false, false); 285 } 286 } 287 288 /** 289 * Called once to initialize the engine. After returning, the 290 * engine's surface will be created by the framework. 291 */ 292 public void onCreate(SurfaceHolder surfaceHolder) { 293 } 294 295 /** 296 * Called right before the engine is going away. After this the 297 * surface will be destroyed and this Engine object is no longer 298 * valid. 299 */ 300 public void onDestroy() { 301 } 302 303 /** 304 * Called to inform you of the wallpaper becoming visible or 305 * hidden. <em>It is very important that a wallpaper only use 306 * CPU while it is visible.</em>. 307 */ 308 public void onVisibilityChanged(boolean visible) { 309 } 310 311 /** 312 * Called as the user performs touch-screen interaction with the 313 * window that is currently showing this wallpaper. Note that the 314 * events you receive here are driven by the actual application the 315 * user is interacting with, so if it is slow you will get viewer 316 * move events. 317 */ 318 public void onTouchEvent(MotionEvent event) { 319 } 320 321 /** 322 * Called to inform you of the wallpaper's offsets changing 323 * within its contain, corresponding to the container's 324 * call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float) 325 * WallpaperManager.setWallpaperOffsets()}. 326 */ 327 public void onOffsetsChanged(float xOffset, float yOffset, 328 int xPixelOffset, int yPixelOffset) { 329 } 330 331 /** 332 * Called when an application has changed the desired virtual size of 333 * the wallpaper. 334 */ 335 public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { 336 } 337 338 /** 339 * Convenience for {@link SurfaceHolder.Callback#surfaceChanged 340 * SurfaceHolder.Callback.surfaceChanged()}. 341 */ 342 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 343 } 344 345 /** 346 * Convenience for {@link SurfaceHolder.Callback#surfaceCreated 347 * SurfaceHolder.Callback.surfaceCreated()}. 348 */ 349 public void onSurfaceCreated(SurfaceHolder holder) { 350 } 351 352 /** 353 * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed 354 * SurfaceHolder.Callback.surfaceDestroyed()}. 355 */ 356 public void onSurfaceDestroyed(SurfaceHolder holder) { 357 } 358 359 void updateSurface(boolean forceRelayout, boolean forceReport) { 360 if (mDestroyed) { 361 Log.w(TAG, "Ignoring updateSurface: destroyed"); 362 } 363 364 int myWidth = mSurfaceHolder.getRequestedWidth(); 365 if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT; 366 int myHeight = mSurfaceHolder.getRequestedHeight(); 367 if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.FILL_PARENT; 368 369 final boolean creating = !mCreated; 370 final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat(); 371 boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; 372 final boolean typeChanged = mType != mSurfaceHolder.getRequestedType(); 373 final boolean flagsChanged = mCurWindowFlags != mWindowFlags; 374 if (forceRelayout || creating || formatChanged || sizeChanged 375 || typeChanged || flagsChanged) { 376 377 if (DEBUG) Log.v(TAG, "Changes: creating=" + creating 378 + " format=" + formatChanged + " size=" + sizeChanged); 379 380 try { 381 mWidth = myWidth; 382 mHeight = myHeight; 383 mFormat = mSurfaceHolder.getRequestedFormat(); 384 mType = mSurfaceHolder.getRequestedType(); 385 386 mLayout.x = 0; 387 mLayout.y = 0; 388 mLayout.width = myWidth; 389 mLayout.height = myHeight; 390 391 mLayout.format = mFormat; 392 393 mCurWindowFlags = mWindowFlags; 394 mLayout.flags = mWindowFlags 395 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 396 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 397 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 398 ; 399 400 mLayout.memoryType = mType; 401 mLayout.token = mWindowToken; 402 403 if (!mCreated) { 404 mLayout.type = mIWallpaperEngine.mWindowType; 405 mLayout.gravity = Gravity.LEFT|Gravity.TOP; 406 mLayout.setTitle(WallpaperService.this.getClass().getName()); 407 mLayout.windowAnimations = 408 com.android.internal.R.style.Animation_Wallpaper; 409 mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets); 410 } 411 412 mSurfaceHolder.mSurfaceLock.lock(); 413 mDrawingAllowed = true; 414 415 final int relayoutResult = mSession.relayout( 416 mWindow, mLayout, mWidth, mHeight, 417 View.VISIBLE, false, mWinFrame, mContentInsets, 418 mVisibleInsets, mSurfaceHolder.mSurface); 419 420 if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface 421 + ", frame=" + mWinFrame); 422 423 int w = mWinFrame.width(); 424 if (mCurWidth != w) { 425 sizeChanged = true; 426 mCurWidth = w; 427 } 428 int h = mWinFrame.height(); 429 if (mCurHeight != h) { 430 sizeChanged = true; 431 mCurHeight = h; 432 } 433 434 mSurfaceHolder.mSurfaceLock.unlock(); 435 436 try { 437 mDestroyReportNeeded = true; 438 439 SurfaceHolder.Callback callbacks[] = null; 440 synchronized (mSurfaceHolder.mCallbacks) { 441 final int N = mSurfaceHolder.mCallbacks.size(); 442 if (N > 0) { 443 callbacks = new SurfaceHolder.Callback[N]; 444 mSurfaceHolder.mCallbacks.toArray(callbacks); 445 } 446 } 447 448 if (!mCreated) { 449 mIsCreating = true; 450 if (DEBUG) Log.v(TAG, "onSurfaceCreated(" 451 + mSurfaceHolder + "): " + this); 452 onSurfaceCreated(mSurfaceHolder); 453 if (callbacks != null) { 454 for (SurfaceHolder.Callback c : callbacks) { 455 c.surfaceCreated(mSurfaceHolder); 456 } 457 } 458 } 459 if (forceReport || creating || formatChanged || sizeChanged) { 460 if (DEBUG) { 461 RuntimeException e = new RuntimeException(); 462 e.fillInStackTrace(); 463 Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating 464 + " formatChanged=" + formatChanged 465 + " sizeChanged=" + sizeChanged, e); 466 } 467 if (DEBUG) Log.v(TAG, "onSurfaceChanged(" 468 + mSurfaceHolder + ", " + mFormat 469 + ", " + mCurWidth + ", " + mCurHeight 470 + "): " + this); 471 onSurfaceChanged(mSurfaceHolder, mFormat, 472 mCurWidth, mCurHeight); 473 if (callbacks != null) { 474 for (SurfaceHolder.Callback c : callbacks) { 475 c.surfaceChanged(mSurfaceHolder, mFormat, 476 mCurWidth, mCurHeight); 477 } 478 } 479 } 480 } finally { 481 mIsCreating = false; 482 mCreated = true; 483 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { 484 mSession.finishDrawing(mWindow); 485 } 486 } 487 } catch (RemoteException ex) { 488 } 489 if (DEBUG) Log.v( 490 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + 491 " w=" + mLayout.width + " h=" + mLayout.height); 492 } 493 } 494 495 void attach(IWallpaperEngineWrapper wrapper) { 496 if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper); 497 if (mDestroyed) { 498 return; 499 } 500 501 mIWallpaperEngine = wrapper; 502 mCaller = wrapper.mCaller; 503 mConnection = wrapper.mConnection; 504 mWindowToken = wrapper.mWindowToken; 505 mSurfaceHolder.setSizeFromLayout(); 506 mInitializing = true; 507 mSession = ViewRoot.getWindowSession(getMainLooper()); 508 mWindow.setSession(mSession); 509 510 IntentFilter filter = new IntentFilter(); 511 filter.addAction(Intent.ACTION_SCREEN_ON); 512 filter.addAction(Intent.ACTION_SCREEN_OFF); 513 registerReceiver(mReceiver, filter); 514 515 if (DEBUG) Log.v(TAG, "onCreate(): " + this); 516 onCreate(mSurfaceHolder); 517 518 mInitializing = false; 519 updateSurface(false, false); 520 } 521 522 void doDesiredSizeChanged(int desiredWidth, int desiredHeight) { 523 if (!mDestroyed) { 524 if (DEBUG) Log.v(TAG, "onDesiredSizeChanged(" 525 + desiredWidth + "," + desiredHeight + "): " + this); 526 onDesiredSizeChanged(desiredWidth, desiredHeight); 527 } 528 } 529 530 void doVisibilityChanged(boolean visible) { 531 mVisible = visible; 532 reportVisibility(); 533 } 534 535 void reportVisibility() { 536 if (!mDestroyed) { 537 boolean visible = mVisible && mScreenOn; 538 if (mReportedVisible != visible) { 539 mReportedVisible = visible; 540 if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible 541 + "): " + this); 542 onVisibilityChanged(visible); 543 } 544 } 545 } 546 547 void doOffsetsChanged() { 548 if (mDestroyed) { 549 return; 550 } 551 552 float xOffset; 553 float yOffset; 554 synchronized (mLock) { 555 xOffset = mPendingXOffset; 556 yOffset = mPendingYOffset; 557 mOffsetMessageEnqueued = false; 558 } 559 if (DEBUG) Log.v(TAG, "Offsets change in " + this 560 + ": " + xOffset + "," + yOffset); 561 final int availw = mIWallpaperEngine.mReqWidth-mCurWidth; 562 final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0; 563 final int availh = mIWallpaperEngine.mReqHeight-mCurHeight; 564 final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0; 565 onOffsetsChanged(xOffset, yOffset, xPixels, yPixels); 566 } 567 568 void detach() { 569 mDestroyed = true; 570 571 if (mVisible) { 572 mVisible = false; 573 if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this); 574 onVisibilityChanged(false); 575 } 576 577 if (mDestroyReportNeeded) { 578 mDestroyReportNeeded = false; 579 SurfaceHolder.Callback callbacks[]; 580 synchronized (mSurfaceHolder.mCallbacks) { 581 callbacks = new SurfaceHolder.Callback[ 582 mSurfaceHolder.mCallbacks.size()]; 583 mSurfaceHolder.mCallbacks.toArray(callbacks); 584 } 585 for (SurfaceHolder.Callback c : callbacks) { 586 c.surfaceDestroyed(mSurfaceHolder); 587 } 588 if (DEBUG) Log.v(TAG, "onSurfaceDestroyed(" 589 + mSurfaceHolder + "): " + this); 590 onSurfaceDestroyed(mSurfaceHolder); 591 } 592 593 if (DEBUG) Log.v(TAG, "onDestroy(): " + this); 594 onDestroy(); 595 596 unregisterReceiver(mReceiver); 597 598 if (mCreated) { 599 try { 600 mSession.remove(mWindow); 601 } catch (RemoteException e) { 602 } 603 mSurfaceHolder.mSurface.release(); 604 mCreated = false; 605 } 606 } 607 } 608 609 class IWallpaperEngineWrapper extends IWallpaperEngine.Stub 610 implements HandlerCaller.Callback { 611 private final HandlerCaller mCaller; 612 613 final IWallpaperConnection mConnection; 614 final IBinder mWindowToken; 615 final int mWindowType; 616 final boolean mIsPreview; 617 int mReqWidth; 618 int mReqHeight; 619 620 Engine mEngine; 621 622 IWallpaperEngineWrapper(WallpaperService context, 623 IWallpaperConnection conn, IBinder windowToken, 624 int windowType, boolean isPreview, int reqWidth, int reqHeight) { 625 mCaller = new HandlerCaller(context, this); 626 mConnection = conn; 627 mWindowToken = windowToken; 628 mWindowType = windowType; 629 mIsPreview = isPreview; 630 mReqWidth = reqWidth; 631 mReqHeight = reqHeight; 632 633 Message msg = mCaller.obtainMessage(DO_ATTACH); 634 mCaller.sendMessage(msg); 635 } 636 637 public void setDesiredSize(int width, int height) { 638 Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height); 639 mCaller.sendMessage(msg); 640 } 641 642 public void setVisibility(boolean visible) { 643 Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED, 644 visible ? 1 : 0); 645 mCaller.sendMessage(msg); 646 } 647 648 public void destroy() { 649 Message msg = mCaller.obtainMessage(DO_DETACH); 650 mCaller.sendMessage(msg); 651 } 652 653 public void executeMessage(Message message) { 654 switch (message.what) { 655 case DO_ATTACH: { 656 try { 657 mConnection.attachEngine(this); 658 } catch (RemoteException e) { 659 Log.w(TAG, "Wallpaper host disappeared", e); 660 return; 661 } 662 Engine engine = onCreateEngine(); 663 mEngine = engine; 664 engine.attach(this); 665 return; 666 } 667 case DO_DETACH: { 668 mEngine.detach(); 669 return; 670 } 671 case DO_SET_DESIRED_SIZE: { 672 mEngine.doDesiredSizeChanged(message.arg1, message.arg2); 673 return; 674 } 675 case MSG_UPDATE_SURFACE: 676 mEngine.updateSurface(true, false); 677 break; 678 case MSG_VISIBILITY_CHANGED: 679 if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine 680 + ": " + message.arg1); 681 mEngine.doVisibilityChanged(message.arg1 != 0); 682 break; 683 case MSG_WALLPAPER_OFFSETS: { 684 mEngine.doOffsetsChanged(); 685 } break; 686 case MSG_WINDOW_RESIZED: { 687 final boolean reportDraw = message.arg1 != 0; 688 mEngine.updateSurface(true, false); 689 if (reportDraw) { 690 try { 691 mEngine.mSession.finishDrawing(mEngine.mWindow); 692 } catch (RemoteException e) { 693 } 694 } 695 } break; 696 case MSG_TOUCH_EVENT: { 697 MotionEvent ev = (MotionEvent)message.obj; 698 synchronized (mEngine.mLock) { 699 if (mEngine.mPendingMove == ev) { 700 mEngine.mPendingMove = null; 701 } 702 } 703 mEngine.onTouchEvent(ev); 704 ev.recycle(); 705 } break; 706 default : 707 Log.w(TAG, "Unknown message type " + message.what); 708 } 709 } 710 } 711 712 /** 713 * Implements the internal {@link IWallpaperService} interface to convert 714 * incoming calls to it back to calls on an {@link WallpaperService}. 715 */ 716 class IWallpaperServiceWrapper extends IWallpaperService.Stub { 717 private final WallpaperService mTarget; 718 719 public IWallpaperServiceWrapper(WallpaperService context) { 720 mTarget = context; 721 } 722 723 public void attach(IWallpaperConnection conn, IBinder windowToken, 724 int windowType, boolean isPreview, int reqWidth, int reqHeight) { 725 new IWallpaperEngineWrapper(mTarget, conn, windowToken, 726 windowType, isPreview, reqWidth, reqHeight); 727 } 728 } 729 730 /** 731 * Implement to return the implementation of the internal accessibility 732 * service interface. Subclasses should not override. 733 */ 734 @Override 735 public final IBinder onBind(Intent intent) { 736 return new IWallpaperServiceWrapper(this); 737 } 738 739 public abstract Engine onCreateEngine(); 740} 741