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