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 17 package android.service.wallpaper; 18 19 import android.content.res.TypedArray; 20 import android.graphics.Canvas; 21 import android.util.MergedConfiguration; 22 import android.view.WindowInsets; 23 24 import com.android.internal.R; 25 import com.android.internal.os.HandlerCaller; 26 import com.android.internal.view.BaseIWindow; 27 import com.android.internal.view.BaseSurfaceHolder; 28 29 import android.annotation.SdkConstant; 30 import android.annotation.SdkConstant.SdkConstantType; 31 import android.app.Service; 32 import android.app.WallpaperManager; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.graphics.PixelFormat; 36 import android.graphics.Rect; 37 import android.hardware.display.DisplayManager; 38 import android.hardware.display.DisplayManager.DisplayListener; 39 import android.os.Bundle; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.Message; 43 import android.os.RemoteException; 44 import android.util.Log; 45 import android.view.Display; 46 import android.view.Gravity; 47 import android.view.IWindowSession; 48 import android.view.InputChannel; 49 import android.view.InputDevice; 50 import android.view.InputEvent; 51 import android.view.InputEventReceiver; 52 import android.view.MotionEvent; 53 import android.view.SurfaceHolder; 54 import android.view.View; 55 import android.view.ViewGroup; 56 import android.view.WindowManager; 57 import android.view.WindowManagerGlobal; 58 59 import java.io.FileDescriptor; 60 import java.io.PrintWriter; 61 import java.util.ArrayList; 62 63 /** 64 * A wallpaper service is responsible for showing a live wallpaper behind 65 * applications that would like to sit on top of it. This service object 66 * itself does very little -- its only purpose is to generate instances of 67 * {@link Engine} as needed. Implementing a wallpaper thus 68 * involves subclassing from this, subclassing an Engine implementation, 69 * and implementing {@link #onCreateEngine()} to return a new instance of 70 * your engine. 71 */ 72 public abstract class WallpaperService extends Service { 73 /** 74 * The {@link Intent} that must be declared as handled by the service. 75 * To be supported, the service must also require the 76 * {@link android.Manifest.permission#BIND_WALLPAPER} permission so 77 * that other applications can not abuse it. 78 */ 79 @SdkConstant(SdkConstantType.SERVICE_ACTION) 80 public static final String SERVICE_INTERFACE = 81 "android.service.wallpaper.WallpaperService"; 82 83 /** 84 * Name under which a WallpaperService component publishes information 85 * about itself. This meta-data must reference an XML resource containing 86 * a <code><{@link android.R.styleable#Wallpaper wallpaper}></code> 87 * tag. 88 */ 89 public static final String SERVICE_META_DATA = "android.service.wallpaper"; 90 91 static final String TAG = "WallpaperService"; 92 static final boolean DEBUG = false; 93 94 private static final int DO_ATTACH = 10; 95 private static final int DO_DETACH = 20; 96 private static final int DO_SET_DESIRED_SIZE = 30; 97 private static final int DO_SET_DISPLAY_PADDING = 40; 98 99 private static final int MSG_UPDATE_SURFACE = 10000; 100 private static final int MSG_VISIBILITY_CHANGED = 10010; 101 private static final int MSG_WALLPAPER_OFFSETS = 10020; 102 private static final int MSG_WALLPAPER_COMMAND = 10025; 103 private static final int MSG_WINDOW_RESIZED = 10030; 104 private static final int MSG_WINDOW_MOVED = 10035; 105 private static final int MSG_TOUCH_EVENT = 10040; 106 107 private final ArrayList<Engine> mActiveEngines 108 = new ArrayList<Engine>(); 109 110 static final class WallpaperCommand { 111 String action; 112 int x; 113 int y; 114 int z; 115 Bundle extras; 116 boolean sync; 117 } 118 119 /** 120 * The actual implementation of a wallpaper. A wallpaper service may 121 * have multiple instances running (for example as a real wallpaper 122 * and as a preview), each of which is represented by its own Engine 123 * instance. You must implement {@link WallpaperService#onCreateEngine()} 124 * to return your concrete Engine implementation. 125 */ 126 public class Engine { 127 IWallpaperEngineWrapper mIWallpaperEngine; 128 129 // Copies from mIWallpaperEngine. 130 HandlerCaller mCaller; 131 IWallpaperConnection mConnection; 132 IBinder mWindowToken; 133 134 boolean mInitializing = true; 135 boolean mVisible; 136 boolean mReportedVisible; 137 boolean mDestroyed; 138 139 // Current window state. 140 boolean mCreated; 141 boolean mSurfaceCreated; 142 boolean mIsCreating; 143 boolean mDrawingAllowed; 144 boolean mOffsetsChanged; 145 boolean mFixedSizeAllowed; 146 int mWidth; 147 int mHeight; 148 int mFormat; 149 int mType; 150 int mCurWidth; 151 int mCurHeight; 152 int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 153 int mWindowPrivateFlags = 154 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; 155 int mCurWindowFlags = mWindowFlags; 156 int mCurWindowPrivateFlags = mWindowPrivateFlags; 157 final Rect mVisibleInsets = new Rect(); 158 final Rect mWinFrame = new Rect(); 159 final Rect mOverscanInsets = new Rect(); 160 final Rect mContentInsets = new Rect(); 161 final Rect mStableInsets = new Rect(); 162 final Rect mOutsets = new Rect(); 163 final Rect mDispatchedOverscanInsets = new Rect(); 164 final Rect mDispatchedContentInsets = new Rect(); 165 final Rect mDispatchedStableInsets = new Rect(); 166 final Rect mDispatchedOutsets = new Rect(); 167 final Rect mFinalSystemInsets = new Rect(); 168 final Rect mFinalStableInsets = new Rect(); 169 final Rect mBackdropFrame = new Rect(); 170 final MergedConfiguration mMergedConfiguration = new MergedConfiguration(); 171 172 final WindowManager.LayoutParams mLayout 173 = new WindowManager.LayoutParams(); 174 IWindowSession mSession; 175 InputChannel mInputChannel; 176 177 final Object mLock = new Object(); 178 boolean mOffsetMessageEnqueued; 179 float mPendingXOffset; 180 float mPendingYOffset; 181 float mPendingXOffsetStep; 182 float mPendingYOffsetStep; 183 boolean mPendingSync; 184 MotionEvent mPendingMove; 185 186 DisplayManager mDisplayManager; 187 Display mDisplay; 188 private int mDisplayState; 189 190 final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { 191 { 192 mRequestedFormat = PixelFormat.RGBX_8888; 193 } 194 195 @Override 196 public boolean onAllowLockCanvas() { 197 return mDrawingAllowed; 198 } 199 200 @Override 201 public void onRelayoutContainer() { 202 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 203 mCaller.sendMessage(msg); 204 } 205 206 @Override 207 public void onUpdateSurface() { 208 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 209 mCaller.sendMessage(msg); 210 } 211 212 public boolean isCreating() { 213 return mIsCreating; 214 } 215 216 @Override 217 public void setFixedSize(int width, int height) { 218 if (!mFixedSizeAllowed) { 219 // Regular apps can't do this. It can only work for 220 // certain designs of window animations, so you can't 221 // rely on it. 222 throw new UnsupportedOperationException( 223 "Wallpapers currently only support sizing from layout"); 224 } 225 super.setFixedSize(width, height); 226 } 227 228 public void setKeepScreenOn(boolean screenOn) { 229 throw new UnsupportedOperationException( 230 "Wallpapers do not support keep screen on"); 231 } 232 233 private void prepareToDraw() { 234 if (mDisplayState == Display.STATE_DOZE 235 || mDisplayState == Display.STATE_DOZE_SUSPEND) { 236 try { 237 mSession.pokeDrawLock(mWindow); 238 } catch (RemoteException e) { 239 // System server died, can be ignored. 240 } 241 } 242 } 243 244 @Override 245 public Canvas lockCanvas() { 246 prepareToDraw(); 247 return super.lockCanvas(); 248 } 249 250 @Override 251 public Canvas lockCanvas(Rect dirty) { 252 prepareToDraw(); 253 return super.lockCanvas(dirty); 254 } 255 256 @Override 257 public Canvas lockHardwareCanvas() { 258 prepareToDraw(); 259 return super.lockHardwareCanvas(); 260 } 261 }; 262 263 final class WallpaperInputEventReceiver extends InputEventReceiver { WallpaperInputEventReceiver(InputChannel inputChannel, Looper looper)264 public WallpaperInputEventReceiver(InputChannel inputChannel, Looper looper) { 265 super(inputChannel, looper); 266 } 267 268 @Override onInputEvent(InputEvent event)269 public void onInputEvent(InputEvent event) { 270 boolean handled = false; 271 try { 272 if (event instanceof MotionEvent 273 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 274 MotionEvent dup = MotionEvent.obtainNoHistory((MotionEvent)event); 275 dispatchPointer(dup); 276 handled = true; 277 } 278 } finally { 279 finishInputEvent(event, handled); 280 } 281 } 282 } 283 WallpaperInputEventReceiver mInputEventReceiver; 284 285 final BaseIWindow mWindow = new BaseIWindow() { 286 @Override 287 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, 288 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, 289 MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout, 290 boolean alwaysConsumeNavBar, int displayId) { 291 Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED, 292 reportDraw ? 1 : 0, outsets); 293 mCaller.sendMessage(msg); 294 } 295 296 @Override 297 public void moved(int newX, int newY) { 298 Message msg = mCaller.obtainMessageII(MSG_WINDOW_MOVED, newX, newY); 299 mCaller.sendMessage(msg); 300 } 301 302 @Override 303 public void dispatchAppVisibility(boolean visible) { 304 // We don't do this in preview mode; we'll let the preview 305 // activity tell us when to run. 306 if (!mIWallpaperEngine.mIsPreview) { 307 Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED, 308 visible ? 1 : 0); 309 mCaller.sendMessage(msg); 310 } 311 } 312 313 @Override 314 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, 315 boolean sync) { 316 synchronized (mLock) { 317 if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y); 318 mPendingXOffset = x; 319 mPendingYOffset = y; 320 mPendingXOffsetStep = xStep; 321 mPendingYOffsetStep = yStep; 322 if (sync) { 323 mPendingSync = true; 324 } 325 if (!mOffsetMessageEnqueued) { 326 mOffsetMessageEnqueued = true; 327 Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS); 328 mCaller.sendMessage(msg); 329 } 330 } 331 } 332 333 @Override 334 public void dispatchWallpaperCommand(String action, int x, int y, 335 int z, Bundle extras, boolean sync) { 336 synchronized (mLock) { 337 if (DEBUG) Log.v(TAG, "Dispatch wallpaper command: " + x + ", " + y); 338 WallpaperCommand cmd = new WallpaperCommand(); 339 cmd.action = action; 340 cmd.x = x; 341 cmd.y = y; 342 cmd.z = z; 343 cmd.extras = extras; 344 cmd.sync = sync; 345 Message msg = mCaller.obtainMessage(MSG_WALLPAPER_COMMAND); 346 msg.obj = cmd; 347 mCaller.sendMessage(msg); 348 } 349 } 350 }; 351 352 /** 353 * Provides access to the surface in which this wallpaper is drawn. 354 */ getSurfaceHolder()355 public SurfaceHolder getSurfaceHolder() { 356 return mSurfaceHolder; 357 } 358 359 /** 360 * Convenience for {@link WallpaperManager#getDesiredMinimumWidth() 361 * WallpaperManager.getDesiredMinimumWidth()}, returning the width 362 * that the system would like this wallpaper to run in. 363 */ getDesiredMinimumWidth()364 public int getDesiredMinimumWidth() { 365 return mIWallpaperEngine.mReqWidth; 366 } 367 368 /** 369 * Convenience for {@link WallpaperManager#getDesiredMinimumHeight() 370 * WallpaperManager.getDesiredMinimumHeight()}, returning the height 371 * that the system would like this wallpaper to run in. 372 */ getDesiredMinimumHeight()373 public int getDesiredMinimumHeight() { 374 return mIWallpaperEngine.mReqHeight; 375 } 376 377 /** 378 * Return whether the wallpaper is currently visible to the user, 379 * this is the last value supplied to 380 * {@link #onVisibilityChanged(boolean)}. 381 */ isVisible()382 public boolean isVisible() { 383 return mReportedVisible; 384 } 385 386 /** 387 * Returns true if this engine is running in preview mode -- that is, 388 * it is being shown to the user before they select it as the actual 389 * wallpaper. 390 */ isPreview()391 public boolean isPreview() { 392 return mIWallpaperEngine.mIsPreview; 393 } 394 395 /** 396 * Control whether this wallpaper will receive raw touch events 397 * from the window manager as the user interacts with the window 398 * that is currently displaying the wallpaper. By default they 399 * are turned off. If enabled, the events will be received in 400 * {@link #onTouchEvent(MotionEvent)}. 401 */ setTouchEventsEnabled(boolean enabled)402 public void setTouchEventsEnabled(boolean enabled) { 403 mWindowFlags = enabled 404 ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) 405 : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); 406 if (mCreated) { 407 updateSurface(false, false, false); 408 } 409 } 410 411 /** 412 * Control whether this wallpaper will receive notifications when the wallpaper 413 * has been scrolled. By default, wallpapers will receive notifications, although 414 * the default static image wallpapers do not. It is a performance optimization to 415 * set this to false. 416 * 417 * @param enabled whether the wallpaper wants to receive offset notifications 418 */ setOffsetNotificationsEnabled(boolean enabled)419 public void setOffsetNotificationsEnabled(boolean enabled) { 420 mWindowPrivateFlags = enabled 421 ? (mWindowPrivateFlags | 422 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) 423 : (mWindowPrivateFlags & 424 ~WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS); 425 if (mCreated) { 426 updateSurface(false, false, false); 427 } 428 } 429 430 /** {@hide} */ setFixedSizeAllowed(boolean allowed)431 public void setFixedSizeAllowed(boolean allowed) { 432 mFixedSizeAllowed = allowed; 433 } 434 435 /** 436 * Called once to initialize the engine. After returning, the 437 * engine's surface will be created by the framework. 438 */ onCreate(SurfaceHolder surfaceHolder)439 public void onCreate(SurfaceHolder surfaceHolder) { 440 } 441 442 /** 443 * Called right before the engine is going away. After this the 444 * surface will be destroyed and this Engine object is no longer 445 * valid. 446 */ onDestroy()447 public void onDestroy() { 448 } 449 450 /** 451 * Called to inform you of the wallpaper becoming visible or 452 * hidden. <em>It is very important that a wallpaper only use 453 * CPU while it is visible.</em>. 454 */ onVisibilityChanged(boolean visible)455 public void onVisibilityChanged(boolean visible) { 456 } 457 458 /** 459 * Called with the current insets that are in effect for the wallpaper. 460 * This gives you the part of the overall wallpaper surface that will 461 * generally be visible to the user (ignoring position offsets applied to it). 462 * 463 * @param insets Insets to apply. 464 */ onApplyWindowInsets(WindowInsets insets)465 public void onApplyWindowInsets(WindowInsets insets) { 466 } 467 468 /** 469 * Called as the user performs touch-screen interaction with the 470 * window that is currently showing this wallpaper. Note that the 471 * events you receive here are driven by the actual application the 472 * user is interacting with, so if it is slow you will get fewer 473 * move events. 474 */ onTouchEvent(MotionEvent event)475 public void onTouchEvent(MotionEvent event) { 476 } 477 478 /** 479 * Called to inform you of the wallpaper's offsets changing 480 * within its contain, corresponding to the container's 481 * call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float) 482 * WallpaperManager.setWallpaperOffsets()}. 483 */ onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset)484 public void onOffsetsChanged(float xOffset, float yOffset, 485 float xOffsetStep, float yOffsetStep, 486 int xPixelOffset, int yPixelOffset) { 487 } 488 489 /** 490 * Process a command that was sent to the wallpaper with 491 * {@link WallpaperManager#sendWallpaperCommand}. 492 * The default implementation does nothing, and always returns null 493 * as the result. 494 * 495 * @param action The name of the command to perform. This tells you 496 * what to do and how to interpret the rest of the arguments. 497 * @param x Generic integer parameter. 498 * @param y Generic integer parameter. 499 * @param z Generic integer parameter. 500 * @param extras Any additional parameters. 501 * @param resultRequested If true, the caller is requesting that 502 * a result, appropriate for the command, be returned back. 503 * @return If returning a result, create a Bundle and place the 504 * result data in to it. Otherwise return null. 505 */ onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested)506 public Bundle onCommand(String action, int x, int y, int z, 507 Bundle extras, boolean resultRequested) { 508 return null; 509 } 510 511 /** 512 * Called when an application has changed the desired virtual size of 513 * the wallpaper. 514 */ onDesiredSizeChanged(int desiredWidth, int desiredHeight)515 public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { 516 } 517 518 /** 519 * Convenience for {@link SurfaceHolder.Callback#surfaceChanged 520 * SurfaceHolder.Callback.surfaceChanged()}. 521 */ onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)522 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 523 } 524 525 /** 526 * Convenience for {@link SurfaceHolder.Callback2#surfaceRedrawNeeded 527 * SurfaceHolder.Callback.surfaceRedrawNeeded()}. 528 */ onSurfaceRedrawNeeded(SurfaceHolder holder)529 public void onSurfaceRedrawNeeded(SurfaceHolder holder) { 530 } 531 532 /** 533 * Convenience for {@link SurfaceHolder.Callback#surfaceCreated 534 * SurfaceHolder.Callback.surfaceCreated()}. 535 */ onSurfaceCreated(SurfaceHolder holder)536 public void onSurfaceCreated(SurfaceHolder holder) { 537 } 538 539 /** 540 * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed 541 * SurfaceHolder.Callback.surfaceDestroyed()}. 542 */ onSurfaceDestroyed(SurfaceHolder holder)543 public void onSurfaceDestroyed(SurfaceHolder holder) { 544 } 545 dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args)546 protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { 547 out.print(prefix); out.print("mInitializing="); out.print(mInitializing); 548 out.print(" mDestroyed="); out.println(mDestroyed); 549 out.print(prefix); out.print("mVisible="); out.print(mVisible); 550 out.print(" mReportedVisible="); out.println(mReportedVisible); 551 out.print(prefix); out.print("mDisplay="); out.println(mDisplay); 552 out.print(prefix); out.print("mCreated="); out.print(mCreated); 553 out.print(" mSurfaceCreated="); out.print(mSurfaceCreated); 554 out.print(" mIsCreating="); out.print(mIsCreating); 555 out.print(" mDrawingAllowed="); out.println(mDrawingAllowed); 556 out.print(prefix); out.print("mWidth="); out.print(mWidth); 557 out.print(" mCurWidth="); out.print(mCurWidth); 558 out.print(" mHeight="); out.print(mHeight); 559 out.print(" mCurHeight="); out.println(mCurHeight); 560 out.print(prefix); out.print("mType="); out.print(mType); 561 out.print(" mWindowFlags="); out.print(mWindowFlags); 562 out.print(" mCurWindowFlags="); out.println(mCurWindowFlags); 563 out.print(prefix); out.print("mWindowPrivateFlags="); out.print(mWindowPrivateFlags); 564 out.print(" mCurWindowPrivateFlags="); out.println(mCurWindowPrivateFlags); 565 out.print(prefix); out.print("mVisibleInsets="); 566 out.print(mVisibleInsets.toShortString()); 567 out.print(" mWinFrame="); out.print(mWinFrame.toShortString()); 568 out.print(" mContentInsets="); out.println(mContentInsets.toShortString()); 569 out.print(prefix); out.print("mConfiguration="); 570 out.println(mMergedConfiguration.getMergedConfiguration()); 571 out.print(prefix); out.print("mLayout="); out.println(mLayout); 572 synchronized (mLock) { 573 out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset); 574 out.print(" mPendingXOffset="); out.println(mPendingXOffset); 575 out.print(prefix); out.print("mPendingXOffsetStep="); 576 out.print(mPendingXOffsetStep); 577 out.print(" mPendingXOffsetStep="); out.println(mPendingXOffsetStep); 578 out.print(prefix); out.print("mOffsetMessageEnqueued="); 579 out.print(mOffsetMessageEnqueued); 580 out.print(" mPendingSync="); out.println(mPendingSync); 581 if (mPendingMove != null) { 582 out.print(prefix); out.print("mPendingMove="); out.println(mPendingMove); 583 } 584 } 585 } 586 dispatchPointer(MotionEvent event)587 private void dispatchPointer(MotionEvent event) { 588 if (event.isTouchEvent()) { 589 synchronized (mLock) { 590 if (event.getAction() == MotionEvent.ACTION_MOVE) { 591 mPendingMove = event; 592 } else { 593 mPendingMove = null; 594 } 595 } 596 Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event); 597 mCaller.sendMessage(msg); 598 } else { 599 event.recycle(); 600 } 601 } 602 updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded)603 void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) { 604 if (mDestroyed) { 605 Log.w(TAG, "Ignoring updateSurface: destroyed"); 606 } 607 608 boolean fixedSize = false; 609 int myWidth = mSurfaceHolder.getRequestedWidth(); 610 if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.MATCH_PARENT; 611 else fixedSize = true; 612 int myHeight = mSurfaceHolder.getRequestedHeight(); 613 if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.MATCH_PARENT; 614 else fixedSize = true; 615 616 final boolean creating = !mCreated; 617 final boolean surfaceCreating = !mSurfaceCreated; 618 final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat(); 619 boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; 620 boolean insetsChanged = !mCreated; 621 final boolean typeChanged = mType != mSurfaceHolder.getRequestedType(); 622 final boolean flagsChanged = mCurWindowFlags != mWindowFlags || 623 mCurWindowPrivateFlags != mWindowPrivateFlags; 624 if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged 625 || typeChanged || flagsChanged || redrawNeeded 626 || !mIWallpaperEngine.mShownReported) { 627 628 if (DEBUG) Log.v(TAG, "Changes: creating=" + creating 629 + " format=" + formatChanged + " size=" + sizeChanged); 630 631 try { 632 mWidth = myWidth; 633 mHeight = myHeight; 634 mFormat = mSurfaceHolder.getRequestedFormat(); 635 mType = mSurfaceHolder.getRequestedType(); 636 637 mLayout.x = 0; 638 mLayout.y = 0; 639 mLayout.width = myWidth; 640 mLayout.height = myHeight; 641 642 mLayout.format = mFormat; 643 644 mCurWindowFlags = mWindowFlags; 645 mLayout.flags = mWindowFlags 646 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 647 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR 648 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 649 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 650 mCurWindowPrivateFlags = mWindowPrivateFlags; 651 mLayout.privateFlags = mWindowPrivateFlags; 652 653 mLayout.memoryType = mType; 654 mLayout.token = mWindowToken; 655 656 if (!mCreated) { 657 // Retrieve watch round info 658 TypedArray windowStyle = obtainStyledAttributes( 659 com.android.internal.R.styleable.Window); 660 windowStyle.recycle(); 661 662 // Add window 663 mLayout.type = mIWallpaperEngine.mWindowType; 664 mLayout.gravity = Gravity.START|Gravity.TOP; 665 mLayout.setTitle(WallpaperService.this.getClass().getName()); 666 mLayout.windowAnimations = 667 com.android.internal.R.style.Animation_Wallpaper; 668 mInputChannel = new InputChannel(); 669 if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE, 670 Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets, mOutsets, 671 mInputChannel) < 0) { 672 Log.w(TAG, "Failed to add window while updating wallpaper surface."); 673 return; 674 } 675 mCreated = true; 676 677 mInputEventReceiver = new WallpaperInputEventReceiver( 678 mInputChannel, Looper.myLooper()); 679 } 680 681 mSurfaceHolder.mSurfaceLock.lock(); 682 mDrawingAllowed = true; 683 684 if (!fixedSize) { 685 mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding); 686 mLayout.surfaceInsets.left += mOutsets.left; 687 mLayout.surfaceInsets.top += mOutsets.top; 688 mLayout.surfaceInsets.right += mOutsets.right; 689 mLayout.surfaceInsets.bottom += mOutsets.bottom; 690 } else { 691 mLayout.surfaceInsets.set(0, 0, 0, 0); 692 } 693 final int relayoutResult = mSession.relayout( 694 mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, 695 View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, 696 mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame, 697 mMergedConfiguration, mSurfaceHolder.mSurface); 698 699 if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface 700 + ", frame=" + mWinFrame); 701 702 int w = mWinFrame.width(); 703 int h = mWinFrame.height(); 704 705 if (!fixedSize) { 706 final Rect padding = mIWallpaperEngine.mDisplayPadding; 707 w += padding.left + padding.right + mOutsets.left + mOutsets.right; 708 h += padding.top + padding.bottom + mOutsets.top + mOutsets.bottom; 709 mOverscanInsets.left += padding.left; 710 mOverscanInsets.top += padding.top; 711 mOverscanInsets.right += padding.right; 712 mOverscanInsets.bottom += padding.bottom; 713 mContentInsets.left += padding.left; 714 mContentInsets.top += padding.top; 715 mContentInsets.right += padding.right; 716 mContentInsets.bottom += padding.bottom; 717 mStableInsets.left += padding.left; 718 mStableInsets.top += padding.top; 719 mStableInsets.right += padding.right; 720 mStableInsets.bottom += padding.bottom; 721 } 722 723 if (mCurWidth != w) { 724 sizeChanged = true; 725 mCurWidth = w; 726 } 727 if (mCurHeight != h) { 728 sizeChanged = true; 729 mCurHeight = h; 730 } 731 732 if (DEBUG) { 733 Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight); 734 } 735 736 insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets); 737 insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets); 738 insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets); 739 insetsChanged |= !mDispatchedOutsets.equals(mOutsets); 740 741 mSurfaceHolder.setSurfaceFrameSize(w, h); 742 mSurfaceHolder.mSurfaceLock.unlock(); 743 744 if (!mSurfaceHolder.mSurface.isValid()) { 745 reportSurfaceDestroyed(); 746 if (DEBUG) Log.v(TAG, "Layout: Surface destroyed"); 747 return; 748 } 749 750 boolean didSurface = false; 751 752 try { 753 mSurfaceHolder.ungetCallbacks(); 754 755 if (surfaceCreating) { 756 mIsCreating = true; 757 didSurface = true; 758 if (DEBUG) Log.v(TAG, "onSurfaceCreated(" 759 + mSurfaceHolder + "): " + this); 760 onSurfaceCreated(mSurfaceHolder); 761 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 762 if (callbacks != null) { 763 for (SurfaceHolder.Callback c : callbacks) { 764 c.surfaceCreated(mSurfaceHolder); 765 } 766 } 767 } 768 769 redrawNeeded |= creating || (relayoutResult 770 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0; 771 772 if (forceReport || creating || surfaceCreating 773 || formatChanged || sizeChanged) { 774 if (DEBUG) { 775 RuntimeException e = new RuntimeException(); 776 e.fillInStackTrace(); 777 Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating 778 + " formatChanged=" + formatChanged 779 + " sizeChanged=" + sizeChanged, e); 780 } 781 if (DEBUG) Log.v(TAG, "onSurfaceChanged(" 782 + mSurfaceHolder + ", " + mFormat 783 + ", " + mCurWidth + ", " + mCurHeight 784 + "): " + this); 785 didSurface = true; 786 onSurfaceChanged(mSurfaceHolder, mFormat, 787 mCurWidth, mCurHeight); 788 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 789 if (callbacks != null) { 790 for (SurfaceHolder.Callback c : callbacks) { 791 c.surfaceChanged(mSurfaceHolder, mFormat, 792 mCurWidth, mCurHeight); 793 } 794 } 795 } 796 797 if (insetsChanged) { 798 mDispatchedOverscanInsets.set(mOverscanInsets); 799 mDispatchedOverscanInsets.left += mOutsets.left; 800 mDispatchedOverscanInsets.top += mOutsets.top; 801 mDispatchedOverscanInsets.right += mOutsets.right; 802 mDispatchedOverscanInsets.bottom += mOutsets.bottom; 803 mDispatchedContentInsets.set(mContentInsets); 804 mDispatchedStableInsets.set(mStableInsets); 805 mDispatchedOutsets.set(mOutsets); 806 mFinalSystemInsets.set(mDispatchedOverscanInsets); 807 mFinalStableInsets.set(mDispatchedStableInsets); 808 WindowInsets insets = new WindowInsets(mFinalSystemInsets, 809 null, mFinalStableInsets, 810 getResources().getConfiguration().isScreenRound(), false); 811 if (DEBUG) { 812 Log.v(TAG, "dispatching insets=" + insets); 813 } 814 onApplyWindowInsets(insets); 815 } 816 817 if (redrawNeeded) { 818 onSurfaceRedrawNeeded(mSurfaceHolder); 819 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 820 if (callbacks != null) { 821 for (SurfaceHolder.Callback c : callbacks) { 822 if (c instanceof SurfaceHolder.Callback2) { 823 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded( 824 mSurfaceHolder); 825 } 826 } 827 } 828 } 829 830 if (didSurface && !mReportedVisible) { 831 // This wallpaper is currently invisible, but its 832 // surface has changed. At this point let's tell it 833 // again that it is invisible in case the report about 834 // the surface caused it to start running. We really 835 // don't want wallpapers running when not visible. 836 if (mIsCreating) { 837 // Some wallpapers will ignore this call if they 838 // had previously been told they were invisble, 839 // so if we are creating a new surface then toggle 840 // the state to get them to notice. 841 if (DEBUG) Log.v(TAG, "onVisibilityChanged(true) at surface: " 842 + this); 843 onVisibilityChanged(true); 844 } 845 if (DEBUG) Log.v(TAG, "onVisibilityChanged(false) at surface: " 846 + this); 847 onVisibilityChanged(false); 848 } 849 850 } finally { 851 mIsCreating = false; 852 mSurfaceCreated = true; 853 if (redrawNeeded) { 854 mSession.finishDrawing(mWindow); 855 } 856 mIWallpaperEngine.reportShown(); 857 } 858 } catch (RemoteException ex) { 859 } 860 if (DEBUG) Log.v( 861 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + 862 " w=" + mLayout.width + " h=" + mLayout.height); 863 } 864 } 865 attach(IWallpaperEngineWrapper wrapper)866 void attach(IWallpaperEngineWrapper wrapper) { 867 if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper); 868 if (mDestroyed) { 869 return; 870 } 871 872 mIWallpaperEngine = wrapper; 873 mCaller = wrapper.mCaller; 874 mConnection = wrapper.mConnection; 875 mWindowToken = wrapper.mWindowToken; 876 mSurfaceHolder.setSizeFromLayout(); 877 mInitializing = true; 878 mSession = WindowManagerGlobal.getWindowSession(); 879 880 mWindow.setSession(mSession); 881 882 mLayout.packageName = getPackageName(); 883 884 mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); 885 mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler()); 886 mDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 887 mDisplayState = mDisplay.getState(); 888 889 if (DEBUG) Log.v(TAG, "onCreate(): " + this); 890 onCreate(mSurfaceHolder); 891 892 mInitializing = false; 893 mReportedVisible = false; 894 updateSurface(false, false, false); 895 } 896 doDesiredSizeChanged(int desiredWidth, int desiredHeight)897 void doDesiredSizeChanged(int desiredWidth, int desiredHeight) { 898 if (!mDestroyed) { 899 if (DEBUG) Log.v(TAG, "onDesiredSizeChanged(" 900 + desiredWidth + "," + desiredHeight + "): " + this); 901 mIWallpaperEngine.mReqWidth = desiredWidth; 902 mIWallpaperEngine.mReqHeight = desiredHeight; 903 onDesiredSizeChanged(desiredWidth, desiredHeight); 904 doOffsetsChanged(true); 905 } 906 } 907 doDisplayPaddingChanged(Rect padding)908 void doDisplayPaddingChanged(Rect padding) { 909 if (!mDestroyed) { 910 if (DEBUG) Log.v(TAG, "onDisplayPaddingChanged(" + padding + "): " + this); 911 if (!mIWallpaperEngine.mDisplayPadding.equals(padding)) { 912 mIWallpaperEngine.mDisplayPadding.set(padding); 913 updateSurface(true, false, false); 914 } 915 } 916 } 917 doVisibilityChanged(boolean visible)918 void doVisibilityChanged(boolean visible) { 919 if (!mDestroyed) { 920 mVisible = visible; 921 reportVisibility(); 922 } 923 } 924 reportVisibility()925 void reportVisibility() { 926 if (!mDestroyed) { 927 mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState(); 928 boolean visible = mVisible && mDisplayState != Display.STATE_OFF; 929 if (mReportedVisible != visible) { 930 mReportedVisible = visible; 931 if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible 932 + "): " + this); 933 if (visible) { 934 // If becoming visible, in preview mode the surface 935 // may have been destroyed so now we need to make 936 // sure it is re-created. 937 doOffsetsChanged(false); 938 updateSurface(false, false, false); 939 } 940 onVisibilityChanged(visible); 941 } 942 } 943 } 944 doOffsetsChanged(boolean always)945 void doOffsetsChanged(boolean always) { 946 if (mDestroyed) { 947 return; 948 } 949 950 if (!always && !mOffsetsChanged) { 951 return; 952 } 953 954 float xOffset; 955 float yOffset; 956 float xOffsetStep; 957 float yOffsetStep; 958 boolean sync; 959 synchronized (mLock) { 960 xOffset = mPendingXOffset; 961 yOffset = mPendingYOffset; 962 xOffsetStep = mPendingXOffsetStep; 963 yOffsetStep = mPendingYOffsetStep; 964 sync = mPendingSync; 965 mPendingSync = false; 966 mOffsetMessageEnqueued = false; 967 } 968 969 if (mSurfaceCreated) { 970 if (mReportedVisible) { 971 if (DEBUG) Log.v(TAG, "Offsets change in " + this 972 + ": " + xOffset + "," + yOffset); 973 final int availw = mIWallpaperEngine.mReqWidth-mCurWidth; 974 final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0; 975 final int availh = mIWallpaperEngine.mReqHeight-mCurHeight; 976 final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0; 977 onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixels, yPixels); 978 } else { 979 mOffsetsChanged = true; 980 } 981 } 982 983 if (sync) { 984 try { 985 if (DEBUG) Log.v(TAG, "Reporting offsets change complete"); 986 mSession.wallpaperOffsetsComplete(mWindow.asBinder()); 987 } catch (RemoteException e) { 988 } 989 } 990 } 991 doCommand(WallpaperCommand cmd)992 void doCommand(WallpaperCommand cmd) { 993 Bundle result; 994 if (!mDestroyed) { 995 result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z, 996 cmd.extras, cmd.sync); 997 } else { 998 result = null; 999 } 1000 if (cmd.sync) { 1001 try { 1002 if (DEBUG) Log.v(TAG, "Reporting command complete"); 1003 mSession.wallpaperCommandComplete(mWindow.asBinder(), result); 1004 } catch (RemoteException e) { 1005 } 1006 } 1007 } 1008 reportSurfaceDestroyed()1009 void reportSurfaceDestroyed() { 1010 if (mSurfaceCreated) { 1011 mSurfaceCreated = false; 1012 mSurfaceHolder.ungetCallbacks(); 1013 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 1014 if (callbacks != null) { 1015 for (SurfaceHolder.Callback c : callbacks) { 1016 c.surfaceDestroyed(mSurfaceHolder); 1017 } 1018 } 1019 if (DEBUG) Log.v(TAG, "onSurfaceDestroyed(" 1020 + mSurfaceHolder + "): " + this); 1021 onSurfaceDestroyed(mSurfaceHolder); 1022 } 1023 } 1024 detach()1025 void detach() { 1026 if (mDestroyed) { 1027 return; 1028 } 1029 1030 mDestroyed = true; 1031 1032 if (mDisplayManager != null) { 1033 mDisplayManager.unregisterDisplayListener(mDisplayListener); 1034 } 1035 1036 if (mVisible) { 1037 mVisible = false; 1038 if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this); 1039 onVisibilityChanged(false); 1040 } 1041 1042 reportSurfaceDestroyed(); 1043 1044 if (DEBUG) Log.v(TAG, "onDestroy(): " + this); 1045 onDestroy(); 1046 1047 if (mCreated) { 1048 try { 1049 if (DEBUG) Log.v(TAG, "Removing window and destroying surface " 1050 + mSurfaceHolder.getSurface() + " of: " + this); 1051 1052 if (mInputEventReceiver != null) { 1053 mInputEventReceiver.dispose(); 1054 mInputEventReceiver = null; 1055 } 1056 1057 mSession.remove(mWindow); 1058 } catch (RemoteException e) { 1059 } 1060 mSurfaceHolder.mSurface.release(); 1061 mCreated = false; 1062 1063 // Dispose the input channel after removing the window so the Window Manager 1064 // doesn't interpret the input channel being closed as an abnormal termination. 1065 if (mInputChannel != null) { 1066 mInputChannel.dispose(); 1067 mInputChannel = null; 1068 } 1069 } 1070 } 1071 1072 private final DisplayListener mDisplayListener = new DisplayListener() { 1073 @Override 1074 public void onDisplayChanged(int displayId) { 1075 if (mDisplay.getDisplayId() == displayId) { 1076 reportVisibility(); 1077 } 1078 } 1079 1080 @Override 1081 public void onDisplayRemoved(int displayId) { 1082 } 1083 1084 @Override 1085 public void onDisplayAdded(int displayId) { 1086 } 1087 }; 1088 } 1089 1090 class IWallpaperEngineWrapper extends IWallpaperEngine.Stub 1091 implements HandlerCaller.Callback { 1092 private final HandlerCaller mCaller; 1093 1094 final IWallpaperConnection mConnection; 1095 final IBinder mWindowToken; 1096 final int mWindowType; 1097 final boolean mIsPreview; 1098 boolean mShownReported; 1099 int mReqWidth; 1100 int mReqHeight; 1101 final Rect mDisplayPadding = new Rect(); 1102 1103 Engine mEngine; 1104 IWallpaperEngineWrapper(WallpaperService context, IWallpaperConnection conn, IBinder windowToken, int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding)1105 IWallpaperEngineWrapper(WallpaperService context, 1106 IWallpaperConnection conn, IBinder windowToken, 1107 int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) { 1108 mCaller = new HandlerCaller(context, context.getMainLooper(), this, true); 1109 mConnection = conn; 1110 mWindowToken = windowToken; 1111 mWindowType = windowType; 1112 mIsPreview = isPreview; 1113 mReqWidth = reqWidth; 1114 mReqHeight = reqHeight; 1115 mDisplayPadding.set(padding); 1116 1117 Message msg = mCaller.obtainMessage(DO_ATTACH); 1118 mCaller.sendMessage(msg); 1119 } 1120 setDesiredSize(int width, int height)1121 public void setDesiredSize(int width, int height) { 1122 Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height); 1123 mCaller.sendMessage(msg); 1124 } 1125 setDisplayPadding(Rect padding)1126 public void setDisplayPadding(Rect padding) { 1127 Message msg = mCaller.obtainMessageO(DO_SET_DISPLAY_PADDING, padding); 1128 mCaller.sendMessage(msg); 1129 } 1130 setVisibility(boolean visible)1131 public void setVisibility(boolean visible) { 1132 Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED, 1133 visible ? 1 : 0); 1134 mCaller.sendMessage(msg); 1135 } 1136 dispatchPointer(MotionEvent event)1137 public void dispatchPointer(MotionEvent event) { 1138 if (mEngine != null) { 1139 mEngine.dispatchPointer(event); 1140 } else { 1141 event.recycle(); 1142 } 1143 } 1144 dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras)1145 public void dispatchWallpaperCommand(String action, int x, int y, 1146 int z, Bundle extras) { 1147 if (mEngine != null) { 1148 mEngine.mWindow.dispatchWallpaperCommand(action, x, y, z, extras, false); 1149 } 1150 } 1151 reportShown()1152 public void reportShown() { 1153 if (!mShownReported) { 1154 mShownReported = true; 1155 try { 1156 mConnection.engineShown(this); 1157 } catch (RemoteException e) { 1158 Log.w(TAG, "Wallpaper host disappeared", e); 1159 return; 1160 } 1161 } 1162 } 1163 destroy()1164 public void destroy() { 1165 Message msg = mCaller.obtainMessage(DO_DETACH); 1166 mCaller.sendMessage(msg); 1167 } 1168 executeMessage(Message message)1169 public void executeMessage(Message message) { 1170 switch (message.what) { 1171 case DO_ATTACH: { 1172 try { 1173 mConnection.attachEngine(this); 1174 } catch (RemoteException e) { 1175 Log.w(TAG, "Wallpaper host disappeared", e); 1176 return; 1177 } 1178 Engine engine = onCreateEngine(); 1179 mEngine = engine; 1180 mActiveEngines.add(engine); 1181 engine.attach(this); 1182 return; 1183 } 1184 case DO_DETACH: { 1185 mActiveEngines.remove(mEngine); 1186 mEngine.detach(); 1187 return; 1188 } 1189 case DO_SET_DESIRED_SIZE: { 1190 mEngine.doDesiredSizeChanged(message.arg1, message.arg2); 1191 return; 1192 } 1193 case DO_SET_DISPLAY_PADDING: { 1194 mEngine.doDisplayPaddingChanged((Rect) message.obj); 1195 } 1196 case MSG_UPDATE_SURFACE: 1197 mEngine.updateSurface(true, false, false); 1198 break; 1199 case MSG_VISIBILITY_CHANGED: 1200 if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine 1201 + ": " + message.arg1); 1202 mEngine.doVisibilityChanged(message.arg1 != 0); 1203 break; 1204 case MSG_WALLPAPER_OFFSETS: { 1205 mEngine.doOffsetsChanged(true); 1206 } break; 1207 case MSG_WALLPAPER_COMMAND: { 1208 WallpaperCommand cmd = (WallpaperCommand)message.obj; 1209 mEngine.doCommand(cmd); 1210 } break; 1211 case MSG_WINDOW_RESIZED: { 1212 final boolean reportDraw = message.arg1 != 0; 1213 mEngine.mOutsets.set((Rect) message.obj); 1214 mEngine.updateSurface(true, false, reportDraw); 1215 mEngine.doOffsetsChanged(true); 1216 } break; 1217 case MSG_WINDOW_MOVED: { 1218 // Do nothing. What does it mean for a Wallpaper to move? 1219 } break; 1220 case MSG_TOUCH_EVENT: { 1221 boolean skip = false; 1222 MotionEvent ev = (MotionEvent)message.obj; 1223 if (ev.getAction() == MotionEvent.ACTION_MOVE) { 1224 synchronized (mEngine.mLock) { 1225 if (mEngine.mPendingMove == ev) { 1226 mEngine.mPendingMove = null; 1227 } else { 1228 // this is not the motion event we are looking for.... 1229 skip = true; 1230 } 1231 } 1232 } 1233 if (!skip) { 1234 if (DEBUG) Log.v(TAG, "Delivering touch event: " + ev); 1235 mEngine.onTouchEvent(ev); 1236 } 1237 ev.recycle(); 1238 } break; 1239 default : 1240 Log.w(TAG, "Unknown message type " + message.what); 1241 } 1242 } 1243 } 1244 1245 /** 1246 * Implements the internal {@link IWallpaperService} interface to convert 1247 * incoming calls to it back to calls on an {@link WallpaperService}. 1248 */ 1249 class IWallpaperServiceWrapper extends IWallpaperService.Stub { 1250 private final WallpaperService mTarget; 1251 IWallpaperServiceWrapper(WallpaperService context)1252 public IWallpaperServiceWrapper(WallpaperService context) { 1253 mTarget = context; 1254 } 1255 1256 @Override attach(IWallpaperConnection conn, IBinder windowToken, int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding)1257 public void attach(IWallpaperConnection conn, IBinder windowToken, 1258 int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) { 1259 new IWallpaperEngineWrapper(mTarget, conn, windowToken, 1260 windowType, isPreview, reqWidth, reqHeight, padding); 1261 } 1262 } 1263 1264 @Override onCreate()1265 public void onCreate() { 1266 super.onCreate(); 1267 } 1268 1269 @Override onDestroy()1270 public void onDestroy() { 1271 super.onDestroy(); 1272 for (int i=0; i<mActiveEngines.size(); i++) { 1273 mActiveEngines.get(i).detach(); 1274 } 1275 mActiveEngines.clear(); 1276 } 1277 1278 /** 1279 * Implement to return the implementation of the internal accessibility 1280 * service interface. Subclasses should not override. 1281 */ 1282 @Override onBind(Intent intent)1283 public final IBinder onBind(Intent intent) { 1284 return new IWallpaperServiceWrapper(this); 1285 } 1286 1287 /** 1288 * Must be implemented to return a new instance of the wallpaper's engine. 1289 * Note that multiple instances may be active at the same time, such as 1290 * when the wallpaper is currently set as the active wallpaper and the user 1291 * is in the wallpaper picker viewing a preview of it as well. 1292 */ onCreateEngine()1293 public abstract Engine onCreateEngine(); 1294 1295 @Override dump(FileDescriptor fd, PrintWriter out, String[] args)1296 protected void dump(FileDescriptor fd, PrintWriter out, String[] args) { 1297 out.print("State of wallpaper "); out.print(this); out.println(":"); 1298 for (int i=0; i<mActiveEngines.size(); i++) { 1299 Engine engine = mActiveEngines.get(i); 1300 out.print(" Engine "); out.print(engine); out.println(":"); 1301 engine.dump(" ", fd, out, args); 1302 } 1303 } 1304 } 1305