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