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