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