WallpaperService.java revision 4c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3
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 17package android.service.wallpaper; 18 19import com.android.internal.os.HandlerCaller; 20import com.android.internal.view.BaseIWindow; 21import com.android.internal.view.BaseSurfaceHolder; 22 23import android.app.Service; 24import android.content.Intent; 25import android.graphics.Rect; 26import android.os.Handler; 27import android.os.IBinder; 28import android.os.Message; 29import android.os.RemoteException; 30import android.util.Log; 31import android.view.Gravity; 32import android.view.IWindowSession; 33import android.view.SurfaceHolder; 34import android.view.View; 35import android.view.ViewRoot; 36import android.view.WindowManager; 37import android.view.WindowManagerImpl; 38 39/** 40 * A wallpaper service is responsible for showing a live wallpaper behind 41 * applications that would like to sit on top of it. 42 * @hide Live Wallpaper 43 */ 44public abstract class WallpaperService extends Service { 45 /** 46 * The {@link Intent} that must be declared as handled by the service. 47 */ 48 public static final String SERVICE_INTERFACE = 49 "android.service.wallpaper.WallpaperService"; 50 51 static final String TAG = "WallpaperService"; 52 static final boolean DEBUG = true; 53 54 private static final int DO_ATTACH = 10; 55 private static final int DO_DETACH = 20; 56 57 private static final int MSG_UPDATE_SURFACE = 10000; 58 59 /** 60 * The actual implementation of a wallpaper. A wallpaper service may 61 * have multiple instances running (for example as a real wallpaper 62 * and as a preview), each of which is represented by its own Engine 63 * instance. 64 */ 65 public class Engine { 66 IWallpaperEngineWrapper mIWallpaperEngine; 67 68 // Copies from mIWallpaperEngine. 69 HandlerCaller mCaller; 70 IWallpaperConnection mConnection; 71 IBinder mWindowToken; 72 73 boolean mInitializing = true; 74 75 // Current window state. 76 boolean mCreated; 77 boolean mIsCreating; 78 boolean mDrawingAllowed; 79 int mWidth; 80 int mHeight; 81 int mFormat; 82 int mType; 83 boolean mDestroyReportNeeded; 84 final Rect mVisibleInsets = new Rect(); 85 final Rect mWinFrame = new Rect(); 86 final Rect mContentInsets = new Rect(); 87 88 final WindowManager.LayoutParams mLayout 89 = new WindowManager.LayoutParams(); 90 IWindowSession mSession; 91 92 final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { 93 94 @Override 95 public boolean onAllowLockCanvas() { 96 return mDrawingAllowed; 97 } 98 99 @Override 100 public void onRelayoutContainer() { 101 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 102 mCaller.sendMessage(msg); 103 } 104 105 @Override 106 public void onUpdateSurface() { 107 Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE); 108 mCaller.sendMessage(msg); 109 } 110 111 public boolean isCreating() { 112 return mIsCreating; 113 } 114 115 public void setKeepScreenOn(boolean screenOn) { 116 // Ignore. 117 } 118 119 }; 120 121 final BaseIWindow mWindow = new BaseIWindow() { 122 123 }; 124 125 public void onAttach(SurfaceHolder surfaceHolder) { 126 } 127 128 public void onDetach() { 129 } 130 131 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 132 } 133 134 public void onSurfaceCreated(SurfaceHolder holder) { 135 } 136 137 public void onSurfaceDestroyed(SurfaceHolder holder) { 138 } 139 140 void updateSurface(boolean force) { 141 int myWidth = mSurfaceHolder.getRequestedWidth(); 142 if (myWidth <= 0) myWidth = mIWallpaperEngine.mReqWidth; 143 int myHeight = mSurfaceHolder.getRequestedHeight(); 144 if (myHeight <= 0) myHeight = mIWallpaperEngine.mReqHeight; 145 146 final boolean creating = !mCreated; 147 final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat(); 148 final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; 149 final boolean typeChanged = mType != mSurfaceHolder.getRequestedType(); 150 if (force || creating || formatChanged || sizeChanged || typeChanged) { 151 152 if (DEBUG) Log.i(TAG, "Changes: creating=" + creating 153 + " format=" + formatChanged + " size=" + sizeChanged); 154 155 try { 156 mWidth = myWidth; 157 mHeight = myHeight; 158 mFormat = mSurfaceHolder.getRequestedFormat(); 159 mType = mSurfaceHolder.getRequestedType(); 160 161 // Scaling/Translate window's layout here because mLayout is not used elsewhere. 162 163 // Places the window relative 164 mLayout.x = 0; 165 mLayout.y = 0; 166 mLayout.width = myWidth; 167 mLayout.height = myHeight; 168 169 mLayout.format = mFormat; 170 mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 171 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 172 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 173 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 174 ; 175 176 mLayout.memoryType = mType; 177 mLayout.token = mWindowToken; 178 179 if (!mCreated) { 180 mLayout.type = WindowManager.LayoutParams.TYPE_WALLPAPER; 181 mLayout.gravity = Gravity.LEFT|Gravity.TOP; 182 mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets); 183 } 184 185 mSurfaceHolder.mSurfaceLock.lock(); 186 mDrawingAllowed = true; 187 188 final int relayoutResult = mSession.relayout( 189 mWindow, mLayout, mWidth, mHeight, 190 View.VISIBLE, false, mWinFrame, mContentInsets, 191 mVisibleInsets, mSurfaceHolder.mSurface); 192 193 if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface 194 + ", frame=" + mWinFrame); 195 196 mSurfaceHolder.mSurfaceLock.unlock(); 197 198 try { 199 mDestroyReportNeeded = true; 200 201 SurfaceHolder.Callback callbacks[] = null; 202 synchronized (mSurfaceHolder.mCallbacks) { 203 final int N = mSurfaceHolder.mCallbacks.size(); 204 if (N > 0) { 205 callbacks = new SurfaceHolder.Callback[N]; 206 mSurfaceHolder.mCallbacks.toArray(callbacks); 207 } 208 } 209 210 if (!mCreated) { 211 mIsCreating = true; 212 onSurfaceCreated(mSurfaceHolder); 213 if (callbacks != null) { 214 for (SurfaceHolder.Callback c : callbacks) { 215 c.surfaceCreated(mSurfaceHolder); 216 } 217 } 218 } 219 if (creating || formatChanged || sizeChanged) { 220 onSurfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight); 221 if (callbacks != null) { 222 for (SurfaceHolder.Callback c : callbacks) { 223 c.surfaceChanged(mSurfaceHolder, mFormat, mWidth, mHeight); 224 } 225 } 226 } 227 } finally { 228 mIsCreating = false; 229 mCreated = true; 230 if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { 231 mSession.finishDrawing(mWindow); 232 } 233 } 234 } catch (RemoteException ex) { 235 } 236 if (DEBUG) Log.v( 237 TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + 238 " w=" + mLayout.width + " h=" + mLayout.height); 239 } 240 } 241 242 void attach(IWallpaperEngineWrapper wrapper) { 243 mIWallpaperEngine = wrapper; 244 mCaller = wrapper.mCaller; 245 mConnection = wrapper.mConnection; 246 mWindowToken = wrapper.mWindowToken; 247 mSurfaceHolder.setSizeFromLayout(); 248 mInitializing = true; 249 mSession = ViewRoot.getWindowSession(getMainLooper()); 250 mWindow.setSession(mSession); 251 252 onAttach(mSurfaceHolder); 253 254 mInitializing = false; 255 updateSurface(false); 256 } 257 258 void detach() { 259 onDetach(); 260 if (mDestroyReportNeeded) { 261 mDestroyReportNeeded = false; 262 SurfaceHolder.Callback callbacks[]; 263 synchronized (mSurfaceHolder.mCallbacks) { 264 callbacks = new SurfaceHolder.Callback[ 265 mSurfaceHolder.mCallbacks.size()]; 266 mSurfaceHolder.mCallbacks.toArray(callbacks); 267 } 268 for (SurfaceHolder.Callback c : callbacks) { 269 c.surfaceDestroyed(mSurfaceHolder); 270 } 271 } 272 if (mCreated) { 273 try { 274 mSession.remove(mWindow); 275 } catch (RemoteException e) { 276 } 277 mSurfaceHolder.mSurface.clear(); 278 mCreated = false; 279 } 280 } 281 } 282 283 class IWallpaperEngineWrapper extends IWallpaperEngine.Stub 284 implements HandlerCaller.Callback { 285 private final HandlerCaller mCaller; 286 287 final IWallpaperConnection mConnection; 288 final IBinder mWindowToken; 289 int mReqWidth; 290 int mReqHeight; 291 292 Engine mEngine; 293 294 IWallpaperEngineWrapper(WallpaperService context, 295 IWallpaperConnection conn, IBinder windowToken, 296 int reqWidth, int reqHeight) { 297 mCaller = new HandlerCaller(context, this); 298 mConnection = conn; 299 mWindowToken = windowToken; 300 mReqWidth = reqWidth; 301 mReqHeight = reqHeight; 302 303 try { 304 conn.attachEngine(this); 305 } catch (RemoteException e) { 306 destroy(); 307 } 308 309 Message msg = mCaller.obtainMessage(DO_ATTACH); 310 mCaller.sendMessage(msg); 311 } 312 313 public void destroy() { 314 Message msg = mCaller.obtainMessage(DO_DETACH); 315 mCaller.sendMessage(msg); 316 } 317 318 public void executeMessage(Message message) { 319 switch (message.what) { 320 case DO_ATTACH: { 321 Engine engine = onCreateEngine(); 322 mEngine = engine; 323 engine.attach(this); 324 return; 325 } 326 case DO_DETACH: { 327 mEngine.detach(); 328 return; 329 } 330 case MSG_UPDATE_SURFACE: 331 mEngine.updateSurface(false); 332 break; 333 default : 334 Log.w(TAG, "Unknown message type " + message.what); 335 } 336 } 337 } 338 339 /** 340 * Implements the internal {@link IWallpaperService} interface to convert 341 * incoming calls to it back to calls on an {@link WallpaperService}. 342 */ 343 class IWallpaperServiceWrapper extends IWallpaperService.Stub { 344 private final WallpaperService mTarget; 345 346 public IWallpaperServiceWrapper(WallpaperService context) { 347 mTarget = context; 348 } 349 350 public void attach(IWallpaperConnection conn, 351 IBinder windowToken, int reqWidth, int reqHeight) { 352 new IWallpaperEngineWrapper( 353 mTarget, conn, windowToken, reqWidth, reqHeight); 354 } 355 } 356 357 /** 358 * Implement to return the implementation of the internal accessibility 359 * service interface. Subclasses should not override. 360 */ 361 @Override 362 public final IBinder onBind(Intent intent) { 363 return new IWallpaperServiceWrapper(this); 364 } 365 366 public abstract Engine onCreateEngine(); 367} 368