WallpaperManager.java revision 72c82ab9923025a91bbabb32e56bfea27bfd083b
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.app; 18 19import android.content.Context; 20import android.content.Intent; 21import android.content.res.Resources; 22import android.graphics.Bitmap; 23import android.graphics.BitmapFactory; 24import android.graphics.drawable.BitmapDrawable; 25import android.graphics.drawable.Drawable; 26import android.os.Handler; 27import android.os.IBinder; 28import android.os.ParcelFileDescriptor; 29import android.os.RemoteException; 30import android.os.ServiceManager; 31import android.view.ViewRoot; 32 33import java.io.FileOutputStream; 34import java.io.IOException; 35import java.io.InputStream; 36 37public class WallpaperManager { 38 private static String TAG = "WallpaperManager"; 39 private static boolean DEBUG = false; 40 41 /** 42 * Launch an activity for the user to pick the current global live 43 * wallpaper. 44 * @hide 45 */ 46 public static final String ACTION_LIVE_WALLPAPER_CHOOSER 47 = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER"; 48 49 private final Context mContext; 50 51 static class Globals extends IWallpaperManagerCallback.Stub { 52 private IWallpaperManager mService; 53 private Drawable mWallpaper; 54 55 Globals() { 56 IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE); 57 mService = IWallpaperManager.Stub.asInterface(b); 58 } 59 60 public void onWallpaperChanged() { 61 /* The wallpaper has changed but we shouldn't eagerly load the 62 * wallpaper as that would be inefficient. Reset the cached wallpaper 63 * to null so if the user requests the wallpaper again then we'll 64 * fetch it. 65 */ 66 synchronized (this) { 67 mWallpaper = null; 68 } 69 } 70 71 public Drawable peekWallpaper(Context context) { 72 synchronized (this) { 73 if (mWallpaper != null) { 74 return mWallpaper; 75 } 76 mWallpaper = getCurrentWallpaperLocked(context); 77 return mWallpaper; 78 } 79 } 80 81 private Drawable getCurrentWallpaperLocked(Context context) { 82 try { 83 ParcelFileDescriptor fd = mService.getWallpaper(this); 84 if (fd != null) { 85 Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor()); 86 if (bm != null) { 87 // For now clear the density until we figure out how 88 // to deal with it for wallpapers. 89 bm.setDensity(0); 90 return new BitmapDrawable(context.getResources(), bm); 91 } 92 } 93 } catch (RemoteException e) { 94 } 95 return null; 96 } 97 } 98 99 private static Object mSync = new Object(); 100 private static Globals sGlobals; 101 102 static Globals getGlobals() { 103 synchronized (mSync) { 104 if (sGlobals == null) { 105 sGlobals = new Globals(); 106 } 107 return sGlobals; 108 } 109 } 110 111 /*package*/ WallpaperManager(Context context, Handler handler) { 112 mContext = context; 113 } 114 115 /** 116 * Retrieve a WallpaperManager associated with the given Context. 117 */ 118 public static WallpaperManager getInstance(Context context) { 119 return (WallpaperManager)context.getSystemService( 120 Context.WALLPAPER_SERVICE); 121 } 122 123 /** @hide */ 124 public IWallpaperManager getIWallpaperManager() { 125 return getGlobals().mService; 126 } 127 128 /** 129 * Like {@link #peekDrawable}, but always returns a valid Drawable. If 130 * no wallpaper is set, the system default wallpaper is returned. 131 * 132 * @return Returns a Drawable object that will draw the wallpaper. 133 */ 134 public Drawable getDrawable() { 135 Drawable dr = peekDrawable(); 136 return dr != null ? dr : Resources.getSystem().getDrawable( 137 com.android.internal.R.drawable.default_wallpaper); 138 } 139 140 /** 141 * Retrieve the current system wallpaper. This is returned as an 142 * abstract Drawable that you can install in a View to display whatever 143 * wallpaper the user has currently set. If there is no wallpaper set, 144 * a null pointer is returned. 145 * 146 * @return Returns a Drawable object that will draw the wallpaper or a 147 * null pointer if these is none. 148 */ 149 public Drawable peekDrawable() { 150 return getGlobals().peekWallpaper(mContext); 151 } 152 153 /** 154 * Change the current system wallpaper to the bitmap in the given resource. 155 * The resource is opened as a raw data stream and copied into the 156 * wallpaper; it must be a valid PNG or JPEG image. On success, the intent 157 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast. 158 * 159 * @param resid The bitmap to save. 160 * 161 * @throws IOException If an error occurs reverting to the default 162 * wallpaper. 163 */ 164 public void setResource(int resid) throws IOException { 165 try { 166 Resources resources = mContext.getResources(); 167 /* Set the wallpaper to the default values */ 168 ParcelFileDescriptor fd = getGlobals().mService.setWallpaper( 169 "res:" + resources.getResourceName(resid)); 170 if (fd != null) { 171 FileOutputStream fos = null; 172 try { 173 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); 174 setWallpaper(resources.openRawResource(resid), fos); 175 } finally { 176 if (fos != null) { 177 fos.close(); 178 } 179 } 180 } 181 } catch (RemoteException e) { 182 } 183 } 184 185 /** 186 * Change the current system wallpaper to a bitmap. The given bitmap is 187 * converted to a PNG and stored as the wallpaper. On success, the intent 188 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast. 189 * 190 * @param bitmap The bitmap to save. 191 * 192 * @throws IOException If an error occurs reverting to the default 193 * wallpaper. 194 */ 195 public void setBitmap(Bitmap bitmap) throws IOException { 196 try { 197 ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null); 198 if (fd == null) { 199 return; 200 } 201 FileOutputStream fos = null; 202 try { 203 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); 204 bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos); 205 } finally { 206 if (fos != null) { 207 fos.close(); 208 } 209 } 210 } catch (RemoteException e) { 211 } 212 } 213 214 /** 215 * Change the current system wallpaper to a specific byte stream. The 216 * give InputStream is copied into persistent storage and will now be 217 * used as the wallpaper. Currently it must be either a JPEG or PNG 218 * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} 219 * is broadcast. 220 * 221 * @param data A stream containing the raw data to install as a wallpaper. 222 * 223 * @throws IOException If an error occurs reverting to the default 224 * wallpaper. 225 */ 226 public void setStream(InputStream data) throws IOException { 227 try { 228 ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null); 229 if (fd == null) { 230 return; 231 } 232 FileOutputStream fos = null; 233 try { 234 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); 235 setWallpaper(data, fos); 236 } finally { 237 if (fos != null) { 238 fos.close(); 239 } 240 } 241 } catch (RemoteException e) { 242 } 243 } 244 245 private void setWallpaper(InputStream data, FileOutputStream fos) 246 throws IOException { 247 byte[] buffer = new byte[32768]; 248 int amt; 249 while ((amt=data.read(buffer)) > 0) { 250 fos.write(buffer, 0, amt); 251 } 252 } 253 254 /** 255 * Returns the desired minimum width for the wallpaper. Callers of 256 * {@link #setBitmap(android.graphics.Bitmap)} or 257 * {@link #setStream(java.io.InputStream)} should check this value 258 * beforehand to make sure the supplied wallpaper respects the desired 259 * minimum width. 260 * 261 * If the returned value is <= 0, the caller should use the width of 262 * the default display instead. 263 * 264 * @return The desired minimum width for the wallpaper. This value should 265 * be honored by applications that set the wallpaper but it is not 266 * mandatory. 267 */ 268 public int getDesiredMinimumWidth() { 269 try { 270 return getGlobals().mService.getWidthHint(); 271 } catch (RemoteException e) { 272 // Shouldn't happen! 273 return 0; 274 } 275 } 276 277 /** 278 * Returns the desired minimum height for the wallpaper. Callers of 279 * {@link #setBitmap(android.graphics.Bitmap)} or 280 * {@link #setStream(java.io.InputStream)} should check this value 281 * beforehand to make sure the supplied wallpaper respects the desired 282 * minimum height. 283 * 284 * If the returned value is <= 0, the caller should use the height of 285 * the default display instead. 286 * 287 * @return The desired minimum height for the wallpaper. This value should 288 * be honored by applications that set the wallpaper but it is not 289 * mandatory. 290 */ 291 public int getDesiredMinimumHeight() { 292 try { 293 return getGlobals().mService.getHeightHint(); 294 } catch (RemoteException e) { 295 // Shouldn't happen! 296 return 0; 297 } 298 } 299 300 /** 301 * For use only by the current home application, to specify the size of 302 * wallpaper it would like to use. This allows such applications to have 303 * a virtual wallpaper that is larger than the physical screen, matching 304 * the size of their workspace. 305 * @param minimumWidth Desired minimum width 306 * @param minimumHeight Desired minimum height 307 */ 308 public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) { 309 try { 310 getGlobals().mService.setDimensionHints(minimumWidth, minimumHeight); 311 } catch (RemoteException e) { 312 } 313 } 314 315 /** 316 * Set the position of the current wallpaper within any larger space, when 317 * that wallpaper is visible behind the given window. The X and Y offsets 318 * are floating point numbers ranging from 0 to 1, representing where the 319 * wallpaper should be positioned within the screen space. These only 320 * make sense when the wallpaper is larger than the screen. 321 * 322 * @param windowToken The window who these offsets should be associated 323 * with, as returned by {@link android.view.View#getWindowVisibility() 324 * View.getWindowToken()}. 325 * @param xOffset The offset olong the X dimension, from 0 to 1. 326 * @param yOffset The offset along the Y dimension, from 0 to 1. 327 */ 328 public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) { 329 try { 330 ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition( 331 windowToken, xOffset, yOffset); 332 } catch (RemoteException e) { 333 // Ignore. 334 } 335 } 336 337 /** 338 * Clear the offsets previously associated with this window through 339 * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts 340 * the window to its default state, where it does not cause the wallpaper 341 * to scroll from whatever its last offsets were. 342 * 343 * @param windowToken The window who these offsets should be associated 344 * with, as returned by {@link android.view.View#getWindowVisibility() 345 * View.getWindowToken()}. 346 */ 347 public void clearWallpaperOffsets(IBinder windowToken) { 348 try { 349 ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition( 350 windowToken, -1, -1); 351 } catch (RemoteException e) { 352 // Ignore. 353 } 354 } 355 356 /** 357 * Remove any currently set wallpaper, reverting to the system's default 358 * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} 359 * is broadcast. 360 * 361 * @throws IOException If an error occurs reverting to the default 362 * wallpaper. 363 */ 364 public void clear() throws IOException { 365 setResource(com.android.internal.R.drawable.default_wallpaper); 366 } 367} 368