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