blob: 113c610d678295e1268bffb188509c083a97a0f0 [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;
Joe Onoratoc6cc0f82011-04-12 11:53:13 -070041import android.view.ViewAncestor;
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";
Adam Cohen5a242ec2010-12-07 21:07:07 -080065
66 /**
67 * Manifest entry for activities that respond to {@link Intent#ACTION_SET_WALLPAPER}
68 * which allows them to provide a custom large icon associated with this action.
69 */
70 public static final String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
71
Dianne Hackborn23ef7b42009-11-18 18:20:39 -080072 /**
73 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
74 * host when the user taps on an empty area (not performing an action
75 * in the host). The x and y arguments are the location of the tap in
76 * screen coordinates.
77 */
78 public static final String COMMAND_TAP = "android.wallpaper.tap";
79
80 /**
81 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
Jeff Brown9f3bdfe2010-10-13 06:01:27 -070082 * host when the user releases a secondary pointer on an empty area
83 * (not performing an action in the host). The x and y arguments are
84 * the location of the secondary tap in screen coordinates.
85 */
86 public static final String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
87
88 /**
89 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
Dianne Hackborn23ef7b42009-11-18 18:20:39 -080090 * host when the user drops an object into an area of the host. The x
91 * and y arguments are the location of the drop.
92 */
93 public static final String COMMAND_DROP = "android.home.drop";
94
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070095 private final Context mContext;
96
Dianne Hackborn19382ac2009-09-11 21:13:37 -070097 /**
98 * Special drawable that draws a wallpaper as fast as possible. Assumes
99 * no scaling or placement off (0,0) of the wallpaper (this should be done
100 * at the time the bitmap is loaded).
101 */
102 static class FastBitmapDrawable extends Drawable {
103 private final Bitmap mBitmap;
104 private final int mWidth;
105 private final int mHeight;
106 private int mDrawLeft;
107 private int mDrawTop;
108
109 private FastBitmapDrawable(Bitmap bitmap) {
110 mBitmap = bitmap;
111 mWidth = bitmap.getWidth();
112 mHeight = bitmap.getHeight();
113 setBounds(0, 0, mWidth, mHeight);
114 }
115
116 @Override
117 public void draw(Canvas canvas) {
118 canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
119 }
120
121 @Override
122 public int getOpacity() {
123 return PixelFormat.OPAQUE;
124 }
125
126 @Override
127 public void setBounds(int left, int top, int right, int bottom) {
128 mDrawLeft = left + (right-left - mWidth) / 2;
129 mDrawTop = top + (bottom-top - mHeight) / 2;
130 }
131
132 @Override
133 public void setBounds(Rect bounds) {
134 // TODO Auto-generated method stub
135 super.setBounds(bounds);
136 }
137
138 @Override
139 public void setAlpha(int alpha) {
140 throw new UnsupportedOperationException(
141 "Not supported with this drawable");
142 }
143
144 @Override
145 public void setColorFilter(ColorFilter cf) {
146 throw new UnsupportedOperationException(
147 "Not supported with this drawable");
148 }
149
150 @Override
151 public void setDither(boolean dither) {
152 throw new UnsupportedOperationException(
153 "Not supported with this drawable");
154 }
155
156 @Override
157 public void setFilterBitmap(boolean filter) {
158 throw new UnsupportedOperationException(
159 "Not supported with this drawable");
160 }
161
162 @Override
163 public int getIntrinsicWidth() {
164 return mWidth;
165 }
166
167 @Override
168 public int getIntrinsicHeight() {
169 return mHeight;
170 }
171
172 @Override
173 public int getMinimumWidth() {
174 return mWidth;
175 }
176
177 @Override
178 public int getMinimumHeight() {
179 return mHeight;
180 }
181 }
182
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700183 static class Globals extends IWallpaperManagerCallback.Stub {
184 private IWallpaperManager mService;
Dianne Hackborn284ac932009-08-28 10:34:25 -0700185 private Bitmap mWallpaper;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700186 private Bitmap mDefaultWallpaper;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700187
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700188 private static final int MSG_CLEAR_WALLPAPER = 1;
189
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700190 private final Handler mHandler;
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700191
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700192 Globals(Looper looper) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700193 IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
194 mService = IWallpaperManager.Stub.asInterface(b);
Dianne Hackborn85644d72009-09-03 00:23:04 -0700195 mHandler = new Handler(looper) {
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700196 @Override
197 public void handleMessage(Message msg) {
198 switch (msg.what) {
199 case MSG_CLEAR_WALLPAPER:
200 synchronized (this) {
201 mWallpaper = null;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700202 mDefaultWallpaper = null;
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700203 }
204 break;
205 }
206 }
207 };
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700208 }
209
210 public void onWallpaperChanged() {
211 /* The wallpaper has changed but we shouldn't eagerly load the
212 * wallpaper as that would be inefficient. Reset the cached wallpaper
213 * to null so if the user requests the wallpaper again then we'll
214 * fetch it.
215 */
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700216 mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700217 }
218
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700219 public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700220 synchronized (this) {
221 if (mWallpaper != null) {
222 return mWallpaper;
223 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700224 if (mDefaultWallpaper != null) {
225 return mDefaultWallpaper;
226 }
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800227 mWallpaper = null;
228 try {
229 mWallpaper = getCurrentWallpaperLocked(context);
230 } catch (OutOfMemoryError e) {
231 Log.w(TAG, "No memory load current wallpaper", e);
232 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700233 if (mWallpaper == null && returnDefault) {
234 mDefaultWallpaper = getDefaultWallpaperLocked(context);
235 return mDefaultWallpaper;
236 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700237 return mWallpaper;
238 }
239 }
240
Dianne Hackborn284ac932009-08-28 10:34:25 -0700241 private Bitmap getCurrentWallpaperLocked(Context context) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700242 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700243 Bundle params = new Bundle();
244 ParcelFileDescriptor fd = mService.getWallpaper(this, params);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700245 if (fd != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700246 int width = params.getInt("width", 0);
247 int height = params.getInt("height", 0);
248
249 if (width <= 0 || height <= 0) {
250 // Degenerate case: no size requested, just load
251 // bitmap as-is.
Johan Alfven2c4a56a2010-09-02 14:26:54 +0200252 Bitmap bm = null;
253 try {
254 bm = BitmapFactory.decodeFileDescriptor(
255 fd.getFileDescriptor(), null, null);
256 } catch (OutOfMemoryError e) {
257 Log.w(TAG, "Can't decode file", e);
258 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700259 try {
260 fd.close();
261 } catch (IOException e) {
262 }
263 if (bm != null) {
264 bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
265 }
266 return bm;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700267 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700268
269 // Load the bitmap with full color depth, to preserve
270 // quality for later processing.
271 BitmapFactory.Options options = new BitmapFactory.Options();
272 options.inDither = false;
273 options.inPreferredConfig = Bitmap.Config.ARGB_8888;
274 Bitmap bm = BitmapFactory.decodeFileDescriptor(
275 fd.getFileDescriptor(), null, options);
276 try {
277 fd.close();
278 } catch (IOException e) {
279 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700280
281 return generateBitmap(context, bm, width, height);
282 }
283 } catch (RemoteException e) {
284 }
285 return null;
286 }
287
288 private Bitmap getDefaultWallpaperLocked(Context context) {
289 try {
290 InputStream is = context.getResources().openRawResource(
291 com.android.internal.R.drawable.default_wallpaper);
292 if (is != null) {
293 int width = mService.getWidthHint();
294 int height = mService.getHeightHint();
295
296 if (width <= 0 || height <= 0) {
297 // Degenerate case: no size requested, just load
298 // bitmap as-is.
Johan Alfven2c4a56a2010-09-02 14:26:54 +0200299 Bitmap bm = null;
300 try {
301 bm = BitmapFactory.decodeStream(is, null, null);
302 } catch (OutOfMemoryError e) {
303 Log.w(TAG, "Can't decode stream", e);
304 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700305 try {
306 is.close();
307 } catch (IOException e) {
308 }
309 if (bm != null) {
310 bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
311 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700312 return bm;
313 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700314
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700315 // Load the bitmap with full color depth, to preserve
316 // quality for later processing.
317 BitmapFactory.Options options = new BitmapFactory.Options();
318 options.inDither = false;
319 options.inPreferredConfig = Bitmap.Config.ARGB_8888;
320 Bitmap bm = BitmapFactory.decodeStream(is, null, options);
321 try {
322 is.close();
323 } catch (IOException e) {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700324 }
325
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800326 try {
327 return generateBitmap(context, bm, width, height);
328 } catch (OutOfMemoryError e) {
329 Log.w(TAG, "Can't generate default bitmap", e);
330 return bm;
331 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700332 }
333 } catch (RemoteException e) {
334 }
335 return null;
336 }
337 }
338
339 private static Object mSync = new Object();
340 private static Globals sGlobals;
341
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700342 static void initGlobals(Looper looper) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700343 synchronized (mSync) {
344 if (sGlobals == null) {
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700345 sGlobals = new Globals(looper);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700346 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700347 }
348 }
349
350 /*package*/ WallpaperManager(Context context, Handler handler) {
351 mContext = context;
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700352 initGlobals(context.getMainLooper());
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700353 }
354
355 /**
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700356 * Retrieve a WallpaperManager associated with the given Context.
357 */
358 public static WallpaperManager getInstance(Context context) {
359 return (WallpaperManager)context.getSystemService(
360 Context.WALLPAPER_SERVICE);
361 }
362
363 /** @hide */
364 public IWallpaperManager getIWallpaperManager() {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700365 return sGlobals.mService;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700366 }
367
368 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700369 * Retrieve the current system wallpaper; if
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700370 * no wallpaper is set, the system default wallpaper is returned.
Scott Main8b2e0002009-09-29 18:17:31 -0700371 * This is returned as an
372 * abstract Drawable that you can install in a View to display whatever
373 * wallpaper the user has currently set.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700374 *
375 * @return Returns a Drawable object that will draw the wallpaper.
376 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700377 public Drawable getDrawable() {
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700378 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
379 if (bm != null) {
380 Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
381 dr.setDither(false);
382 return dr;
383 }
384 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700385 }
386
387 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700388 * Retrieve the current system wallpaper; if there is no wallpaper set,
389 * a null pointer is returned. This is returned as an
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700390 * abstract Drawable that you can install in a View to display whatever
Scott Main8b2e0002009-09-29 18:17:31 -0700391 * wallpaper the user has currently set.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700392 *
393 * @return Returns a Drawable object that will draw the wallpaper or a
394 * null pointer if these is none.
395 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700396 public Drawable peekDrawable() {
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700397 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
398 if (bm != null) {
399 Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
400 dr.setDither(false);
401 return dr;
402 }
403 return null;
404 }
405
406 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700407 * Like {@link #getDrawable()}, but the returned Drawable has a number
408 * of limitations to reduce its overhead as much as possible. It will
409 * never scale the wallpaper (only centering it if the requested bounds
410 * do match the bitmap bounds, which should not be typical), doesn't
411 * allow setting an alpha, color filter, or other attributes, etc. The
412 * bounds of the returned drawable will be initialized to the same bounds
413 * as the wallpaper, so normally you will not need to touch it. The
414 * drawable also assumes that it will be used in a context running in
415 * the same density as the screen (not in density compatibility mode).
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700416 *
417 * @return Returns a Drawable object that will draw the wallpaper.
418 */
419 public Drawable getFastDrawable() {
420 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
421 if (bm != null) {
422 Drawable dr = new FastBitmapDrawable(bm);
423 return dr;
424 }
425 return null;
426 }
427
428 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700429 * Like {@link #getFastDrawable()}, but if there is no wallpaper set,
430 * a null pointer is returned.
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700431 *
432 * @return Returns an optimized Drawable object that will draw the
433 * wallpaper or a null pointer if these is none.
434 */
435 public Drawable peekFastDrawable() {
436 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
437 if (bm != null) {
438 Drawable dr = new FastBitmapDrawable(bm);
439 return dr;
440 }
441 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700442 }
443
444 /**
Dianne Hackborneb034652009-09-07 00:49:58 -0700445 * If the current wallpaper is a live wallpaper component, return the
446 * information about that wallpaper. Otherwise, if it is a static image,
447 * simply return null.
Dianne Hackborneb034652009-09-07 00:49:58 -0700448 */
449 public WallpaperInfo getWallpaperInfo() {
450 try {
451 return sGlobals.mService.getWallpaperInfo();
452 } catch (RemoteException e) {
453 return null;
454 }
455 }
456
457 /**
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700458 * Change the current system wallpaper to the bitmap in the given resource.
459 * The resource is opened as a raw data stream and copied into the
460 * wallpaper; it must be a valid PNG or JPEG image. On success, the intent
461 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
462 *
463 * @param resid The bitmap to save.
464 *
465 * @throws IOException If an error occurs reverting to the default
466 * wallpaper.
467 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700468 public void setResource(int resid) throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700469 try {
470 Resources resources = mContext.getResources();
471 /* Set the wallpaper to the default values */
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700472 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700473 "res:" + resources.getResourceName(resid));
474 if (fd != null) {
475 FileOutputStream fos = null;
476 try {
477 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
478 setWallpaper(resources.openRawResource(resid), fos);
479 } finally {
480 if (fos != null) {
481 fos.close();
482 }
483 }
484 }
485 } catch (RemoteException e) {
486 }
487 }
488
489 /**
490 * Change the current system wallpaper to a bitmap. The given bitmap is
491 * converted to a PNG and stored as the wallpaper. On success, the intent
492 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
493 *
494 * @param bitmap The bitmap to save.
495 *
496 * @throws IOException If an error occurs reverting to the default
497 * wallpaper.
498 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700499 public void setBitmap(Bitmap bitmap) throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700500 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700501 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700502 if (fd == null) {
503 return;
504 }
505 FileOutputStream fos = null;
506 try {
507 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
508 bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
509 } finally {
510 if (fos != null) {
511 fos.close();
512 }
513 }
514 } catch (RemoteException e) {
515 }
516 }
517
518 /**
519 * Change the current system wallpaper to a specific byte stream. The
520 * give InputStream is copied into persistent storage and will now be
521 * used as the wallpaper. Currently it must be either a JPEG or PNG
522 * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
523 * is broadcast.
524 *
525 * @param data A stream containing the raw data to install as a wallpaper.
526 *
527 * @throws IOException If an error occurs reverting to the default
528 * wallpaper.
529 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700530 public void setStream(InputStream data) throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700531 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700532 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700533 if (fd == null) {
534 return;
535 }
536 FileOutputStream fos = null;
537 try {
538 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
539 setWallpaper(data, fos);
540 } finally {
541 if (fos != null) {
542 fos.close();
543 }
544 }
545 } catch (RemoteException e) {
546 }
547 }
548
549 private void setWallpaper(InputStream data, FileOutputStream fos)
550 throws IOException {
551 byte[] buffer = new byte[32768];
552 int amt;
553 while ((amt=data.read(buffer)) > 0) {
554 fos.write(buffer, 0, amt);
555 }
556 }
557
558 /**
559 * Returns the desired minimum width for the wallpaper. Callers of
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700560 * {@link #setBitmap(android.graphics.Bitmap)} or
561 * {@link #setStream(java.io.InputStream)} should check this value
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700562 * beforehand to make sure the supplied wallpaper respects the desired
563 * minimum width.
564 *
565 * If the returned value is <= 0, the caller should use the width of
566 * the default display instead.
567 *
568 * @return The desired minimum width for the wallpaper. This value should
569 * be honored by applications that set the wallpaper but it is not
570 * mandatory.
571 */
572 public int getDesiredMinimumWidth() {
573 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700574 return sGlobals.mService.getWidthHint();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700575 } catch (RemoteException e) {
576 // Shouldn't happen!
577 return 0;
578 }
579 }
580
581 /**
582 * Returns the desired minimum height for the wallpaper. Callers of
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700583 * {@link #setBitmap(android.graphics.Bitmap)} or
584 * {@link #setStream(java.io.InputStream)} should check this value
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700585 * beforehand to make sure the supplied wallpaper respects the desired
586 * minimum height.
587 *
588 * If the returned value is <= 0, the caller should use the height of
589 * the default display instead.
590 *
591 * @return The desired minimum height for the wallpaper. This value should
592 * be honored by applications that set the wallpaper but it is not
593 * mandatory.
594 */
595 public int getDesiredMinimumHeight() {
596 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700597 return sGlobals.mService.getHeightHint();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700598 } catch (RemoteException e) {
599 // Shouldn't happen!
600 return 0;
601 }
602 }
603
604 /**
605 * For use only by the current home application, to specify the size of
606 * wallpaper it would like to use. This allows such applications to have
607 * a virtual wallpaper that is larger than the physical screen, matching
608 * the size of their workspace.
609 * @param minimumWidth Desired minimum width
610 * @param minimumHeight Desired minimum height
611 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700612 public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700613 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700614 sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700615 } catch (RemoteException e) {
616 }
617 }
618
619 /**
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700620 * Set the position of the current wallpaper within any larger space, when
621 * that wallpaper is visible behind the given window. The X and Y offsets
622 * are floating point numbers ranging from 0 to 1, representing where the
623 * wallpaper should be positioned within the screen space. These only
624 * make sense when the wallpaper is larger than the screen.
625 *
626 * @param windowToken The window who these offsets should be associated
Scott Main8b2e0002009-09-29 18:17:31 -0700627 * with, as returned by {@link android.view.View#getWindowToken()
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700628 * View.getWindowToken()}.
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800629 * @param xOffset The offset along the X dimension, from 0 to 1.
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700630 * @param yOffset The offset along the Y dimension, from 0 to 1.
631 */
632 public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
633 try {
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700634 //Log.v(TAG, "Sending new wallpaper offsets from app...");
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700635 ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800636 windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700637 //Log.v(TAG, "...app returning after sending offsets!");
Dianne Hackbornc8a0a752009-08-10 23:05:49 -0700638 } catch (RemoteException e) {
639 // Ignore.
640 }
641 }
642
643 /**
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800644 * For applications that use multiple virtual screens showing a wallpaper,
645 * specify the step size between virtual screens. For example, if the
Dianne Hackborn23ef7b42009-11-18 18:20:39 -0800646 * launcher has 3 virtual screens, it would specify an xStep of 0.5,
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800647 * since the X offset for those screens are 0.0, 0.5 and 1.0
648 * @param xStep The X offset delta from one screen to the next one
649 * @param yStep The Y offset delta from one screen to the next one
650 */
651 public void setWallpaperOffsetSteps(float xStep, float yStep) {
652 mWallpaperXStep = xStep;
653 mWallpaperYStep = yStep;
654 }
655
656 /**
Dianne Hackborn75804932009-10-20 20:15:20 -0700657 * Send an arbitrary command to the current active wallpaper.
658 *
659 * @param windowToken The window who these offsets should be associated
660 * with, as returned by {@link android.view.View#getWindowToken()
661 * View.getWindowToken()}.
662 * @param action Name of the command to perform. This must be a scoped
663 * name to avoid collisions, such as "com.mycompany.wallpaper.DOIT".
664 * @param x Arbitrary integer argument based on command.
665 * @param y Arbitrary integer argument based on command.
666 * @param z Arbitrary integer argument based on command.
667 * @param extras Optional additional information for the command, or null.
668 */
669 public void sendWallpaperCommand(IBinder windowToken, String action,
670 int x, int y, int z, Bundle extras) {
671 try {
672 //Log.v(TAG, "Sending new wallpaper offsets from app...");
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700673 ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
Dianne Hackborn75804932009-10-20 20:15:20 -0700674 windowToken, action, x, y, z, extras, false);
675 //Log.v(TAG, "...app returning after sending offsets!");
676 } catch (RemoteException e) {
677 // Ignore.
678 }
679 }
680
681 /**
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700682 * Clear the offsets previously associated with this window through
683 * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
684 * the window to its default state, where it does not cause the wallpaper
685 * to scroll from whatever its last offsets were.
686 *
687 * @param windowToken The window who these offsets should be associated
Scott Main8b2e0002009-09-29 18:17:31 -0700688 * with, as returned by {@link android.view.View#getWindowToken()
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700689 * View.getWindowToken()}.
690 */
691 public void clearWallpaperOffsets(IBinder windowToken) {
692 try {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700693 ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800694 windowToken, -1, -1, -1, -1);
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700695 } catch (RemoteException e) {
696 // Ignore.
697 }
698 }
699
700 /**
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700701 * Remove any currently set wallpaper, reverting to the system's default
702 * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
703 * is broadcast.
704 *
705 * @throws IOException If an error occurs reverting to the default
706 * wallpaper.
707 */
708 public void clear() throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700709 setResource(com.android.internal.R.drawable.default_wallpaper);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700710 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700711
712 static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
713 if (bm == null) {
714 return bm;
715 }
716 bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
717
718 // This is the final bitmap we want to return.
719 // XXX We should get the pixel depth from the system (to match the
720 // physical display depth), when there is a way.
721 Bitmap newbm = Bitmap.createBitmap(width, height,
722 Bitmap.Config.RGB_565);
723 newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
724 Canvas c = new Canvas(newbm);
725 c.setDensity(DisplayMetrics.DENSITY_DEVICE);
726 Rect targetRect = new Rect();
727 targetRect.left = targetRect.top = 0;
728 targetRect.right = bm.getWidth();
729 targetRect.bottom = bm.getHeight();
730
731 int deltaw = width - targetRect.right;
732 int deltah = height - targetRect.bottom;
733
734 if (deltaw > 0 || deltah > 0) {
735 // We need to scale up so it covers the entire
736 // area.
737 float scale = 1.0f;
738 if (deltaw > deltah) {
739 scale = width / (float)targetRect.right;
740 } else {
741 scale = height / (float)targetRect.bottom;
742 }
743 targetRect.right = (int)(targetRect.right*scale);
744 targetRect.bottom = (int)(targetRect.bottom*scale);
745 deltaw = width - targetRect.right;
746 deltah = height - targetRect.bottom;
747 }
748
749 targetRect.offset(deltaw/2, deltah/2);
750 Paint paint = new Paint();
751 paint.setFilterBitmap(true);
752 paint.setDither(true);
753 c.drawBitmap(bm, null, targetRect, paint);
754
755 bm.recycle();
756 return newbm;
757 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700758}