WallpaperService.java revision 8df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bd
16034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty/*
26034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * Copyright (C) 2009 The Android Open Source Project
36034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty *
46034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * Licensed under the Apache License, Version 2.0 (the "License");
56034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * you may not use this file except in compliance with the License.
66034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * You may obtain a copy of the License at
76034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty *
86034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty *      http://www.apache.org/licenses/LICENSE-2.0
96034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty *
106034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * Unless required by applicable law or agreed to in writing, software
116034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * distributed under the License is distributed on an "AS IS" BASIS,
126034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * See the License for the specific language governing permissions and
146034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * limitations under the License.
156034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty */
166034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
176034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertypackage android.service.wallpaper;
186034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
196034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport com.android.internal.os.HandlerCaller;
206034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport com.android.internal.view.BaseIWindow;
216034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport com.android.internal.view.BaseSurfaceHolder;
226034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
236034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.app.Service;
246034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.app.WallpaperManager;
256034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.content.Intent;
266034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.graphics.Rect;
276034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.os.IBinder;
286034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.os.Message;
296034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.os.RemoteException;
306034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.util.Log;
316034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.Gravity;
326034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.IWindowSession;
336034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.MotionEvent;
346034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.SurfaceHolder;
356034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.View;
366034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.ViewGroup;
376034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.ViewRoot;
386034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.WindowManager;
396034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertyimport android.view.WindowManagerImpl;
406034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
416034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty/**
426034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * A wallpaper service is responsible for showing a live wallpaper behind
436034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * applications that would like to sit on top of it.
446034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty * @hide Live Wallpaper
456034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty */
466034230b29d996927ab2f45eb040a2f583bad388Dirk Doughertypublic abstract class WallpaperService extends Service {
476034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    /**
486034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     * The {@link Intent} that must be declared as handled by the service.
496034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     */
506034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    public static final String SERVICE_INTERFACE =
516034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        "android.service.wallpaper.WallpaperService";
526034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
536034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    static final String TAG = "WallpaperService";
546034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    static final boolean DEBUG = false;
556034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
566034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int DO_ATTACH = 10;
576034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int DO_DETACH = 20;
586034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
596034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int MSG_UPDATE_SURFACE = 10000;
606034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int MSG_VISIBILITY_CHANGED = 10010;
616034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int MSG_WALLPAPER_OFFSETS = 10020;
626034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int MSG_WINDOW_RESIZED = 10030;
636034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    private static final int MSG_TOUCH_EVENT = 10040;
646034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
656034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    /**
666034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     * The actual implementation of a wallpaper.  A wallpaper service may
676034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     * have multiple instances running (for example as a real wallpaper
686034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     * and as a preview), each of which is represented by its own Engine
696034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     * instance.  You must implement {@link WallpaperService#onCreateEngine()}
706034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     * to return your concrete Engine implementation.
716034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty     */
726034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty    public class Engine {
736034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        IWallpaperEngineWrapper mIWallpaperEngine;
746034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
756034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        // Copies from mIWallpaperEngine.
766034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        HandlerCaller mCaller;
776034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        IWallpaperConnection mConnection;
786034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        IBinder mWindowToken;
796034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
806034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        boolean mInitializing = true;
816034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
826034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        // Current window state.
836034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        boolean mCreated;
846034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        boolean mIsCreating;
856034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        boolean mDrawingAllowed;
866034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mWidth;
876034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mHeight;
886034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mFormat;
896034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mType;
906034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mCurWidth;
916034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mCurHeight;
926034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
936034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        int mCurWindowFlags = mWindowFlags;
946034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        boolean mDestroyReportNeeded;
956034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        final Rect mVisibleInsets = new Rect();
966034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        final Rect mWinFrame = new Rect();
976034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        final Rect mContentInsets = new Rect();
986034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
996034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        final WindowManager.LayoutParams mLayout
1006034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty                = new WindowManager.LayoutParams();
1016034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        IWindowSession mSession;
1026034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
1036034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        final Object mLock = new Object();
1046034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        boolean mOffsetMessageEnqueued;
1056034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        float mPendingXOffset;
1066034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        float mPendingYOffset;
1076034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        MotionEvent mPendingMove;
1086034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
1096034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty        final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
1106034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
1116034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            @Override
1126034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            public boolean onAllowLockCanvas() {
1136034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty                return mDrawingAllowed;
1146034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            }
1156034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
1166034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            @Override
1176034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            public void onRelayoutContainer() {
1186034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty                Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
1196034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty                mCaller.sendMessage(msg);
1206034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            }
1216034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty
1226034230b29d996927ab2f45eb040a2f583bad388Dirk Dougherty            @Override
123            public void onUpdateSurface() {
124                Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
125                mCaller.sendMessage(msg);
126            }
127
128            public boolean isCreating() {
129                return mIsCreating;
130            }
131
132            public void setKeepScreenOn(boolean screenOn) {
133                // Ignore.
134            }
135
136        };
137
138        final BaseIWindow mWindow = new BaseIWindow() {
139            @Override
140            public boolean onDispatchPointer(MotionEvent event, long eventTime,
141                    boolean callWhenDone) {
142                synchronized (mLock) {
143                    if (event.getAction() == MotionEvent.ACTION_MOVE) {
144                        if (mPendingMove != null) {
145                            mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
146                            mPendingMove.recycle();
147                        }
148                        mPendingMove = event;
149                    } else {
150                        mPendingMove = null;
151                    }
152                    Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
153                            event);
154                    mCaller.sendMessage(msg);
155                }
156                return false;
157            }
158
159            @Override
160            public void resized(int w, int h, Rect coveredInsets,
161                    Rect visibleInsets, boolean reportDraw) {
162                Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
163                        reportDraw ? 1 : 0);
164                mCaller.sendMessage(msg);
165            }
166
167            @Override
168            public void dispatchAppVisibility(boolean visible) {
169                Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
170                        visible ? 1 : 0);
171                mCaller.sendMessage(msg);
172            }
173
174            @Override
175            public void dispatchWallpaperOffsets(float x, float y) {
176                synchronized (mLock) {
177                    mPendingXOffset = x;
178                    mPendingYOffset = y;
179                    if (!mOffsetMessageEnqueued) {
180                        mOffsetMessageEnqueued = true;
181                        Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
182                        mCaller.sendMessage(msg);
183                    }
184                }
185            }
186
187        };
188
189        /**
190         * Provides access to the surface in which this wallpaper is drawn.
191         */
192        public SurfaceHolder getSurfaceHolder() {
193            return mSurfaceHolder;
194        }
195
196        /**
197         * Convenience for {@link WallpaperManager#getDesiredMinimumWidth()
198         * WallpaperManager.getDesiredMinimumWidth()}, returning the width
199         * that the system would like this wallpaper to run in.
200         */
201        public int getDesiredMinimumWidth() {
202            return mIWallpaperEngine.mReqWidth;
203        }
204
205        /**
206         * Convenience for {@link WallpaperManager#getDesiredMinimumHeight()
207         * WallpaperManager.getDesiredMinimumHeight()}, returning the height
208         * that the system would like this wallpaper to run in.
209         */
210        public int getDesiredMinimumHeight() {
211            return mIWallpaperEngine.mReqHeight;
212        }
213
214        /**
215         * Control whether this wallpaper will receive raw touch events
216         * from the window manager as the user interacts with the window
217         * that is currently displaying the wallpaper.  By default they
218         * are turned off.  If enabled, the events will be received in
219         * {@link #onTouchEvent(MotionEvent)}.
220         */
221        public void setTouchEventsEnabled(boolean enabled) {
222            mWindowFlags = enabled
223                    ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
224                    : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
225            if (mCreated) {
226                updateSurface(false);
227            }
228        }
229
230        /**
231         * Called once to initialize the engine.  After returning, the
232         * engine's surface will be created by the framework.
233         */
234        public void onCreate(SurfaceHolder surfaceHolder) {
235        }
236
237        /**
238         * Called right before the engine is going away.  After this the
239         * surface will be destroyed and this Engine object is no longer
240         * valid.
241         */
242        public void onDestroy() {
243        }
244
245        /**
246         * Called to inform you of the wallpaper becoming visible or
247         * hidden.  <em>It is very important that a wallpaper only use
248         * CPU while it is visible.</em>.
249         */
250        public void onVisibilityChanged(boolean visible) {
251        }
252
253        /**
254         * Called as the user performs touch-screen interaction with the
255         * window that is currently showing this wallpaper.  Note that the
256         * events you receive here are driven by the actual application the
257         * user is interacting with, so if it is slow you will get viewer
258         * move events.
259         */
260        public void onTouchEvent(MotionEvent event) {
261        }
262
263        /**
264         * Called to inform you of the wallpaper's offsets changing
265         * within its contain, corresponding to the container's
266         * call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float)
267         * WallpaperManager.setWallpaperOffsets()}.
268         */
269        public void onOffsetsChanged(float xOffset, float yOffset,
270                int xPixelOffset, int yPixelOffset) {
271        }
272
273        /**
274         * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
275         * SurfaceHolder.Callback.surfaceChanged()}.
276         */
277        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
278        }
279
280        /**
281         * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
282         * SurfaceHolder.Callback.surfaceCreated()}.
283         */
284        public void onSurfaceCreated(SurfaceHolder holder) {
285        }
286
287        /**
288         * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed
289         * SurfaceHolder.Callback.surfaceDestroyed()}.
290         */
291        public void onSurfaceDestroyed(SurfaceHolder holder) {
292        }
293
294        void updateSurface(boolean force) {
295            int myWidth = mSurfaceHolder.getRequestedWidth();
296            if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
297            int myHeight = mSurfaceHolder.getRequestedHeight();
298            if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.FILL_PARENT;
299
300            final boolean creating = !mCreated;
301            final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
302            boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
303            final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
304            final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
305            if (force || creating || formatChanged || sizeChanged || typeChanged
306                    || flagsChanged) {
307
308                if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
309                        + " format=" + formatChanged + " size=" + sizeChanged);
310
311                try {
312                    mWidth = myWidth;
313                    mHeight = myHeight;
314                    mFormat = mSurfaceHolder.getRequestedFormat();
315                    mType = mSurfaceHolder.getRequestedType();
316
317                    mLayout.x = 0;
318                    mLayout.y = 0;
319                    mLayout.width = myWidth;
320                    mLayout.height = myHeight;
321
322                    mLayout.format = mFormat;
323
324                    mCurWindowFlags = mWindowFlags;
325                    mLayout.flags = mWindowFlags
326                            | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
327                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
328                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
329                            ;
330
331                    mLayout.memoryType = mType;
332                    mLayout.token = mWindowToken;
333
334                    if (!mCreated) {
335                        mLayout.type = WindowManager.LayoutParams.TYPE_WALLPAPER;
336                        mLayout.gravity = Gravity.LEFT|Gravity.TOP;
337                        mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
338                    }
339
340                    mSurfaceHolder.mSurfaceLock.lock();
341                    mDrawingAllowed = true;
342
343                    final int relayoutResult = mSession.relayout(
344                        mWindow, mLayout, mWidth, mHeight,
345                            View.VISIBLE, false, mWinFrame, mContentInsets,
346                            mVisibleInsets, mSurfaceHolder.mSurface);
347
348                    if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
349                            + ", frame=" + mWinFrame);
350
351                    int w = mWinFrame.width();
352                    if (mCurWidth != w) {
353                        sizeChanged = true;
354                        mCurWidth = w;
355                    }
356                    int h = mWinFrame.height();
357                    if (mCurHeight != h) {
358                        sizeChanged = true;
359                        mCurHeight = h;
360                    }
361
362                    mSurfaceHolder.mSurfaceLock.unlock();
363
364                    try {
365                        mDestroyReportNeeded = true;
366
367                        SurfaceHolder.Callback callbacks[] = null;
368                        synchronized (mSurfaceHolder.mCallbacks) {
369                            final int N = mSurfaceHolder.mCallbacks.size();
370                            if (N > 0) {
371                                callbacks = new SurfaceHolder.Callback[N];
372                                mSurfaceHolder.mCallbacks.toArray(callbacks);
373                            }
374                        }
375
376                        if (!mCreated) {
377                            mIsCreating = true;
378                            onSurfaceCreated(mSurfaceHolder);
379                            if (callbacks != null) {
380                                for (SurfaceHolder.Callback c : callbacks) {
381                                    c.surfaceCreated(mSurfaceHolder);
382                                }
383                            }
384                        }
385                        if (force || creating || formatChanged || sizeChanged) {
386                            onSurfaceChanged(mSurfaceHolder, mFormat,
387                                    mCurWidth, mCurHeight);
388                            if (callbacks != null) {
389                                for (SurfaceHolder.Callback c : callbacks) {
390                                    c.surfaceChanged(mSurfaceHolder, mFormat,
391                                            mCurWidth, mCurHeight);
392                                }
393                            }
394                        }
395                    } finally {
396                        mIsCreating = false;
397                        mCreated = true;
398                        if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
399                            mSession.finishDrawing(mWindow);
400                        }
401                    }
402                } catch (RemoteException ex) {
403                }
404                if (DEBUG) Log.v(
405                    TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
406                    " w=" + mLayout.width + " h=" + mLayout.height);
407            }
408        }
409
410        void attach(IWallpaperEngineWrapper wrapper) {
411            mIWallpaperEngine = wrapper;
412            mCaller = wrapper.mCaller;
413            mConnection = wrapper.mConnection;
414            mWindowToken = wrapper.mWindowToken;
415            // XXX temp -- should run in size from layout (screen) mode.
416            mSurfaceHolder.setFixedSize(mIWallpaperEngine.mReqWidth,
417                    mIWallpaperEngine.mReqHeight);
418            //mSurfaceHolder.setSizeFromLayout();
419            mInitializing = true;
420            mSession = ViewRoot.getWindowSession(getMainLooper());
421            mWindow.setSession(mSession);
422
423            onCreate(mSurfaceHolder);
424
425            mInitializing = false;
426            updateSurface(false);
427        }
428
429        void detach() {
430            onDestroy();
431            if (mDestroyReportNeeded) {
432                mDestroyReportNeeded = false;
433                SurfaceHolder.Callback callbacks[];
434                synchronized (mSurfaceHolder.mCallbacks) {
435                    callbacks = new SurfaceHolder.Callback[
436                            mSurfaceHolder.mCallbacks.size()];
437                    mSurfaceHolder.mCallbacks.toArray(callbacks);
438                }
439                for (SurfaceHolder.Callback c : callbacks) {
440                    c.surfaceDestroyed(mSurfaceHolder);
441                }
442            }
443            if (mCreated) {
444                try {
445                    mSession.remove(mWindow);
446                } catch (RemoteException e) {
447                }
448                mSurfaceHolder.mSurface.clear();
449                mCreated = false;
450            }
451        }
452    }
453
454    class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
455            implements HandlerCaller.Callback {
456        private final HandlerCaller mCaller;
457
458        final IWallpaperConnection mConnection;
459        final IBinder mWindowToken;
460        int mReqWidth;
461        int mReqHeight;
462
463        Engine mEngine;
464
465        IWallpaperEngineWrapper(WallpaperService context,
466                IWallpaperConnection conn, IBinder windowToken,
467                int reqWidth, int reqHeight) {
468            mCaller = new HandlerCaller(context, this);
469            mConnection = conn;
470            mWindowToken = windowToken;
471            mReqWidth = reqWidth;
472            mReqHeight = reqHeight;
473
474            try {
475                conn.attachEngine(this);
476            } catch (RemoteException e) {
477                destroy();
478            }
479
480            Message msg = mCaller.obtainMessage(DO_ATTACH);
481            mCaller.sendMessage(msg);
482        }
483
484        public void destroy() {
485            Message msg = mCaller.obtainMessage(DO_DETACH);
486            mCaller.sendMessage(msg);
487        }
488
489        public void executeMessage(Message message) {
490            switch (message.what) {
491                case DO_ATTACH: {
492                    Engine engine = onCreateEngine();
493                    mEngine = engine;
494                    engine.attach(this);
495                    return;
496                }
497                case DO_DETACH: {
498                    mEngine.detach();
499                    return;
500                }
501                case MSG_UPDATE_SURFACE:
502                    mEngine.updateSurface(false);
503                    break;
504                case MSG_VISIBILITY_CHANGED:
505                    if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
506                            + ": " + message.arg1);
507                    mEngine.onVisibilityChanged(message.arg1 != 0);
508                    break;
509                case MSG_WALLPAPER_OFFSETS: {
510                    float xOffset;
511                    float yOffset;
512                    synchronized (mEngine.mLock) {
513                        xOffset = mEngine.mPendingXOffset;
514                        yOffset = mEngine.mPendingYOffset;
515                        mEngine.mOffsetMessageEnqueued = false;
516                    }
517                    if (DEBUG) Log.v(TAG, "Offsets change in " + mEngine
518                            + ": " + xOffset + "," + yOffset);
519                    final int availw = mReqWidth-mEngine.mCurWidth;
520                    final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
521                    final int availh = mReqHeight-mEngine.mCurHeight;
522                    final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
523                    mEngine.onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
524                } break;
525                case MSG_WINDOW_RESIZED: {
526                    final boolean reportDraw = message.arg1 != 0;
527                    mEngine.updateSurface(true);
528                    if (reportDraw) {
529                        try {
530                            mEngine.mSession.finishDrawing(mEngine.mWindow);
531                        } catch (RemoteException e) {
532                        }
533                    }
534                } break;
535                case MSG_TOUCH_EVENT: {
536                    MotionEvent ev = (MotionEvent)message.obj;
537                    synchronized (mEngine.mLock) {
538                        if (mEngine.mPendingMove == ev) {
539                            mEngine.mPendingMove = null;
540                        }
541                    }
542                    mEngine.onTouchEvent(ev);
543                    ev.recycle();
544                } break;
545                default :
546                    Log.w(TAG, "Unknown message type " + message.what);
547            }
548        }
549    }
550
551    /**
552     * Implements the internal {@link IWallpaperService} interface to convert
553     * incoming calls to it back to calls on an {@link WallpaperService}.
554     */
555    class IWallpaperServiceWrapper extends IWallpaperService.Stub {
556        private final WallpaperService mTarget;
557
558        public IWallpaperServiceWrapper(WallpaperService context) {
559            mTarget = context;
560        }
561
562        public void attach(IWallpaperConnection conn,
563                IBinder windowToken, int reqWidth, int reqHeight) {
564            new IWallpaperEngineWrapper(
565                    mTarget, conn, windowToken, reqWidth, reqHeight);
566        }
567    }
568
569    /**
570     * Implement to return the implementation of the internal accessibility
571     * service interface.  Subclasses should not override.
572     */
573    @Override
574    public final IBinder onBind(Intent intent) {
575        return new IWallpaperServiceWrapper(this);
576    }
577
578    public abstract Engine onCreateEngine();
579}
580