summaryrefslogtreecommitdiffstats
path: root/core/java/android/service/wallpaper/WallpaperService.java
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2009-08-08 20:40:27 -0700
committerDianne Hackborn <hackbod@google.com>2009-08-08 22:13:46 -0700
commit4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3 (patch)
tree4bda953a3a1e32695c3c22006dc320b6a0cbcb1b /core/java/android/service/wallpaper/WallpaperService.java
parent542040c51c49874c92d01381de1b1986cb53b4dd (diff)
downloadframeworks_base-4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3.zip
frameworks_base-4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3.tar.gz
frameworks_base-4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3.tar.bz2
Very primitive wallpapers in a surface.
This is all of the basic pieces: - The WallpaperService now creates a surface with the window manager for its contents. - There is a simple service that displays a bitmap. - The wallpaper manager takes care of starting and stopping the service. - The window manager knows about wallpaper windows and how to layer them with the windows that want to be shown on top of wallpaper. Lots and lots of issues remain, but at this point you can actually write a wallpaper service, select it in the UI, and see it behind an activity.
Diffstat (limited to 'core/java/android/service/wallpaper/WallpaperService.java')
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java336
1 files changed, 310 insertions, 26 deletions
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a729ed5..dbec1e6 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -17,17 +17,29 @@
package android.service.wallpaper;
import com.android.internal.os.HandlerCaller;
+import com.android.internal.view.BaseIWindow;
+import com.android.internal.view.BaseSurfaceHolder;
import android.app.Service;
import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.view.Gravity;
+import android.view.IWindowSession;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.ViewRoot;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
/**
* A wallpaper service is responsible for showing a live wallpaper behind
* applications that would like to sit on top of it.
+ * @hide Live Wallpaper
*/
public abstract class WallpaperService extends Service {
/**
@@ -36,48 +48,320 @@ public abstract class WallpaperService extends Service {
public static final String SERVICE_INTERFACE =
"android.service.wallpaper.WallpaperService";
- private static final String LOG_TAG = "WallpaperService";
-
+ static final String TAG = "WallpaperService";
+ static final boolean DEBUG = true;
+
+ private static final int DO_ATTACH = 10;
+ private static final int DO_DETACH = 20;
+
+ private static final int MSG_UPDATE_SURFACE = 10000;
+
/**
- * Implement to return the implementation of the internal accessibility
- * service interface. Subclasses should not override.
+ * The actual implementation of a wallpaper. A wallpaper service may
+ * have multiple instances running (for example as a real wallpaper
+ * and as a preview), each of which is represented by its own Engine
+ * instance.
*/
- @Override
- public final IBinder onBind(Intent intent) {
- return new IWallpaperServiceWrapper(this);
- }
+ public class Engine {
+ IWallpaperEngineWrapper mIWallpaperEngine;
+
+ // Copies from mIWallpaperEngine.
+ HandlerCaller mCaller;
+ IWallpaperConnection mConnection;
+ IBinder mWindowToken;
+
+ boolean mInitializing = true;
+
+ // Current window state.
+ boolean mCreated;
+ boolean mIsCreating;
+ boolean mDrawingAllowed;
+ int mWidth;
+ int mHeight;
+ int mFormat;
+ int mType;
+ boolean mDestroyReportNeeded;
+ final Rect mVisibleInsets = new Rect();
+ final Rect mWinFrame = new Rect();
+ final Rect mContentInsets = new Rect();
+
+ final WindowManager.LayoutParams mLayout
+ = new WindowManager.LayoutParams();
+ IWindowSession mSession;
- /**
- * Implements the internal {@link IWallpaperService} interface to convert
- * incoming calls to it back to calls on an {@link WallpaperService}.
- */
- class IWallpaperServiceWrapper extends IWallpaperService.Stub
- implements HandlerCaller.Callback {
+ final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
+
+ @Override
+ public boolean onAllowLockCanvas() {
+ return mDrawingAllowed;
+ }
+
+ @Override
+ public void onRelayoutContainer() {
+ Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+ mCaller.sendMessage(msg);
+ }
+
+ @Override
+ public void onUpdateSurface() {
+ Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+ mCaller.sendMessage(msg);
+ }
- private static final int DO_ON_INTERRUPT = 10;
+ public boolean isCreating() {
+ return mIsCreating;
+ }
+
+ public void setKeepScreenOn(boolean screenOn) {
+ // Ignore.
+ }
+
+ };
- private final HandlerCaller mCaller;
+ final BaseIWindow mWindow = new BaseIWindow() {
+
+ };
+
+ public void onAttach(SurfaceHolder surfaceHolder) {
+ }
+
+ public void onDetach() {
+ }
+
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ }
- private WallpaperService mTarget;
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ }
- public IWallpaperServiceWrapper(WallpaperService context) {
- mTarget = context;
- mCaller = new HandlerCaller(context, this);
+ public void onSurfaceDestroyed(SurfaceHolder holder) {
}
- public void onInterrupt() {
- Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
- mCaller.sendMessage(message);
+ void updateSurface(boolean force) {
+ int myWidth = mSurfaceHolder.getRequestedWidth();
+ if (myWidth <= 0) myWidth = mIWallpaperEngine.mReqWidth;
+ int myHeight = mSurfaceHolder.getRequestedHeight();
+ if (myHeight <= 0) myHeight = mIWallpaperEngine.mReqHeight;
+
+ final boolean creating = !mCreated;
+ final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
+ final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+ final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
+ if (force || creating || formatChanged || sizeChanged || typeChanged) {
+
+ if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ + " format=" + formatChanged + " size=" + sizeChanged);
+
+ try {
+ mWidth = myWidth;
+ mHeight = myHeight;
+ mFormat = mSurfaceHolder.getRequestedFormat();
+ mType = mSurfaceHolder.getRequestedType();
+
+ // Scaling/Translate window's layout here because mLayout is not used elsewhere.
+
+ // Places the window relative
+ mLayout.x = 0;
+ mLayout.y = 0;
+ mLayout.width = myWidth;
+ mLayout.height = myHeight;
+
+ mLayout.format = mFormat;
+ mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ ;
+
+ mLayout.memoryType = mType;
+ mLayout.token = mWindowToken;
+
+ if (!mCreated) {
+ mLayout.type = WindowManager.LayoutParams.TYPE_WALLPAPER;
+ mLayout.gravity = Gravity.LEFT|Gravity.TOP;
+ mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
+ }
+
+ mSurfaceHolder.mSurfaceLock.lock();
+ mDrawingAllowed = true;
+
+ final int relayoutResult = mSession.relayout(
+ mWindow, mLayout, mWidth, mHeight,
+ View.VISIBLE, false, mWinFrame, mContentInsets,
+ mVisibleInsets, mSurfaceHolder.mSurface);
+
+ if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
+ + ", frame=" + mWinFrame);
+
+ mSurfaceHolder.mSurfaceLock.unlock();
+
+ try {
+ mDestroyReportNeeded = true;
+
+ SurfaceHolder.Callback callbacks[] = null;
+ synchronized (mSurfaceHolder.mCallbacks) {
+ final int N = mSurfaceHolder.mCallbacks.size();
+ if (N > 0) {
+ callbacks = new SurfaceHolder.Callback[N];
+ mSurfaceHolder.mCallbacks.toArray(callbacks);
+ }
+ }
+
+ if (!mCreated) {
+ mIsCreating = true;
+ onSurfaceCreated(mSurfaceHolder);
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceCreated(mSurfaceHolder);
+ }
+ }
+ }
+ if (creating || formatChanged || sizeChanged) {
+ onSurfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight);
+ }
+ }
+ }
+ } finally {
+ mIsCreating = false;
+ mCreated = true;
+ if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ mSession.finishDrawing(mWindow);
+ }
+ }
+ } catch (RemoteException ex) {
+ }
+ if (DEBUG) Log.v(
+ TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
+ " w=" + mLayout.width + " h=" + mLayout.height);
+ }
+ }
+
+ void attach(IWallpaperEngineWrapper wrapper) {
+ mIWallpaperEngine = wrapper;
+ mCaller = wrapper.mCaller;
+ mConnection = wrapper.mConnection;
+ mWindowToken = wrapper.mWindowToken;
+ mSurfaceHolder.setSizeFromLayout();
+ mInitializing = true;
+ mSession = ViewRoot.getWindowSession(getMainLooper());
+ mWindow.setSession(mSession);
+
+ onAttach(mSurfaceHolder);
+
+ mInitializing = false;
+ updateSurface(false);
+ }
+
+ void detach() {
+ onDetach();
+ if (mDestroyReportNeeded) {
+ mDestroyReportNeeded = false;
+ SurfaceHolder.Callback callbacks[];
+ synchronized (mSurfaceHolder.mCallbacks) {
+ callbacks = new SurfaceHolder.Callback[
+ mSurfaceHolder.mCallbacks.size()];
+ mSurfaceHolder.mCallbacks.toArray(callbacks);
+ }
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceDestroyed(mSurfaceHolder);
+ }
+ }
+ if (mCreated) {
+ try {
+ mSession.remove(mWindow);
+ } catch (RemoteException e) {
+ }
+ mSurfaceHolder.mSurface.clear();
+ mCreated = false;
+ }
+ }
+ }
+
+ class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
+ implements HandlerCaller.Callback {
+ private final HandlerCaller mCaller;
+
+ final IWallpaperConnection mConnection;
+ final IBinder mWindowToken;
+ int mReqWidth;
+ int mReqHeight;
+
+ Engine mEngine;
+
+ IWallpaperEngineWrapper(WallpaperService context,
+ IWallpaperConnection conn, IBinder windowToken,
+ int reqWidth, int reqHeight) {
+ mCaller = new HandlerCaller(context, this);
+ mConnection = conn;
+ mWindowToken = windowToken;
+ mReqWidth = reqWidth;
+ mReqHeight = reqHeight;
+
+ try {
+ conn.attachEngine(this);
+ } catch (RemoteException e) {
+ destroy();
+ }
+
+ Message msg = mCaller.obtainMessage(DO_ATTACH);
+ mCaller.sendMessage(msg);
+ }
+
+ public void destroy() {
+ Message msg = mCaller.obtainMessage(DO_DETACH);
+ mCaller.sendMessage(msg);
}
public void executeMessage(Message message) {
switch (message.what) {
- case DO_ON_INTERRUPT :
- //mTarget.onInterrupt();
+ case DO_ATTACH: {
+ Engine engine = onCreateEngine();
+ mEngine = engine;
+ engine.attach(this);
return;
+ }
+ case DO_DETACH: {
+ mEngine.detach();
+ return;
+ }
+ case MSG_UPDATE_SURFACE:
+ mEngine.updateSurface(false);
+ break;
default :
- Log.w(LOG_TAG, "Unknown message type " + message.what);
+ Log.w(TAG, "Unknown message type " + message.what);
}
}
}
+
+ /**
+ * Implements the internal {@link IWallpaperService} interface to convert
+ * incoming calls to it back to calls on an {@link WallpaperService}.
+ */
+ class IWallpaperServiceWrapper extends IWallpaperService.Stub {
+ private final WallpaperService mTarget;
+
+ public IWallpaperServiceWrapper(WallpaperService context) {
+ mTarget = context;
+ }
+
+ public void attach(IWallpaperConnection conn,
+ IBinder windowToken, int reqWidth, int reqHeight) {
+ new IWallpaperEngineWrapper(
+ mTarget, conn, windowToken, reqWidth, reqHeight);
+ }
+ }
+
+ /**
+ * Implement to return the implementation of the internal accessibility
+ * service interface. Subclasses should not override.
+ */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IWallpaperServiceWrapper(this);
+ }
+
+ public abstract Engine onCreateEngine();
}