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