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