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