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