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