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