Home | History | Annotate | Download | only in wallpaper
      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>&lt;{@link android.R.styleable#Wallpaper wallpaper}&gt;</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 {
    250             public WallpaperInputEventReceiver(InputChannel inputChannel, Looper looper) {
    251                 super(inputChannel, looper);
    252             }
    253 
    254             @Override
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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} */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    501         public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
    502         }
    503 
    504         /**
    505          * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
    506          * SurfaceHolder.Callback.surfaceChanged()}.
    507          */
    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          */
    515         public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
    516         }
    517 
    518         /**
    519          * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
    520          * SurfaceHolder.Callback.surfaceCreated()}.
    521          */
    522         public void onSurfaceCreated(SurfaceHolder holder) {
    523         }
    524 
    525         /**
    526          * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed
    527          * SurfaceHolder.Callback.surfaceDestroyed()}.
    528          */
    529         public void onSurfaceDestroyed(SurfaceHolder holder) {
    530         }
    531 
    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 
    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 
    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 
    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 
    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 
    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 
    903         void doVisibilityChanged(boolean visible) {
    904             if (!mDestroyed) {
    905                 mVisible = visible;
    906                 reportVisibility();
    907             }
    908         }
    909 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   1111         public void setDisplayPadding(Rect padding) {
   1112             Message msg = mCaller.obtainMessageO(DO_SET_DISPLAY_PADDING, padding);
   1113             mCaller.sendMessage(msg);
   1114         }
   1115 
   1116         public void setVisibility(boolean visible) {
   1117             Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
   1118                     visible ? 1 : 0);
   1119             mCaller.sendMessage(msg);
   1120         }
   1121 
   1122         public void dispatchPointer(MotionEvent event) {
   1123             if (mEngine != null) {
   1124                 mEngine.dispatchPointer(event);
   1125             } else {
   1126                 event.recycle();
   1127             }
   1128         }
   1129 
   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 
   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 
   1149         public void destroy() {
   1150             Message msg = mCaller.obtainMessage(DO_DETACH);
   1151             mCaller.sendMessage(msg);
   1152         }
   1153 
   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 
   1237         public IWallpaperServiceWrapper(WallpaperService context) {
   1238             mTarget = context;
   1239         }
   1240 
   1241         @Override
   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
   1250     public void onCreate() {
   1251         super.onCreate();
   1252     }
   1253 
   1254     @Override
   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
   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      */
   1278     public abstract Engine onCreateEngine();
   1279 
   1280     @Override
   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