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