diff options
author | Dianne Hackborn <hackbod@google.com> | 2009-08-08 20:40:27 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2009-08-08 22:13:46 -0700 |
commit | 4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3 (patch) | |
tree | 4bda953a3a1e32695c3c22006dc320b6a0cbcb1b /core/java/android/service | |
parent | 542040c51c49874c92d01381de1b1986cb53b4dd (diff) | |
download | frameworks_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')
4 files changed, 366 insertions, 27 deletions
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl new file mode 100644 index 0000000..b09ccab --- /dev/null +++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.wallpaper; + +import android.os.ParcelFileDescriptor; +import android.service.wallpaper.IWallpaperEngine; + +/** + * @hide + */ +interface IWallpaperConnection { + void attachEngine(IWallpaperEngine engine); + ParcelFileDescriptor setWallpaper(String name); +} diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl new file mode 100644 index 0000000..9586e34 --- /dev/null +++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.wallpaper; + +/** + * @hide + */ +oneway interface IWallpaperEngine { + void destroy(); +} diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl index 97e032b..eb58c3b 100644 --- a/core/java/android/service/wallpaper/IWallpaperService.aidl +++ b/core/java/android/service/wallpaper/IWallpaperService.aidl @@ -16,9 +16,12 @@ package android.service.wallpaper; +import android.service.wallpaper.IWallpaperConnection; + /** * @hide */ oneway interface IWallpaperService { - void onInterrupt(); + void attach(IWallpaperConnection connection, + IBinder windowToken, int reqWidth, int reqHeight); } 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(); } |