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