OSDN Git Service

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