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