blob: e455a5966c8af23a30c06c1c5af5d1de0c51e6b2 [file] [log] [blame]
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001/*
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
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070017package android.app;
18
19import android.content.Context;
20import android.content.Intent;
21import android.content.res.Resources;
22import android.graphics.Bitmap;
23import android.graphics.BitmapFactory;
Dianne Hackborn284ac932009-08-28 10:34:25 -070024import android.graphics.Canvas;
Dianne Hackborn19382ac2009-09-11 21:13:37 -070025import android.graphics.ColorFilter;
Dianne Hackborn284ac932009-08-28 10:34:25 -070026import android.graphics.Paint;
Dianne Hackborn19382ac2009-09-11 21:13:37 -070027import android.graphics.PixelFormat;
Dianne Hackborn284ac932009-08-28 10:34:25 -070028import android.graphics.Rect;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070029import android.graphics.drawable.BitmapDrawable;
30import android.graphics.drawable.Drawable;
Dianne Hackborn284ac932009-08-28 10:34:25 -070031import android.os.Bundle;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070032import android.os.Handler;
33import android.os.IBinder;
Dianne Hackborn840c3a22009-09-02 17:35:17 -070034import android.os.Looper;
35import android.os.Message;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070036import android.os.ParcelFileDescriptor;
37import android.os.RemoteException;
38import android.os.ServiceManager;
Dianne Hackborn284ac932009-08-28 10:34:25 -070039import android.util.DisplayMetrics;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -070040import android.util.Log;
Dianne Hackbornc8a0a752009-08-10 23:05:49 -070041import android.view.ViewRoot;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070042
43import java.io.FileOutputStream;
44import java.io.IOException;
45import java.io.InputStream;
46
Scott Main8b2e0002009-09-29 18:17:31 -070047/**
48 * Provides access to the system wallpaper. With WallpaperManager, you can
49 * get the current wallpaper, get the desired dimensions for the wallpaper, set
50 * the wallpaper, and more. Get an instance of WallpaperManager with
51 * {@link #getInstance(android.content.Context) getInstance()}.
52 */
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070053public class WallpaperManager {
54 private static String TAG = "WallpaperManager";
55 private static boolean DEBUG = false;
Marco Nelissenbf6956b2009-11-09 15:21:13 -080056 private float mWallpaperXStep = -1;
57 private float mWallpaperYStep = -1;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070058
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070059 /**
60 * Launch an activity for the user to pick the current global live
61 * wallpaper.
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070062 */
63 public static final String ACTION_LIVE_WALLPAPER_CHOOSER
64 = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
65
Dianne Hackborn23ef7b42009-11-18 18:20:39 -080066 /**
67 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
68 * host when the user taps on an empty area (not performing an action
69 * in the host). The x and y arguments are the location of the tap in
70 * screen coordinates.
71 */
72 public static final String COMMAND_TAP = "android.wallpaper.tap";
73
74 /**
75 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
76 * host when the user drops an object into an area of the host. The x
77 * and y arguments are the location of the drop.
78 */
79 public static final String COMMAND_DROP = "android.home.drop";
80
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070081 private final Context mContext;
82
Dianne Hackborn19382ac2009-09-11 21:13:37 -070083 /**
84 * Special drawable that draws a wallpaper as fast as possible. Assumes
85 * no scaling or placement off (0,0) of the wallpaper (this should be done
86 * at the time the bitmap is loaded).
87 */
88 static class FastBitmapDrawable extends Drawable {
89 private final Bitmap mBitmap;
90 private final int mWidth;
91 private final int mHeight;
92 private int mDrawLeft;
93 private int mDrawTop;
94
95 private FastBitmapDrawable(Bitmap bitmap) {
96 mBitmap = bitmap;
97 mWidth = bitmap.getWidth();
98 mHeight = bitmap.getHeight();
99 setBounds(0, 0, mWidth, mHeight);
100 }
101
102 @Override
103 public void draw(Canvas canvas) {
104 canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
105 }
106
107 @Override
108 public int getOpacity() {
109 return PixelFormat.OPAQUE;
110 }
111
112 @Override
113 public void setBounds(int left, int top, int right, int bottom) {
114 mDrawLeft = left + (right-left - mWidth) / 2;
115 mDrawTop = top + (bottom-top - mHeight) / 2;
116 }
117
118 @Override
119 public void setBounds(Rect bounds) {
120 // TODO Auto-generated method stub
121 super.setBounds(bounds);
122 }
123
124 @Override
125 public void setAlpha(int alpha) {
126 throw new UnsupportedOperationException(
127 "Not supported with this drawable");
128 }
129
130 @Override
131 public void setColorFilter(ColorFilter cf) {
132 throw new UnsupportedOperationException(
133 "Not supported with this drawable");
134 }
135
136 @Override
137 public void setDither(boolean dither) {
138 throw new UnsupportedOperationException(
139 "Not supported with this drawable");
140 }
141
142 @Override
143 public void setFilterBitmap(boolean filter) {
144 throw new UnsupportedOperationException(
145 "Not supported with this drawable");
146 }
147
148 @Override
149 public int getIntrinsicWidth() {
150 return mWidth;
151 }
152
153 @Override
154 public int getIntrinsicHeight() {
155 return mHeight;
156 }
157
158 @Override
159 public int getMinimumWidth() {
160 return mWidth;
161 }
162
163 @Override
164 public int getMinimumHeight() {
165 return mHeight;
166 }
167 }
168
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700169 static class Globals extends IWallpaperManagerCallback.Stub {
170 private IWallpaperManager mService;
Dianne Hackborn284ac932009-08-28 10:34:25 -0700171 private Bitmap mWallpaper;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700172 private Bitmap mDefaultWallpaper;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700173
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700174 private static final int MSG_CLEAR_WALLPAPER = 1;
175
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700176 private final Handler mHandler;
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700177
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700178 Globals(Looper looper) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700179 IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
180 mService = IWallpaperManager.Stub.asInterface(b);
Dianne Hackborn85644d72009-09-03 00:23:04 -0700181 mHandler = new Handler(looper) {
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700182 @Override
183 public void handleMessage(Message msg) {
184 switch (msg.what) {
185 case MSG_CLEAR_WALLPAPER:
186 synchronized (this) {
187 mWallpaper = null;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700188 mDefaultWallpaper = null;
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700189 }
190 break;
191 }
192 }
193 };
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700194 }
195
196 public void onWallpaperChanged() {
197 /* The wallpaper has changed but we shouldn't eagerly load the
198 * wallpaper as that would be inefficient. Reset the cached wallpaper
199 * to null so if the user requests the wallpaper again then we'll
200 * fetch it.
201 */
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700202 mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700203 }
204
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700205 public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700206 synchronized (this) {
207 if (mWallpaper != null) {
208 return mWallpaper;
209 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700210 if (mDefaultWallpaper != null) {
211 return mDefaultWallpaper;
212 }
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800213 mWallpaper = null;
214 try {
215 mWallpaper = getCurrentWallpaperLocked(context);
216 } catch (OutOfMemoryError e) {
217 Log.w(TAG, "No memory load current wallpaper", e);
218 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700219 if (mWallpaper == null && returnDefault) {
220 mDefaultWallpaper = getDefaultWallpaperLocked(context);
221 return mDefaultWallpaper;
222 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700223 return mWallpaper;
224 }
225 }
226
Dianne Hackborn284ac932009-08-28 10:34:25 -0700227 private Bitmap getCurrentWallpaperLocked(Context context) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700228 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700229 Bundle params = new Bundle();
230 ParcelFileDescriptor fd = mService.getWallpaper(this, params);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700231 if (fd != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700232 int width = params.getInt("width", 0);
233 int height = params.getInt("height", 0);
234
235 if (width <= 0 || height <= 0) {
236 // Degenerate case: no size requested, just load
237 // bitmap as-is.
238 Bitmap bm = BitmapFactory.decodeFileDescriptor(
239 fd.getFileDescriptor(), null, null);
240 try {
241 fd.close();
242 } catch (IOException e) {
243 }
244 if (bm != null) {
245 bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
246 }
247 return bm;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700248 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700249
250 // Load the bitmap with full color depth, to preserve
251 // quality for later processing.
252 BitmapFactory.Options options = new BitmapFactory.Options();
253 options.inDither = false;
254 options.inPreferredConfig = Bitmap.Config.ARGB_8888;
255 Bitmap bm = BitmapFactory.decodeFileDescriptor(
256 fd.getFileDescriptor(), null, options);
257 try {
258 fd.close();
259 } catch (IOException e) {
260 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700261
262 return generateBitmap(context, bm, width, height);
263 }
264 } catch (RemoteException e) {
265 }
266 return null;
267 }
268
269 private Bitmap getDefaultWallpaperLocked(Context context) {
270 try {
271 InputStream is = context.getResources().openRawResource(
272 com.android.internal.R.drawable.default_wallpaper);
273 if (is != null) {
274 int width = mService.getWidthHint();
275 int height = mService.getHeightHint();
276
277 if (width <= 0 || height <= 0) {
278 // Degenerate case: no size requested, just load
279 // bitmap as-is.
280 Bitmap bm = BitmapFactory.decodeStream(is, null, null);
281 try {
282 is.close();
283 } catch (IOException e) {
284 }
285 if (bm != null) {
286 bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
287 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700288 return bm;
289 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700290
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700291 // Load the bitmap with full color depth, to preserve
292 // quality for later processing.
293 BitmapFactory.Options options = new BitmapFactory.Options();
294 options.inDither = false;
295 options.inPreferredConfig = Bitmap.Config.ARGB_8888;
296 Bitmap bm = BitmapFactory.decodeStream(is, null, options);
297 try {
298 is.close();
299 } catch (IOException e) {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700300 }
301
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800302 try {
303 return generateBitmap(context, bm, width, height);
304 } catch (OutOfMemoryError e) {
305 Log.w(TAG, "Can't generate default bitmap", e);
306 return bm;
307 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700308 }
309 } catch (RemoteException e) {
310 }
311 return null;
312 }
313 }
314
315 private static Object mSync = new Object();
316 private static Globals sGlobals;
317
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700318 static void initGlobals(Looper looper) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700319 synchronized (mSync) {
320 if (sGlobals == null) {
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700321 sGlobals = new Globals(looper);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700322 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700323 }
324 }
325
326 /*package*/ WallpaperManager(Context context, Handler handler) {
327 mContext = context;
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700328 initGlobals(context.getMainLooper());
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700329 }
330
331 /**
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700332 * Retrieve a WallpaperManager associated with the given Context.
333 */
334 public static WallpaperManager getInstance(Context context) {
335 return (WallpaperManager)context.getSystemService(
336 Context.WALLPAPER_SERVICE);
337 }
338
339 /** @hide */
340 public IWallpaperManager getIWallpaperManager() {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700341 return sGlobals.mService;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700342 }
343
344 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700345 * Retrieve the current system wallpaper; if
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700346 * no wallpaper is set, the system default wallpaper is returned.
Scott Main8b2e0002009-09-29 18:17:31 -0700347 * This is returned as an
348 * abstract Drawable that you can install in a View to display whatever
349 * wallpaper the user has currently set.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700350 *
351 * @return Returns a Drawable object that will draw the wallpaper.
352 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700353 public Drawable getDrawable() {
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700354 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
355 if (bm != null) {
356 Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
357 dr.setDither(false);
358 return dr;
359 }
360 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700361 }
362
363 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700364 * Retrieve the current system wallpaper; if there is no wallpaper set,
365 * a null pointer is returned. This is returned as an
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700366 * abstract Drawable that you can install in a View to display whatever
Scott Main8b2e0002009-09-29 18:17:31 -0700367 * wallpaper the user has currently set.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700368 *
369 * @return Returns a Drawable object that will draw the wallpaper or a
370 * null pointer if these is none.
371 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700372 public Drawable peekDrawable() {
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700373 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
374 if (bm != null) {
375 Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
376 dr.setDither(false);
377 return dr;
378 }
379 return null;
380 }
381
382 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700383 * Like {@link #getDrawable()}, but the returned Drawable has a number
384 * of limitations to reduce its overhead as much as possible. It will
385 * never scale the wallpaper (only centering it if the requested bounds
386 * do match the bitmap bounds, which should not be typical), doesn't
387 * allow setting an alpha, color filter, or other attributes, etc. The
388 * bounds of the returned drawable will be initialized to the same bounds
389 * as the wallpaper, so normally you will not need to touch it. The
390 * drawable also assumes that it will be used in a context running in
391 * the same density as the screen (not in density compatibility mode).
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700392 *
393 * @return Returns a Drawable object that will draw the wallpaper.
394 */
395 public Drawable getFastDrawable() {
396 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
397 if (bm != null) {
398 Drawable dr = new FastBitmapDrawable(bm);
399 return dr;
400 }
401 return null;
402 }
403
404 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700405 * Like {@link #getFastDrawable()}, but if there is no wallpaper set,
406 * a null pointer is returned.
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700407 *
408 * @return Returns an optimized Drawable object that will draw the
409 * wallpaper or a null pointer if these is none.
410 */
411 public Drawable peekFastDrawable() {
412 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
413 if (bm != null) {
414 Drawable dr = new FastBitmapDrawable(bm);
415 return dr;
416 }
417 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700418 }
419
420 /**
Dianne Hackborneb034652009-09-07 00:49:58 -0700421 * If the current wallpaper is a live wallpaper component, return the
422 * information about that wallpaper. Otherwise, if it is a static image,
423 * simply return null.
Dianne Hackborneb034652009-09-07 00:49:58 -0700424 */
425 public WallpaperInfo getWallpaperInfo() {
426 try {
427 return sGlobals.mService.getWallpaperInfo();
428 } catch (RemoteException e) {
429 return null;
430 }
431 }
432
433 /**
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700434 * Change the current system wallpaper to the bitmap in the given resource.
435 * The resource is opened as a raw data stream and copied into the
436 * wallpaper; it must be a valid PNG or JPEG image. On success, the intent
437 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
438 *
439 * @param resid The bitmap to save.
440 *
441 * @throws IOException If an error occurs reverting to the default
442 * wallpaper.
443 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700444 public void setResource(int resid) throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700445 try {
446 Resources resources = mContext.getResources();
447 /* Set the wallpaper to the default values */
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700448 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700449 "res:" + resources.getResourceName(resid));
450 if (fd != null) {
451 FileOutputStream fos = null;
452 try {
453 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
454 setWallpaper(resources.openRawResource(resid), fos);
455 } finally {
456 if (fos != null) {
457 fos.close();
458 }
459 }
460 }
461 } catch (RemoteException e) {
462 }
463 }
464
465 /**
466 * Change the current system wallpaper to a bitmap. The given bitmap is
467 * converted to a PNG and stored as the wallpaper. On success, the intent
468 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
469 *
470 * @param bitmap The bitmap to save.
471 *
472 * @throws IOException If an error occurs reverting to the default
473 * wallpaper.
474 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700475 public void setBitmap(Bitmap bitmap) throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700476 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700477 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700478 if (fd == null) {
479 return;
480 }
481 FileOutputStream fos = null;
482 try {
483 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
484 bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
485 } finally {
486 if (fos != null) {
487 fos.close();
488 }
489 }
490 } catch (RemoteException e) {
491 }
492 }
493
494 /**
495 * Change the current system wallpaper to a specific byte stream. The
496 * give InputStream is copied into persistent storage and will now be
497 * used as the wallpaper. Currently it must be either a JPEG or PNG
498 * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
499 * is broadcast.
500 *
501 * @param data A stream containing the raw data to install as a wallpaper.
502 *
503 * @throws IOException If an error occurs reverting to the default
504 * wallpaper.
505 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700506 public void setStream(InputStream data) throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700507 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700508 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700509 if (fd == null) {
510 return;
511 }
512 FileOutputStream fos = null;
513 try {
514 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
515 setWallpaper(data, fos);
516 } finally {
517 if (fos != null) {
518 fos.close();
519 }
520 }
521 } catch (RemoteException e) {
522 }
523 }
524
525 private void setWallpaper(InputStream data, FileOutputStream fos)
526 throws IOException {
527 byte[] buffer = new byte[32768];
528 int amt;
529 while ((amt=data.read(buffer)) > 0) {
530 fos.write(buffer, 0, amt);
531 }
532 }
533
534 /**
535 * Returns the desired minimum width for the wallpaper. Callers of
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700536 * {@link #setBitmap(android.graphics.Bitmap)} or
537 * {@link #setStream(java.io.InputStream)} should check this value
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700538 * beforehand to make sure the supplied wallpaper respects the desired
539 * minimum width.
540 *
541 * If the returned value is <= 0, the caller should use the width of
542 * the default display instead.
543 *
544 * @return The desired minimum width for the wallpaper. This value should
545 * be honored by applications that set the wallpaper but it is not
546 * mandatory.
547 */
548 public int getDesiredMinimumWidth() {
549 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700550 return sGlobals.mService.getWidthHint();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700551 } catch (RemoteException e) {
552 // Shouldn't happen!
553 return 0;
554 }
555 }
556
557 /**
558 * Returns the desired minimum height for the wallpaper. Callers of
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700559 * {@link #setBitmap(android.graphics.Bitmap)} or
560 * {@link #setStream(java.io.InputStream)} should check this value
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700561 * beforehand to make sure the supplied wallpaper respects the desired
562 * minimum height.
563 *
564 * If the returned value is <= 0, the caller should use the height of
565 * the default display instead.
566 *
567 * @return The desired minimum height for the wallpaper. This value should
568 * be honored by applications that set the wallpaper but it is not
569 * mandatory.
570 */
571 public int getDesiredMinimumHeight() {
572 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700573 return sGlobals.mService.getHeightHint();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700574 } catch (RemoteException e) {
575 // Shouldn't happen!
576 return 0;
577 }
578 }
579
580 /**
581 * For use only by the current home application, to specify the size of
582 * wallpaper it would like to use. This allows such applications to have
583 * a virtual wallpaper that is larger than the physical screen, matching
584 * the size of their workspace.
585 * @param minimumWidth Desired minimum width
586 * @param minimumHeight Desired minimum height
587 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700588 public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700589 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700590 sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700591 } catch (RemoteException e) {
592 }
593 }
594
595 /**
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700596 * Set the position of the current wallpaper within any larger space, when
597 * that wallpaper is visible behind the given window. The X and Y offsets
598 * are floating point numbers ranging from 0 to 1, representing where the
599 * wallpaper should be positioned within the screen space. These only
600 * make sense when the wallpaper is larger than the screen.
601 *
602 * @param windowToken The window who these offsets should be associated
Scott Main8b2e0002009-09-29 18:17:31 -0700603 * with, as returned by {@link android.view.View#getWindowToken()
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700604 * View.getWindowToken()}.
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800605 * @param xOffset The offset along the X dimension, from 0 to 1.
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700606 * @param yOffset The offset along the Y dimension, from 0 to 1.
607 */
608 public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
609 try {
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700610 //Log.v(TAG, "Sending new wallpaper offsets from app...");
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700611 ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800612 windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700613 //Log.v(TAG, "...app returning after sending offsets!");
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700614 } catch (RemoteException e) {
615 // Ignore.
616 }
617 }
618
619 /**
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800620 * For applications that use multiple virtual screens showing a wallpaper,
621 * specify the step size between virtual screens. For example, if the
Dianne Hackborn23ef7b42009-11-18 18:20:39 -0800622 * launcher has 3 virtual screens, it would specify an xStep of 0.5,
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800623 * since the X offset for those screens are 0.0, 0.5 and 1.0
624 * @param xStep The X offset delta from one screen to the next one
625 * @param yStep The Y offset delta from one screen to the next one
626 */
627 public void setWallpaperOffsetSteps(float xStep, float yStep) {
628 mWallpaperXStep = xStep;
629 mWallpaperYStep = yStep;
630 }
631
632 /**
Dianne Hackborn75804932009-10-20 20:15:20 -0700633 * Send an arbitrary command to the current active wallpaper.
634 *
635 * @param windowToken The window who these offsets should be associated
636 * with, as returned by {@link android.view.View#getWindowToken()
637 * View.getWindowToken()}.
638 * @param action Name of the command to perform. This must be a scoped
639 * name to avoid collisions, such as "com.mycompany.wallpaper.DOIT".
640 * @param x Arbitrary integer argument based on command.
641 * @param y Arbitrary integer argument based on command.
642 * @param z Arbitrary integer argument based on command.
643 * @param extras Optional additional information for the command, or null.
644 */
645 public void sendWallpaperCommand(IBinder windowToken, String action,
646 int x, int y, int z, Bundle extras) {
647 try {
648 //Log.v(TAG, "Sending new wallpaper offsets from app...");
649 ViewRoot.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
650 windowToken, action, x, y, z, extras, false);
651 //Log.v(TAG, "...app returning after sending offsets!");
652 } catch (RemoteException e) {
653 // Ignore.
654 }
655 }
656
657 /**
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700658 * Clear the offsets previously associated with this window through
659 * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
660 * the window to its default state, where it does not cause the wallpaper
661 * to scroll from whatever its last offsets were.
662 *
663 * @param windowToken The window who these offsets should be associated
Scott Main8b2e0002009-09-29 18:17:31 -0700664 * with, as returned by {@link android.view.View#getWindowToken()
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700665 * View.getWindowToken()}.
666 */
667 public void clearWallpaperOffsets(IBinder windowToken) {
668 try {
669 ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800670 windowToken, -1, -1, -1, -1);
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700671 } catch (RemoteException e) {
672 // Ignore.
673 }
674 }
675
676 /**
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700677 * Remove any currently set wallpaper, reverting to the system's default
678 * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
679 * is broadcast.
680 *
681 * @throws IOException If an error occurs reverting to the default
682 * wallpaper.
683 */
684 public void clear() throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700685 setResource(com.android.internal.R.drawable.default_wallpaper);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700686 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700687
688 static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
689 if (bm == null) {
690 return bm;
691 }
692 bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
693
694 // This is the final bitmap we want to return.
695 // XXX We should get the pixel depth from the system (to match the
696 // physical display depth), when there is a way.
697 Bitmap newbm = Bitmap.createBitmap(width, height,
698 Bitmap.Config.RGB_565);
699 newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
700 Canvas c = new Canvas(newbm);
701 c.setDensity(DisplayMetrics.DENSITY_DEVICE);
702 Rect targetRect = new Rect();
703 targetRect.left = targetRect.top = 0;
704 targetRect.right = bm.getWidth();
705 targetRect.bottom = bm.getHeight();
706
707 int deltaw = width - targetRect.right;
708 int deltah = height - targetRect.bottom;
709
710 if (deltaw > 0 || deltah > 0) {
711 // We need to scale up so it covers the entire
712 // area.
713 float scale = 1.0f;
714 if (deltaw > deltah) {
715 scale = width / (float)targetRect.right;
716 } else {
717 scale = height / (float)targetRect.bottom;
718 }
719 targetRect.right = (int)(targetRect.right*scale);
720 targetRect.bottom = (int)(targetRect.bottom*scale);
721 deltaw = width - targetRect.right;
722 deltah = height - targetRect.bottom;
723 }
724
725 targetRect.offset(deltaw/2, deltah/2);
726 Paint paint = new Paint();
727 paint.setFilterBitmap(true);
728 paint.setDither(true);
729 c.drawBitmap(bm, null, targetRect, paint);
730
731 bm.recycle();
732 return newbm;
733 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700734}