WallpaperService.java revision 0586a1b77a788a119166a37fccd909bf9ed65f23
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 com.android.internal.os.HandlerCaller;
20import com.android.internal.view.BaseIWindow;
21import com.android.internal.view.BaseSurfaceHolder;
22
23import android.app.Service;
24import android.app.WallpaperManager;
25import android.content.Intent;
26import android.graphics.Rect;
27import android.os.IBinder;
28import android.os.Message;
29import android.os.RemoteException;
30import android.util.Log;
31import android.view.Gravity;
32import android.view.IWindowSession;
33import android.view.MotionEvent;
34import android.view.SurfaceHolder;
35import android.view.View;
36import android.view.ViewGroup;
37import android.view.ViewRoot;
38import android.view.WindowManager;
39import android.view.WindowManagerImpl;
40
41/**
42 * A wallpaper service is responsible for showing a live wallpaper behind
43 * applications that would like to sit on top of it.
44 * @hide Live Wallpaper
45 */
46public abstract class WallpaperService extends Service {
47    /**
48     * The {@link Intent} that must be declared as handled by the service.
49     */
50    public static final String SERVICE_INTERFACE =
51        "android.service.wallpaper.WallpaperService";
52
53    static final String TAG = "WallpaperService";
54    static final boolean DEBUG = false;
55
56    private static final int DO_ATTACH = 10;
57    private static final int DO_DETACH = 20;
58    private static final int DO_SET_DESIRED_SIZE = 30;
59
60    private static final int MSG_UPDATE_SURFACE = 10000;
61    private static final int MSG_VISIBILITY_CHANGED = 10010;
62    private static final int MSG_WALLPAPER_OFFSETS = 10020;
63    private static final int MSG_WINDOW_RESIZED = 10030;
64    private static final int MSG_TOUCH_EVENT = 10040;
65
66    /**
67     * The actual implementation of a wallpaper.  A wallpaper service may
68     * have multiple instances running (for example as a real wallpaper
69     * and as a preview), each of which is represented by its own Engine
70     * instance.  You must implement {@link WallpaperService#onCreateEngine()}
71     * to return your concrete Engine implementation.
72     */
73    public class Engine {
74        IWallpaperEngineWrapper mIWallpaperEngine;
75
76        // Copies from mIWallpaperEngine.
77        HandlerCaller mCaller;
78        IWallpaperConnection mConnection;
79        IBinder mWindowToken;
80
81        boolean mInitializing = true;
82        boolean mVisible;
83        boolean mDestroyed;
84
85        // Current window state.
86        boolean mCreated;
87        boolean mIsCreating;
88        boolean mDrawingAllowed;
89        int mWidth;
90        int mHeight;
91        int mFormat;
92        int mType;
93        int mCurWidth;
94        int mCurHeight;
95        int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
96        int mCurWindowFlags = mWindowFlags;
97        boolean mDestroyReportNeeded;
98        final Rect mVisibleInsets = new Rect();
99        final Rect mWinFrame = new Rect();
100        final Rect mContentInsets = new Rect();
101
102        final WindowManager.LayoutParams mLayout
103                = new WindowManager.LayoutParams();
104        IWindowSession mSession;
105
106        final Object mLock = new Object();
107        boolean mOffsetMessageEnqueued;
108        float mPendingXOffset;
109        float mPendingYOffset;
110        MotionEvent mPendingMove;
111
112        final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
113
114            @Override
115            public boolean onAllowLockCanvas() {
116                return mDrawingAllowed;
117            }
118
119            @Override
120            public void onRelayoutContainer() {
121                Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
122                mCaller.sendMessage(msg);
123            }
124
125            @Override
126            public void onUpdateSurface() {
127                Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
128                mCaller.sendMessage(msg);
129            }
130
131            public boolean isCreating() {
132                return mIsCreating;
133            }
134
135            @Override
136            public void setFixedSize(int width, int height) {
137                throw new UnsupportedOperationException(
138                        "Wallpapers currently only support sizing from layout");
139            }
140
141            public void setKeepScreenOn(boolean screenOn) {
142                throw new UnsupportedOperationException(
143                        "Wallpapers do not support keep screen on");
144            }
145
146        };
147
148        final BaseIWindow mWindow = new BaseIWindow() {
149            @Override
150            public boolean onDispatchPointer(MotionEvent event, long eventTime,
151                    boolean callWhenDone) {
152                synchronized (mLock) {
153                    if (event.getAction() == MotionEvent.ACTION_MOVE) {
154                        if (mPendingMove != null) {
155                            mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
156                            mPendingMove.recycle();
157                        }
158                        mPendingMove = event;
159                    } else {
160                        mPendingMove = null;
161                    }
162                    Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
163                            event);
164                    mCaller.sendMessage(msg);
165                }
166                return false;
167            }
168
169            @Override
170            public void resized(int w, int h, Rect coveredInsets,
171                    Rect visibleInsets, boolean reportDraw) {
172                Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
173                        reportDraw ? 1 : 0);
174                mCaller.sendMessage(msg);
175            }
176
177            @Override
178            public void dispatchAppVisibility(boolean visible) {
179                // We don't do this in preview mode; we'll let the preview
180                // activity tell us when to run.
181                if (!mIWallpaperEngine.mIsPreview) {
182                    Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
183                            visible ? 1 : 0);
184                    mCaller.sendMessage(msg);
185                }
186            }
187
188            @Override
189            public void dispatchWallpaperOffsets(float x, float y) {
190                synchronized (mLock) {
191                    mPendingXOffset = x;
192                    mPendingYOffset = y;
193                    if (!mOffsetMessageEnqueued) {
194                        mOffsetMessageEnqueued = true;
195                        Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
196                        mCaller.sendMessage(msg);
197                    }
198                }
199            }
200
201        };
202
203        /**
204         * Provides access to the surface in which this wallpaper is drawn.
205         */
206        public SurfaceHolder getSurfaceHolder() {
207            return mSurfaceHolder;
208        }
209
210        /**
211         * Convenience for {@link WallpaperManager#getDesiredMinimumWidth()
212         * WallpaperManager.getDesiredMinimumWidth()}, returning the width
213         * that the system would like this wallpaper to run in.
214         */
215        public int getDesiredMinimumWidth() {
216            return mIWallpaperEngine.mReqWidth;
217        }
218
219        /**
220         * Convenience for {@link WallpaperManager#getDesiredMinimumHeight()
221         * WallpaperManager.getDesiredMinimumHeight()}, returning the height
222         * that the system would like this wallpaper to run in.
223         */
224        public int getDesiredMinimumHeight() {
225            return mIWallpaperEngine.mReqHeight;
226        }
227
228        /**
229         * Return whether the wallpaper is currently visible to the user,
230         * this is the last value supplied to
231         * {@link #onVisibilityChanged(boolean)}.
232         */
233        public boolean isVisible() {
234            return mVisible;
235        }
236
237        /**
238         * Returns true if this engine is running in preview mode -- that is,
239         * it is being shown to the user before they select it as the actual
240         * wallpaper.
241         */
242        public boolean isPreview() {
243            return mIWallpaperEngine.mIsPreview;
244        }
245
246        /**
247         * Control whether this wallpaper will receive raw touch events
248         * from the window manager as the user interacts with the window
249         * that is currently displaying the wallpaper.  By default they
250         * are turned off.  If enabled, the events will be received in
251         * {@link #onTouchEvent(MotionEvent)}.
252         */
253        public void setTouchEventsEnabled(boolean enabled) {
254            mWindowFlags = enabled
255                    ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
256                    : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
257            if (mCreated) {
258                updateSurface(false, false);
259            }
260        }
261
262        /**
263         * Called once to initialize the engine.  After returning, the
264         * engine's surface will be created by the framework.
265         */
266        public void onCreate(SurfaceHolder surfaceHolder) {
267        }
268
269        /**
270         * Called right before the engine is going away.  After this the
271         * surface will be destroyed and this Engine object is no longer
272         * valid.
273         */
274        public void onDestroy() {
275        }
276
277        /**
278         * Called to inform you of the wallpaper becoming visible or
279         * hidden.  <em>It is very important that a wallpaper only use
280         * CPU while it is visible.</em>.
281         */
282        public void onVisibilityChanged(boolean visible) {
283        }
284
285        /**
286         * Called as the user performs touch-screen interaction with the
287         * window that is currently showing this wallpaper.  Note that the
288         * events you receive here are driven by the actual application the
289         * user is interacting with, so if it is slow you will get viewer
290         * move events.
291         */
292        public void onTouchEvent(MotionEvent event) {
293        }
294
295        /**
296         * Called to inform you of the wallpaper's offsets changing
297         * within its contain, corresponding to the container's
298         * call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float)
299         * WallpaperManager.setWallpaperOffsets()}.
300         */
301        public void onOffsetsChanged(float xOffset, float yOffset,
302                int xPixelOffset, int yPixelOffset) {
303        }
304
305        /**
306         * Called when an application has changed the desired virtual size of
307         * the wallpaper.
308         */
309        public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
310        }
311
312        /**
313         * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
314         * SurfaceHolder.Callback.surfaceChanged()}.
315         */
316        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
317        }
318
319        /**
320         * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
321         * SurfaceHolder.Callback.surfaceCreated()}.
322         */
323        public void onSurfaceCreated(SurfaceHolder holder) {
324        }
325
326        /**
327         * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed
328         * SurfaceHolder.Callback.surfaceDestroyed()}.
329         */
330        public void onSurfaceDestroyed(SurfaceHolder holder) {
331        }
332
333        void updateSurface(boolean forceRelayout, boolean forceReport) {
334            if (mDestroyed) {
335                Log.w(TAG, "Ignoring updateSurface: destroyed");
336            }
337
338            int myWidth = mSurfaceHolder.getRequestedWidth();
339            if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
340            int myHeight = mSurfaceHolder.getRequestedHeight();
341            if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.FILL_PARENT;
342
343            final boolean creating = !mCreated;
344            final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
345            boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
346            final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
347            final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
348            if (forceRelayout || creating || formatChanged || sizeChanged
349                    || typeChanged || flagsChanged) {
350
351                if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
352                        + " format=" + formatChanged + " size=" + sizeChanged);
353
354                try {
355                    mWidth = myWidth;
356                    mHeight = myHeight;
357                    mFormat = mSurfaceHolder.getRequestedFormat();
358                    mType = mSurfaceHolder.getRequestedType();
359
360                    mLayout.x = 0;
361                    mLayout.y = 0;
362                    mLayout.width = myWidth;
363                    mLayout.height = myHeight;
364
365                    mLayout.format = mFormat;
366
367                    mCurWindowFlags = mWindowFlags;
368                    mLayout.flags = mWindowFlags
369                            | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
370                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
371                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
372                            ;
373
374                    mLayout.memoryType = mType;
375                    mLayout.token = mWindowToken;
376
377                    if (!mCreated) {
378                        mLayout.type = mIWallpaperEngine.mWindowType;
379                        mLayout.gravity = Gravity.LEFT|Gravity.TOP;
380                        mLayout.setTitle(WallpaperService.this.getClass().getName());
381                        mLayout.windowAnimations =
382                                com.android.internal.R.style.Animation_Wallpaper;
383                        mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
384                    }
385
386                    mSurfaceHolder.mSurfaceLock.lock();
387                    mDrawingAllowed = true;
388
389                    final int relayoutResult = mSession.relayout(
390                        mWindow, mLayout, mWidth, mHeight,
391                            View.VISIBLE, false, mWinFrame, mContentInsets,
392                            mVisibleInsets, mSurfaceHolder.mSurface);
393
394                    if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
395                            + ", frame=" + mWinFrame);
396
397                    int w = mWinFrame.width();
398                    if (mCurWidth != w) {
399                        sizeChanged = true;
400                        mCurWidth = w;
401                    }
402                    int h = mWinFrame.height();
403                    if (mCurHeight != h) {
404                        sizeChanged = true;
405                        mCurHeight = h;
406                    }
407
408                    mSurfaceHolder.mSurfaceLock.unlock();
409
410                    try {
411                        mDestroyReportNeeded = true;
412
413                        SurfaceHolder.Callback callbacks[] = null;
414                        synchronized (mSurfaceHolder.mCallbacks) {
415                            final int N = mSurfaceHolder.mCallbacks.size();
416                            if (N > 0) {
417                                callbacks = new SurfaceHolder.Callback[N];
418                                mSurfaceHolder.mCallbacks.toArray(callbacks);
419                            }
420                        }
421
422                        if (!mCreated) {
423                            mIsCreating = true;
424                            if (DEBUG) Log.v(TAG, "onSurfaceCreated("
425                                    + mSurfaceHolder + "): " + this);
426                            onSurfaceCreated(mSurfaceHolder);
427                            if (callbacks != null) {
428                                for (SurfaceHolder.Callback c : callbacks) {
429                                    c.surfaceCreated(mSurfaceHolder);
430                                }
431                            }
432                        }
433                        if (forceReport || creating || formatChanged || sizeChanged) {
434                            if (DEBUG) {
435                                RuntimeException e = new RuntimeException();
436                                e.fillInStackTrace();
437                                Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating
438                                        + " formatChanged=" + formatChanged
439                                        + " sizeChanged=" + sizeChanged, e);
440                            }
441                            if (DEBUG) Log.v(TAG, "onSurfaceChanged("
442                                    + mSurfaceHolder + ", " + mFormat
443                                    + ", " + mCurWidth + ", " + mCurHeight
444                                    + "): " + this);
445                            onSurfaceChanged(mSurfaceHolder, mFormat,
446                                    mCurWidth, mCurHeight);
447                            if (callbacks != null) {
448                                for (SurfaceHolder.Callback c : callbacks) {
449                                    c.surfaceChanged(mSurfaceHolder, mFormat,
450                                            mCurWidth, mCurHeight);
451                                }
452                            }
453                        }
454                    } finally {
455                        mIsCreating = false;
456                        mCreated = true;
457                        if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
458                            mSession.finishDrawing(mWindow);
459                        }
460                    }
461                } catch (RemoteException ex) {
462                }
463                if (DEBUG) Log.v(
464                    TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
465                    " w=" + mLayout.width + " h=" + mLayout.height);
466            }
467        }
468
469        void attach(IWallpaperEngineWrapper wrapper) {
470            if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper);
471            if (mDestroyed) {
472                return;
473            }
474
475            mIWallpaperEngine = wrapper;
476            mCaller = wrapper.mCaller;
477            mConnection = wrapper.mConnection;
478            mWindowToken = wrapper.mWindowToken;
479            mSurfaceHolder.setSizeFromLayout();
480            mInitializing = true;
481            mSession = ViewRoot.getWindowSession(getMainLooper());
482            mWindow.setSession(mSession);
483
484            if (DEBUG) Log.v(TAG, "onCreate(): " + this);
485            onCreate(mSurfaceHolder);
486
487            mInitializing = false;
488            updateSurface(false, false);
489        }
490
491        void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
492            if (!mDestroyed) {
493                if (DEBUG) Log.v(TAG, "onDesiredSizeChanged("
494                        + desiredWidth + "," + desiredHeight + "): " + this);
495                onDesiredSizeChanged(desiredWidth, desiredHeight);
496            }
497        }
498
499        void doVisibilityChanged(boolean visible) {
500            if (!mDestroyed) {
501                mVisible = visible;
502                if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
503                        + "): " + this);
504                onVisibilityChanged(visible);
505            }
506        }
507
508        void doOffsetsChanged() {
509            if (mDestroyed) {
510                return;
511            }
512
513            float xOffset;
514            float yOffset;
515            synchronized (mLock) {
516                xOffset = mPendingXOffset;
517                yOffset = mPendingYOffset;
518                mOffsetMessageEnqueued = false;
519            }
520            if (DEBUG) Log.v(TAG, "Offsets change in " + this
521                    + ": " + xOffset + "," + yOffset);
522            final int availw = mIWallpaperEngine.mReqWidth-mCurWidth;
523            final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
524            final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
525            final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
526            onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
527        }
528
529        void detach() {
530            mDestroyed = true;
531
532            if (mVisible) {
533                mVisible = false;
534                if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this);
535                onVisibilityChanged(false);
536            }
537
538            if (mDestroyReportNeeded) {
539                mDestroyReportNeeded = false;
540                SurfaceHolder.Callback callbacks[];
541                synchronized (mSurfaceHolder.mCallbacks) {
542                    callbacks = new SurfaceHolder.Callback[
543                            mSurfaceHolder.mCallbacks.size()];
544                    mSurfaceHolder.mCallbacks.toArray(callbacks);
545                }
546                for (SurfaceHolder.Callback c : callbacks) {
547                    c.surfaceDestroyed(mSurfaceHolder);
548                }
549                if (DEBUG) Log.v(TAG, "onSurfaceDestroyed("
550                        + mSurfaceHolder + "): " + this);
551                onSurfaceDestroyed(mSurfaceHolder);
552            }
553
554            if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
555            onDestroy();
556
557            if (mCreated) {
558                try {
559                    mSession.remove(mWindow);
560                } catch (RemoteException e) {
561                }
562                mSurfaceHolder.mSurface.release();
563                mCreated = false;
564            }
565        }
566    }
567
568    class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
569            implements HandlerCaller.Callback {
570        private final HandlerCaller mCaller;
571
572        final IWallpaperConnection mConnection;
573        final IBinder mWindowToken;
574        final int mWindowType;
575        final boolean mIsPreview;
576        int mReqWidth;
577        int mReqHeight;
578
579        Engine mEngine;
580
581        IWallpaperEngineWrapper(WallpaperService context,
582                IWallpaperConnection conn, IBinder windowToken,
583                int windowType, boolean isPreview, int reqWidth, int reqHeight) {
584            mCaller = new HandlerCaller(context, this);
585            mConnection = conn;
586            mWindowToken = windowToken;
587            mWindowType = windowType;
588            mIsPreview = isPreview;
589            mReqWidth = reqWidth;
590            mReqHeight = reqHeight;
591
592            Message msg = mCaller.obtainMessage(DO_ATTACH);
593            mCaller.sendMessage(msg);
594        }
595
596        public void setDesiredSize(int width, int height) {
597            Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height);
598            mCaller.sendMessage(msg);
599        }
600
601        public void setVisibility(boolean visible) {
602            Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
603                    visible ? 1 : 0);
604            mCaller.sendMessage(msg);
605        }
606
607        public void destroy() {
608            Message msg = mCaller.obtainMessage(DO_DETACH);
609            mCaller.sendMessage(msg);
610        }
611
612        public void executeMessage(Message message) {
613            switch (message.what) {
614                case DO_ATTACH: {
615                    try {
616                        mConnection.attachEngine(this);
617                    } catch (RemoteException e) {
618                        Log.w(TAG, "Wallpaper host disappeared", e);
619                        return;
620                    }
621                    Engine engine = onCreateEngine();
622                    mEngine = engine;
623                    engine.attach(this);
624                    return;
625                }
626                case DO_DETACH: {
627                    mEngine.detach();
628                    return;
629                }
630                case DO_SET_DESIRED_SIZE: {
631                    mEngine.doDesiredSizeChanged(message.arg1, message.arg2);
632                    return;
633                }
634                case MSG_UPDATE_SURFACE:
635                    mEngine.updateSurface(true, false);
636                    break;
637                case MSG_VISIBILITY_CHANGED:
638                    if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
639                            + ": " + message.arg1);
640                    mEngine.doVisibilityChanged(message.arg1 != 0);
641                    break;
642                case MSG_WALLPAPER_OFFSETS: {
643                    mEngine.doOffsetsChanged();
644                } break;
645                case MSG_WINDOW_RESIZED: {
646                    final boolean reportDraw = message.arg1 != 0;
647                    mEngine.updateSurface(true, false);
648                    if (reportDraw) {
649                        try {
650                            mEngine.mSession.finishDrawing(mEngine.mWindow);
651                        } catch (RemoteException e) {
652                        }
653                    }
654                } break;
655                case MSG_TOUCH_EVENT: {
656                    MotionEvent ev = (MotionEvent)message.obj;
657                    synchronized (mEngine.mLock) {
658                        if (mEngine.mPendingMove == ev) {
659                            mEngine.mPendingMove = null;
660                        }
661                    }
662                    mEngine.onTouchEvent(ev);
663                    ev.recycle();
664                } break;
665                default :
666                    Log.w(TAG, "Unknown message type " + message.what);
667            }
668        }
669    }
670
671    /**
672     * Implements the internal {@link IWallpaperService} interface to convert
673     * incoming calls to it back to calls on an {@link WallpaperService}.
674     */
675    class IWallpaperServiceWrapper extends IWallpaperService.Stub {
676        private final WallpaperService mTarget;
677
678        public IWallpaperServiceWrapper(WallpaperService context) {
679            mTarget = context;
680        }
681
682        public void attach(IWallpaperConnection conn, IBinder windowToken,
683                int windowType, boolean isPreview, int reqWidth, int reqHeight) {
684            new IWallpaperEngineWrapper(mTarget, conn, windowToken,
685                    windowType, isPreview, reqWidth, reqHeight);
686        }
687    }
688
689    /**
690     * Implement to return the implementation of the internal accessibility
691     * service interface.  Subclasses should not override.
692     */
693    @Override
694    public final IBinder onBind(Intent intent) {
695        return new IWallpaperServiceWrapper(this);
696    }
697
698    public abstract Engine onCreateEngine();
699}
700