blob: 942cc99585edb4d5327be40fd7eb1ce97e72e5e8 [file] [log] [blame]
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001/*
Christopher Tated7faf532016-02-25 12:43:38 -08002 * Copyright (C) 2009 The Android Open Source Project
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07003 *
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
Christopher Tatead3c2592016-01-20 18:13:17 -080019import android.annotation.IntDef;
Lucas Dupinc40608c2017-04-14 18:33:08 -070020import android.annotation.NonNull;
21import android.annotation.Nullable;
Tor Norbye7b9c9122013-05-30 16:48:33 -070022import android.annotation.RawRes;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060023import android.annotation.RequiresPermission;
Jeff Sharkey0f3f60b2017-04-24 18:06:20 -060024import android.annotation.SdkConstant;
Christopher Tatedbf4a9c2017-06-27 12:37:23 -070025import android.annotation.SdkConstant.SdkConstantType;
Dianne Hackborn067e5f62014-09-07 23:14:30 -070026import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060027import android.annotation.SystemService;
Jeff Sharkey28f08772014-04-16 09:41:58 -070028import android.content.ComponentName;
Adam Lesinskibba72d12013-10-11 18:10:56 -070029import android.content.ContentResolver;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070030import android.content.Context;
31import android.content.Intent;
Michael Jurkae8d1bf72013-09-09 15:58:54 +020032import android.content.pm.PackageManager;
33import android.content.pm.ResolveInfo;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070034import android.content.res.Resources;
Christopher Tate5d99d472016-05-06 17:59:27 -070035import android.content.res.Resources.NotFoundException;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070036import android.graphics.Bitmap;
37import android.graphics.BitmapFactory;
Michael Jurkab668d0b2013-10-04 15:11:05 -070038import android.graphics.BitmapRegionDecoder;
Dianne Hackborn284ac932009-08-28 10:34:25 -070039import android.graphics.Canvas;
Dianne Hackborn19382ac2009-09-11 21:13:37 -070040import android.graphics.ColorFilter;
Michael Jurkab668d0b2013-10-04 15:11:05 -070041import android.graphics.Matrix;
Dianne Hackborn284ac932009-08-28 10:34:25 -070042import android.graphics.Paint;
Dianne Hackborn19382ac2009-09-11 21:13:37 -070043import android.graphics.PixelFormat;
Jeff Brown24572372011-06-09 19:05:15 -070044import android.graphics.PorterDuff;
45import android.graphics.PorterDuffXfermode;
Dianne Hackborn284ac932009-08-28 10:34:25 -070046import android.graphics.Rect;
Michael Jurkab668d0b2013-10-04 15:11:05 -070047import android.graphics.RectF;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070048import android.graphics.drawable.BitmapDrawable;
49import android.graphics.drawable.Drawable;
Michael Jurkae8d1bf72013-09-09 15:58:54 +020050import android.net.Uri;
Christopher Tate93252de2017-06-15 14:48:41 -070051import android.os.Build;
Dianne Hackborn284ac932009-08-28 10:34:25 -070052import android.os.Bundle;
Christopher Tate98d609c2016-05-18 17:31:58 -070053import android.os.DeadSystemException;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070054import android.os.Handler;
55import android.os.IBinder;
Dianne Hackborn840c3a22009-09-02 17:35:17 -070056import android.os.Looper;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070057import android.os.ParcelFileDescriptor;
58import android.os.RemoteException;
59import android.os.ServiceManager;
Jeff Sharkey28f08772014-04-16 09:41:58 -070060import android.os.SystemProperties;
Jorim Jaggie31f6b82016-07-01 16:15:09 -070061import android.os.UserHandle;
Lucas Dupineeb36be2017-08-04 10:45:12 -070062import android.service.wallpaper.WallpaperService;
Jeff Sharkey28f08772014-04-16 09:41:58 -070063import android.text.TextUtils;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -070064import android.util.Log;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -070065import android.util.Pair;
Jeff Brown98365d72012-08-19 20:30:52 -070066import android.view.WindowManagerGlobal;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070067
Christopher Tateffa6a882015-12-11 15:08:46 -080068import libcore.io.IoUtils;
69
Michael Jurkab668d0b2013-10-04 15:11:05 -070070import java.io.BufferedInputStream;
Jeff Sharkey28f08772014-04-16 09:41:58 -070071import java.io.File;
72import java.io.FileInputStream;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070073import java.io.FileOutputStream;
74import java.io.IOException;
75import java.io.InputStream;
Christopher Tatead3c2592016-01-20 18:13:17 -080076import java.lang.annotation.Retention;
77import java.lang.annotation.RetentionPolicy;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -070078import java.util.ArrayList;
Michael Jurkae8d1bf72013-09-09 15:58:54 +020079import java.util.List;
Christopher Tate1e1e2e02016-01-25 15:34:36 -080080import java.util.concurrent.CountDownLatch;
81import java.util.concurrent.TimeUnit;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070082
Scott Main8b2e0002009-09-29 18:17:31 -070083/**
84 * Provides access to the system wallpaper. With WallpaperManager, you can
85 * get the current wallpaper, get the desired dimensions for the wallpaper, set
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060086 * the wallpaper, and more.
Benjamin Franzf3ece362015-02-11 10:51:10 +000087 *
88 * <p> An app can check whether wallpapers are supported for the current user, by calling
Oleksandr Peletskyif2519812016-01-26 20:16:06 +010089 * {@link #isWallpaperSupported()}, and whether setting of wallpapers is allowed, by calling
Christopher Tate98d609c2016-05-18 17:31:58 -070090 * {@link #isSetWallpaperAllowed()}.
Scott Main8b2e0002009-09-29 18:17:31 -070091 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060092@SystemService(Context.WALLPAPER_SERVICE)
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070093public class WallpaperManager {
94 private static String TAG = "WallpaperManager";
95 private static boolean DEBUG = false;
Marco Nelissenbf6956b2009-11-09 15:21:13 -080096 private float mWallpaperXStep = -1;
97 private float mWallpaperYStep = -1;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070098
Jeff Sharkey28f08772014-04-16 09:41:58 -070099 /** {@hide} */
100 private static final String PROP_WALLPAPER = "ro.config.wallpaper";
101 /** {@hide} */
Christopher Tate5d99d472016-05-06 17:59:27 -0700102 private static final String PROP_LOCK_WALLPAPER = "ro.config.lock_wallpaper";
103 /** {@hide} */
Jeff Sharkey28f08772014-04-16 09:41:58 -0700104 private static final String PROP_WALLPAPER_COMPONENT = "ro.config.wallpaper_component";
105
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700106 /**
Michael Jurkae8d1bf72013-09-09 15:58:54 +0200107 * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
108 * an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
109 * <p>Input: {@link Intent#getData} is the URI of the image to crop and set as wallpaper.
110 * <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
Adam Lesinskibba72d12013-10-11 18:10:56 -0700111 * Activities that support this intent should specify a MIME filter of "image/*"
Michael Jurkae8d1bf72013-09-09 15:58:54 +0200112 */
Jeff Sharkey0f3f60b2017-04-24 18:06:20 -0600113 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Michael Jurkae8d1bf72013-09-09 15:58:54 +0200114 public static final String ACTION_CROP_AND_SET_WALLPAPER =
115 "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
116
117 /**
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700118 * Launch an activity for the user to pick the current global live
119 * wallpaper.
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700120 */
121 public static final String ACTION_LIVE_WALLPAPER_CHOOSER
122 = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
Adam Cohen5a242ec2010-12-07 21:07:07 -0800123
124 /**
Dianne Hackborn7df7d202012-04-19 18:00:04 -0700125 * Directly launch live wallpaper preview, allowing the user to immediately
126 * confirm to switch to a specific live wallpaper. You must specify
127 * {@link #EXTRA_LIVE_WALLPAPER_COMPONENT} with the ComponentName of
128 * a live wallpaper component that is to be shown.
129 */
130 public static final String ACTION_CHANGE_LIVE_WALLPAPER
131 = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER";
132
133 /**
134 * Extra in {@link #ACTION_CHANGE_LIVE_WALLPAPER} that specifies the
135 * ComponentName of a live wallpaper that should be shown as a preview,
136 * for the user to confirm.
137 */
138 public static final String EXTRA_LIVE_WALLPAPER_COMPONENT
139 = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
140
141 /**
Adam Cohen5a242ec2010-12-07 21:07:07 -0800142 * Manifest entry for activities that respond to {@link Intent#ACTION_SET_WALLPAPER}
143 * which allows them to provide a custom large icon associated with this action.
144 */
145 public static final String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
146
Dianne Hackborn23ef7b42009-11-18 18:20:39 -0800147 /**
148 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
149 * host when the user taps on an empty area (not performing an action
150 * in the host). The x and y arguments are the location of the tap in
151 * screen coordinates.
152 */
153 public static final String COMMAND_TAP = "android.wallpaper.tap";
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100154
Dianne Hackborn23ef7b42009-11-18 18:20:39 -0800155 /**
156 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
Jeff Brown9f3bdfe2010-10-13 06:01:27 -0700157 * host when the user releases a secondary pointer on an empty area
158 * (not performing an action in the host). The x and y arguments are
159 * the location of the secondary tap in screen coordinates.
160 */
161 public static final String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
162
163 /**
164 * Command for {@link #sendWallpaperCommand}: reported by the wallpaper
Dianne Hackborn23ef7b42009-11-18 18:20:39 -0800165 * host when the user drops an object into an area of the host. The x
166 * and y arguments are the location of the drop.
167 */
168 public static final String COMMAND_DROP = "android.home.drop";
Christopher Tatead3c2592016-01-20 18:13:17 -0800169
170 /**
171 * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
172 * @hide
173 */
174 public static final String EXTRA_NEW_WALLPAPER_ID = "android.service.wallpaper.extra.ID";
175
Christopher Tate5d99d472016-05-06 17:59:27 -0700176 // flags for which kind of wallpaper to act on
Christopher Tatead3c2592016-01-20 18:13:17 -0800177
178 /** @hide */
179 @IntDef(flag = true, value = {
Christopher Tateedf7d042016-03-29 18:24:25 -0700180 FLAG_SYSTEM,
181 FLAG_LOCK
Christopher Tatead3c2592016-01-20 18:13:17 -0800182 })
183 @Retention(RetentionPolicy.SOURCE)
184 public @interface SetWallpaperFlags {}
185
186 /**
Christopher Tate5d99d472016-05-06 17:59:27 -0700187 * Flag: set or retrieve the general system wallpaper.
Christopher Tatead3c2592016-01-20 18:13:17 -0800188 */
Christopher Tateedf7d042016-03-29 18:24:25 -0700189 public static final int FLAG_SYSTEM = 1 << 0;
Christopher Tatead3c2592016-01-20 18:13:17 -0800190
191 /**
Christopher Tate5d99d472016-05-06 17:59:27 -0700192 * Flag: set or retrieve the lock-screen-specific wallpaper.
Christopher Tatead3c2592016-01-20 18:13:17 -0800193 */
Christopher Tateedf7d042016-03-29 18:24:25 -0700194 public static final int FLAG_LOCK = 1 << 1;
Christopher Tatead3c2592016-01-20 18:13:17 -0800195
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700196 private final Context mContext;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100197
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700198 /**
199 * Special drawable that draws a wallpaper as fast as possible. Assumes
200 * no scaling or placement off (0,0) of the wallpaper (this should be done
201 * at the time the bitmap is loaded).
202 */
203 static class FastBitmapDrawable extends Drawable {
204 private final Bitmap mBitmap;
205 private final int mWidth;
206 private final int mHeight;
207 private int mDrawLeft;
208 private int mDrawTop;
Romain Guy407ec782011-08-24 17:06:58 -0700209 private final Paint mPaint;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700210
211 private FastBitmapDrawable(Bitmap bitmap) {
212 mBitmap = bitmap;
213 mWidth = bitmap.getWidth();
214 mHeight = bitmap.getHeight();
Romain Guy407ec782011-08-24 17:06:58 -0700215
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700216 setBounds(0, 0, mWidth, mHeight);
Romain Guy407ec782011-08-24 17:06:58 -0700217
218 mPaint = new Paint();
219 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700220 }
221
222 @Override
223 public void draw(Canvas canvas) {
Romain Guy407ec782011-08-24 17:06:58 -0700224 canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, mPaint);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700225 }
226
227 @Override
228 public int getOpacity() {
229 return PixelFormat.OPAQUE;
230 }
231
232 @Override
233 public void setBounds(int left, int top, int right, int bottom) {
234 mDrawLeft = left + (right-left - mWidth) / 2;
235 mDrawTop = top + (bottom-top - mHeight) / 2;
236 }
237
238 @Override
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700239 public void setAlpha(int alpha) {
Romain Guy407ec782011-08-24 17:06:58 -0700240 throw new UnsupportedOperationException("Not supported with this drawable");
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700241 }
242
243 @Override
Chris Craikbd3bfc52015-03-02 10:43:29 -0800244 public void setColorFilter(ColorFilter colorFilter) {
Romain Guy407ec782011-08-24 17:06:58 -0700245 throw new UnsupportedOperationException("Not supported with this drawable");
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700246 }
247
248 @Override
249 public void setDither(boolean dither) {
Romain Guy407ec782011-08-24 17:06:58 -0700250 throw new UnsupportedOperationException("Not supported with this drawable");
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700251 }
252
253 @Override
254 public void setFilterBitmap(boolean filter) {
Romain Guy407ec782011-08-24 17:06:58 -0700255 throw new UnsupportedOperationException("Not supported with this drawable");
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700256 }
257
258 @Override
259 public int getIntrinsicWidth() {
260 return mWidth;
261 }
262
263 @Override
264 public int getIntrinsicHeight() {
265 return mHeight;
266 }
267
268 @Override
269 public int getMinimumWidth() {
270 return mWidth;
271 }
272
273 @Override
274 public int getMinimumHeight() {
275 return mHeight;
276 }
277 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100278
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700279 private static class Globals extends IWallpaperManagerCallback.Stub {
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700280 private final IWallpaperManager mService;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700281 private boolean mColorCallbackRegistered;
282 private final ArrayList<Pair<OnColorsChangedListener, Handler>> mColorListeners =
283 new ArrayList<>();
Vadim Tryshev93a914a2016-03-07 12:48:51 -0800284 private Bitmap mCachedWallpaper;
285 private int mCachedWallpaperUserId;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700286 private Bitmap mDefaultWallpaper;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700287 private Handler mMainLooperHandler;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100288
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700289 Globals(Looper looper) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700290 IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
291 mService = IWallpaperManager.Stub.asInterface(b);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700292 mMainLooperHandler = new Handler(looper);
Christopher Tatebe132e62016-02-10 12:59:49 -0800293 forgetLoadedWallpaper();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700294 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100295
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700296 public void onWallpaperChanged() {
297 /* The wallpaper has changed but we shouldn't eagerly load the
298 * wallpaper as that would be inefficient. Reset the cached wallpaper
299 * to null so if the user requests the wallpaper again then we'll
300 * fetch it.
301 */
Christopher Tatebe132e62016-02-10 12:59:49 -0800302 forgetLoadedWallpaper();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700303 }
Adam Cohen041a0ba2011-11-09 20:10:27 -0800304
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700305 /**
306 * Start listening to wallpaper color events.
307 * Will be called whenever someone changes their wallpaper or if a live wallpaper
308 * changes its colors.
309 * @param callback Listener
310 * @param handler Thread to call it from. Main thread if null.
Lucas Dupin50ba9912017-07-14 11:55:05 -0700311 * @param userId Owner of the wallpaper or UserHandle.USER_ALL
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700312 */
313 public void addOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
Lucas Dupin50ba9912017-07-14 11:55:05 -0700314 @Nullable Handler handler, int userId) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700315 synchronized (this) {
316 if (!mColorCallbackRegistered) {
317 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700318 mService.registerWallpaperColorsCallback(this, userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700319 mColorCallbackRegistered = true;
320 } catch (RemoteException e) {
321 // Failed, service is gone
322 Log.w(TAG, "Can't register for color updates", e);
323 }
324 }
325 mColorListeners.add(new Pair<>(callback, handler));
326 }
327 }
328
329 /**
330 * Stop listening to wallpaper color events.
331 *
332 * @param callback listener
Lucas Dupin50ba9912017-07-14 11:55:05 -0700333 * @param userId Owner of the wallpaper or UserHandle.USER_ALL
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700334 */
Lucas Dupin50ba9912017-07-14 11:55:05 -0700335 public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
336 int userId) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700337 synchronized (this) {
338 mColorListeners.removeIf(pair -> pair.first == callback);
339
340 if (mColorListeners.size() == 0 && mColorCallbackRegistered) {
341 mColorCallbackRegistered = false;
342 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700343 mService.unregisterWallpaperColorsCallback(this, userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700344 } catch (RemoteException e) {
345 // Failed, service is gone
346 Log.w(TAG, "Can't unregister color updates", e);
347 }
348 }
349 }
350 }
351
352 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -0700353 public void onWallpaperColorsChanged(WallpaperColors colors, int which, int userId) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700354 synchronized (this) {
355 for (Pair<OnColorsChangedListener, Handler> listener : mColorListeners) {
356 Handler handler = listener.second;
357 if (listener.second == null) {
358 handler = mMainLooperHandler;
359 }
360 handler.post(() -> {
361 // Dealing with race conditions between posting a callback and
362 // removeOnColorsChangedListener being called.
363 boolean stillExists;
364 synchronized (sGlobals) {
365 stillExists = mColorListeners.contains(listener);
366 }
367 if (stillExists) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700368 listener.first.onColorsChanged(colors, which, userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700369 }
370 });
371 }
372 }
373 }
374
Lucas Dupin50ba9912017-07-14 11:55:05 -0700375 WallpaperColors getWallpaperColors(int which, int userId) {
Christopher Tatedbf4a9c2017-06-27 12:37:23 -0700376 if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
377 throw new IllegalArgumentException(
378 "Must request colors for exactly one kind of wallpaper");
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700379 }
Christopher Tatedbf4a9c2017-06-27 12:37:23 -0700380
381 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700382 return mService.getWallpaperColors(which, userId);
Christopher Tatedbf4a9c2017-06-27 12:37:23 -0700383 } catch (RemoteException e) {
384 // Can't get colors, connection lost.
385 }
386 return null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700387 }
388
Christopher Tate5d99d472016-05-06 17:59:27 -0700389 public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
390 @SetWallpaperFlags int which) {
391 return peekWallpaperBitmap(context, returnDefault, which, context.getUserId());
Yorke Leedcd93cc2016-01-08 14:12:55 -0800392 }
393
Christopher Tate5d99d472016-05-06 17:59:27 -0700394 public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
395 @SetWallpaperFlags int which, int userId) {
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700396 if (mService != null) {
397 try {
398 if (!mService.isWallpaperSupported(context.getOpPackageName())) {
399 return null;
Benjamin Franzf3ece362015-02-11 10:51:10 +0000400 }
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700401 } catch (RemoteException e) {
402 throw e.rethrowFromSystemServer();
Benjamin Franzf3ece362015-02-11 10:51:10 +0000403 }
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700404 }
405 synchronized (this) {
Vadim Tryshev93a914a2016-03-07 12:48:51 -0800406 if (mCachedWallpaper != null && mCachedWallpaperUserId == userId) {
407 return mCachedWallpaper;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700408 }
Vadim Tryshev93a914a2016-03-07 12:48:51 -0800409 mCachedWallpaper = null;
410 mCachedWallpaperUserId = 0;
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800411 try {
Christopher Tate93252de2017-06-15 14:48:41 -0700412 mCachedWallpaper = getCurrentWallpaperLocked(context, userId);
Vadim Tryshev93a914a2016-03-07 12:48:51 -0800413 mCachedWallpaperUserId = userId;
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800414 } catch (OutOfMemoryError e) {
Christopher Tate93252de2017-06-15 14:48:41 -0700415 Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
416 } catch (SecurityException e) {
417 if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.O) {
418 Log.w(TAG, "No permission to access wallpaper, suppressing"
419 + " exception to avoid crashing legacy app.");
420 } else {
421 // Post-O apps really most sincerely need the permission.
422 throw e;
423 }
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800424 }
Vadim Tryshev93a914a2016-03-07 12:48:51 -0800425 if (mCachedWallpaper != null) {
426 return mCachedWallpaper;
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700427 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700428 }
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700429 if (returnDefault) {
430 Bitmap defaultWallpaper = mDefaultWallpaper;
431 if (defaultWallpaper == null) {
432 defaultWallpaper = getDefaultWallpaper(context, which);
433 synchronized (this) {
434 mDefaultWallpaper = defaultWallpaper;
435 }
436 }
437 return defaultWallpaper;
438 }
439 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700440 }
Dianne Hackbornba398392011-08-01 16:11:57 -0700441
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700442 void forgetLoadedWallpaper() {
Dianne Hackbornba398392011-08-01 16:11:57 -0700443 synchronized (this) {
Vadim Tryshev93a914a2016-03-07 12:48:51 -0800444 mCachedWallpaper = null;
445 mCachedWallpaperUserId = 0;
Dianne Hackbornba398392011-08-01 16:11:57 -0700446 mDefaultWallpaper = null;
447 }
448 }
449
Christopher Tate93252de2017-06-15 14:48:41 -0700450 private Bitmap getCurrentWallpaperLocked(Context context, int userId) {
Adam Lesinski2c8d67c2014-04-23 13:46:21 -0700451 if (mService == null) {
452 Log.w(TAG, "WallpaperService not running");
453 return null;
454 }
455
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700456 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700457 Bundle params = new Bundle();
Christopher Tate93252de2017-06-15 14:48:41 -0700458 ParcelFileDescriptor fd = mService.getWallpaper(context.getOpPackageName(),
459 this, FLAG_SYSTEM, params, userId);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700460 if (fd != null) {
Jeff Brown24572372011-06-09 19:05:15 -0700461 try {
462 BitmapFactory.Options options = new BitmapFactory.Options();
Michael Jurka824a4b52013-12-18 17:10:16 +0100463 return BitmapFactory.decodeFileDescriptor(
Jeff Brown24572372011-06-09 19:05:15 -0700464 fd.getFileDescriptor(), null, options);
Jeff Brown24572372011-06-09 19:05:15 -0700465 } catch (OutOfMemoryError e) {
466 Log.w(TAG, "Can't decode file", e);
467 } finally {
Christopher Tateffa6a882015-12-11 15:08:46 -0800468 IoUtils.closeQuietly(fd);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700469 }
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700470 }
471 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700472 throw e.rethrowFromSystemServer();
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700473 }
474 return null;
475 }
Christopher Tateffa6a882015-12-11 15:08:46 -0800476
Fyodor Kupolovb6378cf2016-07-12 10:32:08 -0700477 private Bitmap getDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
Christopher Tate5d99d472016-05-06 17:59:27 -0700478 InputStream is = openDefaultWallpaper(context, which);
Adam Lesinski2c8d67c2014-04-23 13:46:21 -0700479 if (is != null) {
480 try {
481 BitmapFactory.Options options = new BitmapFactory.Options();
482 return BitmapFactory.decodeStream(is, null, options);
483 } catch (OutOfMemoryError e) {
484 Log.w(TAG, "Can't decode stream", e);
485 } finally {
Christopher Tateffa6a882015-12-11 15:08:46 -0800486 IoUtils.closeQuietly(is);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700487 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700488 }
489 return null;
490 }
491 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100492
Romain Guy407ec782011-08-24 17:06:58 -0700493 private static final Object sSync = new Object[0];
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700494 private static Globals sGlobals;
495
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700496 static void initGlobals(Looper looper) {
Romain Guy407ec782011-08-24 17:06:58 -0700497 synchronized (sSync) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700498 if (sGlobals == null) {
Dianne Hackborn5e802fb2009-09-02 21:50:50 -0700499 sGlobals = new Globals(looper);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700500 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700501 }
502 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100503
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700504 /*package*/ WallpaperManager(Context context, Handler handler) {
505 mContext = context;
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700506 initGlobals(context.getMainLooper());
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700507 }
508
509 /**
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700510 * Retrieve a WallpaperManager associated with the given Context.
511 */
512 public static WallpaperManager getInstance(Context context) {
513 return (WallpaperManager)context.getSystemService(
514 Context.WALLPAPER_SERVICE);
515 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100516
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700517 /** @hide */
518 public IWallpaperManager getIWallpaperManager() {
Dianne Hackborn840c3a22009-09-02 17:35:17 -0700519 return sGlobals.mService;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700520 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100521
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700522 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700523 * Retrieve the current system wallpaper; if
Michael Jurkab668d0b2013-10-04 15:11:05 -0700524 * no wallpaper is set, the system built-in static wallpaper is returned.
Scott Main8b2e0002009-09-29 18:17:31 -0700525 * This is returned as an
526 * abstract Drawable that you can install in a View to display whatever
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100527 * wallpaper the user has currently set.
Christopher Tate41dc83bd2016-07-15 15:59:23 -0700528 * <p>
529 * This method can return null if there is no system wallpaper available, if
530 * wallpapers are not supported in the current user, or if the calling app is not
531 * permitted to access the system wallpaper.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700532 *
Christopher Tate41dc83bd2016-07-15 15:59:23 -0700533 * @return Returns a Drawable object that will draw the system wallpaper,
534 * or {@code null} if no system wallpaper exists or if the calling application
535 * is not able to access the wallpaper.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700536 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700537 public Drawable getDrawable() {
Christopher Tate5d99d472016-05-06 17:59:27 -0700538 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700539 if (bm != null) {
540 Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
541 dr.setDither(false);
542 return dr;
543 }
544 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700545 }
546
547 /**
Christopher Tate5d99d472016-05-06 17:59:27 -0700548 * Obtain a drawable for the built-in static system wallpaper.
Michael Jurkab668d0b2013-10-04 15:11:05 -0700549 */
550 public Drawable getBuiltInDrawable() {
Christopher Tate5d99d472016-05-06 17:59:27 -0700551 return getBuiltInDrawable(0, 0, false, 0, 0, FLAG_SYSTEM);
552 }
553
554 /**
555 * Obtain a drawable for the specified built-in static system wallpaper.
556 *
557 * @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
558 * IllegalArgumentException if an invalid wallpaper is requested.
559 * @return A Drawable presenting the specified wallpaper image, or {@code null}
560 * if no built-in default image for that wallpaper type exists.
561 */
562 public Drawable getBuiltInDrawable(@SetWallpaperFlags int which) {
563 return getBuiltInDrawable(0, 0, false, 0, 0, which);
Michael Jurkab668d0b2013-10-04 15:11:05 -0700564 }
565
566 /**
567 * Returns a drawable for the system built-in static wallpaper. Based on the parameters, the
568 * drawable can be cropped and scaled
569 *
570 * @param outWidth The width of the returned drawable
571 * @param outWidth The height of the returned drawable
572 * @param scaleToFit If true, scale the wallpaper down rather than just cropping it
573 * @param horizontalAlignment A float value between 0 and 1 specifying where to crop the image;
574 * 0 for left-aligned, 0.5 for horizontal center-aligned, and 1 for right-aligned
575 * @param verticalAlignment A float value between 0 and 1 specifying where to crop the image;
576 * 0 for top-aligned, 0.5 for vertical center-aligned, and 1 for bottom-aligned
Christopher Tate5d99d472016-05-06 17:59:27 -0700577 * @return A Drawable presenting the built-in default system wallpaper image,
578 * or {@code null} if no such default image is defined on this device.
Michael Jurkab668d0b2013-10-04 15:11:05 -0700579 */
580 public Drawable getBuiltInDrawable(int outWidth, int outHeight,
581 boolean scaleToFit, float horizontalAlignment, float verticalAlignment) {
Christopher Tate5d99d472016-05-06 17:59:27 -0700582 return getBuiltInDrawable(outWidth, outHeight, scaleToFit,
583 horizontalAlignment, verticalAlignment, FLAG_SYSTEM);
584 }
585
586 /**
587 * Returns a drawable for the built-in static wallpaper of the specified type. Based on the
588 * parameters, the drawable can be cropped and scaled.
589 *
590 * @param outWidth The width of the returned drawable
591 * @param outWidth The height of the returned drawable
592 * @param scaleToFit If true, scale the wallpaper down rather than just cropping it
593 * @param horizontalAlignment A float value between 0 and 1 specifying where to crop the image;
594 * 0 for left-aligned, 0.5 for horizontal center-aligned, and 1 for right-aligned
595 * @param verticalAlignment A float value between 0 and 1 specifying where to crop the image;
596 * 0 for top-aligned, 0.5 for vertical center-aligned, and 1 for bottom-aligned
597 * @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
598 * IllegalArgumentException if an invalid wallpaper is requested.
599 * @return A Drawable presenting the built-in default wallpaper image of the given type,
600 * or {@code null} if no default image of that type is defined on this device.
601 */
602 public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
603 float horizontalAlignment, float verticalAlignment, @SetWallpaperFlags int which) {
Michael Jurkab668d0b2013-10-04 15:11:05 -0700604 if (sGlobals.mService == null) {
605 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -0700606 throw new RuntimeException(new DeadSystemException());
Michael Jurkab668d0b2013-10-04 15:11:05 -0700607 }
Christopher Tate5d99d472016-05-06 17:59:27 -0700608
609 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
610 throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
611 }
612
Michael Jurkab668d0b2013-10-04 15:11:05 -0700613 Resources resources = mContext.getResources();
614 horizontalAlignment = Math.max(0, Math.min(1, horizontalAlignment));
615 verticalAlignment = Math.max(0, Math.min(1, verticalAlignment));
616
Christopher Tate5d99d472016-05-06 17:59:27 -0700617 InputStream wpStream = openDefaultWallpaper(mContext, which);
618 if (wpStream == null) {
619 if (DEBUG) {
620 Log.w(TAG, "default wallpaper stream " + which + " is null");
621 }
Michael Jurkab668d0b2013-10-04 15:11:05 -0700622 return null;
623 } else {
Christopher Tate5d99d472016-05-06 17:59:27 -0700624 InputStream is = new BufferedInputStream(wpStream);
Michael Jurkab668d0b2013-10-04 15:11:05 -0700625 if (outWidth <= 0 || outHeight <= 0) {
626 Bitmap fullSize = BitmapFactory.decodeStream(is, null, null);
627 return new BitmapDrawable(resources, fullSize);
628 } else {
629 int inWidth;
630 int inHeight;
Christopher Tate5d99d472016-05-06 17:59:27 -0700631 // Just measure this time through...
Michael Jurkab668d0b2013-10-04 15:11:05 -0700632 {
633 BitmapFactory.Options options = new BitmapFactory.Options();
634 options.inJustDecodeBounds = true;
635 BitmapFactory.decodeStream(is, null, options);
636 if (options.outWidth != 0 && options.outHeight != 0) {
637 inWidth = options.outWidth;
638 inHeight = options.outHeight;
639 } else {
640 Log.e(TAG, "default wallpaper dimensions are 0");
641 return null;
642 }
643 }
644
Christopher Tate5d99d472016-05-06 17:59:27 -0700645 // Reopen the stream to do the full decode. We know at this point
646 // that openDefaultWallpaper() will return non-null.
647 is = new BufferedInputStream(openDefaultWallpaper(mContext, which));
Michael Jurkab668d0b2013-10-04 15:11:05 -0700648
649 RectF cropRectF;
650
651 outWidth = Math.min(inWidth, outWidth);
652 outHeight = Math.min(inHeight, outHeight);
653 if (scaleToFit) {
654 cropRectF = getMaxCropRect(inWidth, inHeight, outWidth, outHeight,
655 horizontalAlignment, verticalAlignment);
656 } else {
657 float left = (inWidth - outWidth) * horizontalAlignment;
658 float right = left + outWidth;
659 float top = (inHeight - outHeight) * verticalAlignment;
660 float bottom = top + outHeight;
Michael Jurka05391532013-10-14 20:44:42 -0700661 cropRectF = new RectF(left, top, right, bottom);
Michael Jurkab668d0b2013-10-04 15:11:05 -0700662 }
663 Rect roundedTrueCrop = new Rect();
664 cropRectF.roundOut(roundedTrueCrop);
665
666 if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
667 Log.w(TAG, "crop has bad values for full size image");
668 return null;
669 }
670
671 // See how much we're reducing the size of the image
672 int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / outWidth,
673 roundedTrueCrop.height() / outHeight);
674
675 // Attempt to open a region decoder
676 BitmapRegionDecoder decoder = null;
677 try {
678 decoder = BitmapRegionDecoder.newInstance(is, true);
679 } catch (IOException e) {
680 Log.w(TAG, "cannot open region decoder for default wallpaper");
681 }
682
683 Bitmap crop = null;
684 if (decoder != null) {
685 // Do region decoding to get crop bitmap
686 BitmapFactory.Options options = new BitmapFactory.Options();
687 if (scaleDownSampleSize > 1) {
688 options.inSampleSize = scaleDownSampleSize;
689 }
690 crop = decoder.decodeRegion(roundedTrueCrop, options);
691 decoder.recycle();
692 }
693
694 if (crop == null) {
Christopher Tate5d99d472016-05-06 17:59:27 -0700695 // BitmapRegionDecoder has failed, try to crop in-memory. We know at
696 // this point that openDefaultWallpaper() will return non-null.
697 is = new BufferedInputStream(openDefaultWallpaper(mContext, which));
Michael Jurkab668d0b2013-10-04 15:11:05 -0700698 Bitmap fullSize = null;
Christopher Tate5d99d472016-05-06 17:59:27 -0700699 BitmapFactory.Options options = new BitmapFactory.Options();
700 if (scaleDownSampleSize > 1) {
701 options.inSampleSize = scaleDownSampleSize;
Michael Jurkab668d0b2013-10-04 15:11:05 -0700702 }
Christopher Tate5d99d472016-05-06 17:59:27 -0700703 fullSize = BitmapFactory.decodeStream(is, null, options);
Michael Jurkab668d0b2013-10-04 15:11:05 -0700704 if (fullSize != null) {
705 crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
706 roundedTrueCrop.top, roundedTrueCrop.width(),
707 roundedTrueCrop.height());
708 }
709 }
710
711 if (crop == null) {
712 Log.w(TAG, "cannot decode default wallpaper");
713 return null;
714 }
715
716 // Scale down if necessary
717 if (outWidth > 0 && outHeight > 0 &&
718 (crop.getWidth() != outWidth || crop.getHeight() != outHeight)) {
719 Matrix m = new Matrix();
720 RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
721 RectF returnRect = new RectF(0, 0, outWidth, outHeight);
722 m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
723 Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
724 (int) returnRect.height(), Bitmap.Config.ARGB_8888);
725 if (tmp != null) {
726 Canvas c = new Canvas(tmp);
727 Paint p = new Paint();
728 p.setFilterBitmap(true);
729 c.drawBitmap(crop, m, p);
730 crop = tmp;
731 }
732 }
733
734 return new BitmapDrawable(resources, crop);
735 }
736 }
737 }
738
739 private static RectF getMaxCropRect(int inWidth, int inHeight, int outWidth, int outHeight,
740 float horizontalAlignment, float verticalAlignment) {
741 RectF cropRect = new RectF();
742 // Get a crop rect that will fit this
743 if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
744 cropRect.top = 0;
745 cropRect.bottom = inHeight;
746 float cropWidth = outWidth * (inHeight / (float) outHeight);
747 cropRect.left = (inWidth - cropWidth) * horizontalAlignment;
748 cropRect.right = cropRect.left + cropWidth;
749 } else {
750 cropRect.left = 0;
751 cropRect.right = inWidth;
752 float cropHeight = outHeight * (inWidth / (float) outWidth);
753 cropRect.top = (inHeight - cropHeight) * verticalAlignment;
754 cropRect.bottom = cropRect.top + cropHeight;
755 }
756 return cropRect;
757 }
758
759 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700760 * Retrieve the current system wallpaper; if there is no wallpaper set,
761 * a null pointer is returned. This is returned as an
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700762 * abstract Drawable that you can install in a View to display whatever
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100763 * wallpaper the user has currently set.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700764 *
765 * @return Returns a Drawable object that will draw the wallpaper or a
766 * null pointer if these is none.
767 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700768 public Drawable peekDrawable() {
Christopher Tate5d99d472016-05-06 17:59:27 -0700769 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700770 if (bm != null) {
771 Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
772 dr.setDither(false);
773 return dr;
774 }
775 return null;
776 }
777
778 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700779 * Like {@link #getDrawable()}, but the returned Drawable has a number
780 * of limitations to reduce its overhead as much as possible. It will
781 * never scale the wallpaper (only centering it if the requested bounds
782 * do match the bitmap bounds, which should not be typical), doesn't
783 * allow setting an alpha, color filter, or other attributes, etc. The
784 * bounds of the returned drawable will be initialized to the same bounds
785 * as the wallpaper, so normally you will not need to touch it. The
786 * drawable also assumes that it will be used in a context running in
787 * the same density as the screen (not in density compatibility mode).
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700788 *
789 * @return Returns a Drawable object that will draw the wallpaper.
790 */
Christopher Tate93252de2017-06-15 14:48:41 -0700791 @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700792 public Drawable getFastDrawable() {
Christopher Tate5d99d472016-05-06 17:59:27 -0700793 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700794 if (bm != null) {
Romain Guy407ec782011-08-24 17:06:58 -0700795 return new FastBitmapDrawable(bm);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700796 }
797 return null;
798 }
799
800 /**
Scott Main8b2e0002009-09-29 18:17:31 -0700801 * Like {@link #getFastDrawable()}, but if there is no wallpaper set,
802 * a null pointer is returned.
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700803 *
804 * @return Returns an optimized Drawable object that will draw the
805 * wallpaper or a null pointer if these is none.
806 */
Christopher Tate93252de2017-06-15 14:48:41 -0700807 @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700808 public Drawable peekFastDrawable() {
Christopher Tate5d99d472016-05-06 17:59:27 -0700809 Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700810 if (bm != null) {
Romain Guy407ec782011-08-24 17:06:58 -0700811 return new FastBitmapDrawable(bm);
Dianne Hackborn19382ac2009-09-11 21:13:37 -0700812 }
813 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700814 }
815
816 /**
Romain Guy407ec782011-08-24 17:06:58 -0700817 * Like {@link #getDrawable()} but returns a Bitmap.
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100818 *
Romain Guy407ec782011-08-24 17:06:58 -0700819 * @hide
820 */
821 public Bitmap getBitmap() {
Yorke Leedcd93cc2016-01-08 14:12:55 -0800822 return getBitmapAsUser(mContext.getUserId());
823 }
824
825 /**
826 * Like {@link #getDrawable()} but returns a Bitmap for the provided user.
827 *
828 * @hide
829 */
830 public Bitmap getBitmapAsUser(int userId) {
Christopher Tate5d99d472016-05-06 17:59:27 -0700831 return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId);
Romain Guy407ec782011-08-24 17:06:58 -0700832 }
833
834 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800835 * Get an open, readable file descriptor to the given wallpaper image file.
Christopher Tateedf7d042016-03-29 18:24:25 -0700836 * The caller is responsible for closing the file descriptor when done ingesting the file.
Christopher Tatebe132e62016-02-10 12:59:49 -0800837 *
838 * <p>If no lock-specific wallpaper has been configured for the given user, then
Christopher Tateedf7d042016-03-29 18:24:25 -0700839 * this method will return {@code null} when requesting {@link #FLAG_LOCK} rather than
Christopher Tatebe132e62016-02-10 12:59:49 -0800840 * returning the system wallpaper's image file.
Christopher Tateedf7d042016-03-29 18:24:25 -0700841 *
842 * @param which The wallpaper whose image file is to be retrieved. Must be a single
843 * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
844 * {@link #FLAG_LOCK}.
Christopher Tate93252de2017-06-15 14:48:41 -0700845 * @return An open, readable file desriptor to the requested wallpaper image file;
846 * or {@code null} if no such wallpaper is configured or if the calling app does
847 * not have permission to read the current wallpaper.
Christopher Tateedf7d042016-03-29 18:24:25 -0700848 *
849 * @see #FLAG_LOCK
850 * @see #FLAG_SYSTEM
Christopher Tatebe132e62016-02-10 12:59:49 -0800851 */
Christopher Tate93252de2017-06-15 14:48:41 -0700852 @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
Christopher Tate5d99d472016-05-06 17:59:27 -0700853 public ParcelFileDescriptor getWallpaperFile(@SetWallpaperFlags int which) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800854 return getWallpaperFile(which, mContext.getUserId());
855 }
856
Lucas Dupinc40608c2017-04-14 18:33:08 -0700857 /**
858 * Registers a listener to get notified when the wallpaper colors change.
Lucas Dupinc40608c2017-04-14 18:33:08 -0700859 * @param listener A listener to register
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700860 * @param handler Where to call it from. Will be called from the main thread
Lucas Dupinc40608c2017-04-14 18:33:08 -0700861 * if null.
862 */
863 public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700864 @NonNull Handler handler) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700865 addOnColorsChangedListener(listener, handler, mContext.getUserId());
866 }
867
868 /**
869 * Registers a listener to get notified when the wallpaper colors change
870 * @param listener A listener to register
871 * @param handler Where to call it from. Will be called from the main thread
872 * if null.
873 * @param userId Owner of the wallpaper or UserHandle.USER_ALL.
874 * @hide
875 */
876 public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
877 @NonNull Handler handler, int userId) {
878 sGlobals.addOnColorsChangedListener(listener, handler, userId);
Lucas Dupinc40608c2017-04-14 18:33:08 -0700879 }
880
881 /**
882 * Stop listening to color updates.
Lucas Dupin50ba9912017-07-14 11:55:05 -0700883 * @param callback A callback to unsubscribe.
Lucas Dupinc40608c2017-04-14 18:33:08 -0700884 */
885 public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700886 removeOnColorsChangedListener(callback, mContext.getUserId());
887 }
888
889 /**
890 * Stop listening to color updates.
891 * @param callback A callback to unsubscribe.
892 * @param userId Owner of the wallpaper or UserHandle.USER_ALL.
893 * @hide
894 */
895 public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
896 int userId) {
897 sGlobals.removeOnColorsChangedListener(callback, userId);
Lucas Dupinc40608c2017-04-14 18:33:08 -0700898 }
899
900 /**
Lucas Dupineeb36be2017-08-04 10:45:12 -0700901 * Get the primary colors of a wallpaper.
902 *
903 * <p>You can expect null if:
904 * • Colors are still being processed by the system.
905 * • A live wallpaper doesn't implement {@link WallpaperService.Engine#onComputeColors()}.
906 *
907 * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
908 * {@link #FLAG_LOCK}.
909 * @return Current {@link WallpaperColors} or null if colors are unknown.
910 * @see #addOnColorsChangedListener(OnColorsChangedListener, Handler)
Lucas Dupinc40608c2017-04-14 18:33:08 -0700911 */
912 public @Nullable WallpaperColors getWallpaperColors(int which) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700913 return getWallpaperColors(which, mContext.getUserId());
914 }
915
916 /**
917 * Get the primary colors of a wallpaper
918 * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or
919 * {@link #FLAG_LOCK}
920 * @param userId Owner of the wallpaper.
921 * @return {@link WallpaperColors} or null if colors are unknown.
922 * @hide
923 */
924 public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
925 return sGlobals.getWallpaperColors(which, userId);
Lucas Dupinc40608c2017-04-14 18:33:08 -0700926 }
927
Christopher Tatebe132e62016-02-10 12:59:49 -0800928 /**
929 * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
930 * for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
931 * permission to access another user's wallpaper data.
Christopher Tateedf7d042016-03-29 18:24:25 -0700932 *
933 * @param which The wallpaper whose image file is to be retrieved. Must be a single
934 * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
935 * {@link #FLAG_LOCK}.
936 * @param userId The user or profile whose imagery is to be retrieved
937 *
938 * @see #FLAG_LOCK
939 * @see #FLAG_SYSTEM
940 *
Christopher Tatebe132e62016-02-10 12:59:49 -0800941 * @hide
942 */
Christopher Tate5d99d472016-05-06 17:59:27 -0700943 public ParcelFileDescriptor getWallpaperFile(@SetWallpaperFlags int which, int userId) {
Christopher Tateedf7d042016-03-29 18:24:25 -0700944 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800945 throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
946 }
947
948 if (sGlobals.mService == null) {
949 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -0700950 throw new RuntimeException(new DeadSystemException());
Christopher Tatebe132e62016-02-10 12:59:49 -0800951 } else {
952 try {
953 Bundle outParams = new Bundle();
Christopher Tate93252de2017-06-15 14:48:41 -0700954 return sGlobals.mService.getWallpaper(mContext.getOpPackageName(), null, which,
955 outParams, userId);
Christopher Tatebe132e62016-02-10 12:59:49 -0800956 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700957 throw e.rethrowFromSystemServer();
Christopher Tate93252de2017-06-15 14:48:41 -0700958 } catch (SecurityException e) {
959 if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.O) {
960 Log.w(TAG, "No permission to access wallpaper, suppressing"
961 + " exception to avoid crashing legacy app.");
962 return null;
963 } else {
964 throw e;
965 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800966 }
967 }
968 }
969
970 /**
Dianne Hackbornba398392011-08-01 16:11:57 -0700971 * Remove all internal references to the last loaded wallpaper. Useful
972 * for apps that want to reduce memory usage when they only temporarily
973 * need to have the wallpaper. After calling, the next request for the
974 * wallpaper will require reloading it again from disk.
975 */
976 public void forgetLoadedWallpaper() {
Christopher Tatebe132e62016-02-10 12:59:49 -0800977 sGlobals.forgetLoadedWallpaper();
Dianne Hackbornba398392011-08-01 16:11:57 -0700978 }
979
980 /**
Dianne Hackborneb034652009-09-07 00:49:58 -0700981 * If the current wallpaper is a live wallpaper component, return the
982 * information about that wallpaper. Otherwise, if it is a static image,
983 * simply return null.
Dianne Hackborneb034652009-09-07 00:49:58 -0700984 */
985 public WallpaperInfo getWallpaperInfo() {
986 try {
Mike Lockwoodc067c9c2011-10-31 12:50:12 -0400987 if (sGlobals.mService == null) {
988 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -0700989 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -0400990 } else {
Jorim Jaggie31f6b82016-07-01 16:15:09 -0700991 return sGlobals.mService.getWallpaperInfo(UserHandle.myUserId());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -0400992 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700993 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700994 throw e.rethrowFromSystemServer();
Dianne Hackborneb034652009-09-07 00:49:58 -0700995 }
996 }
Michael Jurkae8d1bf72013-09-09 15:58:54 +0200997
998 /**
Christopher Tatee409f0e2016-03-21 14:53:15 -0700999 * Get the ID of the current wallpaper of the given kind. If there is no
1000 * such wallpaper configured, returns a negative number.
1001 *
Christopher Tate98d609c2016-05-18 17:31:58 -07001002 * <p>Every time the wallpaper image is set, a new ID is assigned to it.
1003 * This method allows the caller to determine whether the wallpaper imagery
1004 * has changed, regardless of how that change happened.
1005 *
Christopher Tatee409f0e2016-03-21 14:53:15 -07001006 * @param which The wallpaper whose ID is to be returned. Must be a single
Christopher Tateedf7d042016-03-29 18:24:25 -07001007 * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
1008 * {@link #FLAG_LOCK}.
Christopher Tatee409f0e2016-03-21 14:53:15 -07001009 * @return The positive numeric ID of the current wallpaper of the given kind,
1010 * or a negative value if no such wallpaper is configured.
1011 */
Christopher Tate5d99d472016-05-06 17:59:27 -07001012 public int getWallpaperId(@SetWallpaperFlags int which) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001013 return getWallpaperIdForUser(which, mContext.getUserId());
1014 }
1015
1016 /**
1017 * Get the ID of the given user's current wallpaper of the given kind. If there
1018 * is no such wallpaper configured, returns a negative number.
1019 * @hide
1020 */
Christopher Tate5d99d472016-05-06 17:59:27 -07001021 public int getWallpaperIdForUser(@SetWallpaperFlags int which, int userId) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001022 try {
1023 if (sGlobals.mService == null) {
1024 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001025 throw new RuntimeException(new DeadSystemException());
Christopher Tatee409f0e2016-03-21 14:53:15 -07001026 } else {
1027 return sGlobals.mService.getWallpaperIdForUser(which, userId);
1028 }
1029 } catch (RemoteException e) {
1030 throw e.rethrowFromSystemServer();
1031 }
1032 }
1033
1034 /**
Michael Jurkae8d1bf72013-09-09 15:58:54 +02001035 * Gets an Intent that will launch an activity that crops the given
1036 * image and sets the device's wallpaper. If there is a default HOME activity
1037 * that supports cropping wallpapers, it will be preferred as the default.
Ying Wang930d4e52013-09-14 11:57:17 -07001038 * Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
Michael Jurkae8d1bf72013-09-09 15:58:54 +02001039 * intent.
Adam Lesinskibba72d12013-10-11 18:10:56 -07001040 *
1041 * @param imageUri The image URI that will be set in the intent. The must be a content
1042 * URI and its provider must resolve its type to "image/*"
1043 *
1044 * @throws IllegalArgumentException if the URI is not a content URI or its MIME type is
1045 * not "image/*"
Michael Jurkae8d1bf72013-09-09 15:58:54 +02001046 */
1047 public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
Allen Shen1c0f21e2014-04-29 16:16:29 +08001048 if (imageUri == null) {
1049 throw new IllegalArgumentException("Image URI must not be null");
1050 }
1051
Adam Lesinskibba72d12013-10-11 18:10:56 -07001052 if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
1053 throw new IllegalArgumentException("Image URI must be of the "
1054 + ContentResolver.SCHEME_CONTENT + " scheme type");
1055 }
1056
Michael Jurkae8d1bf72013-09-09 15:58:54 +02001057 final PackageManager packageManager = mContext.getPackageManager();
1058 Intent cropAndSetWallpaperIntent =
1059 new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
1060 cropAndSetWallpaperIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
1061
1062 // Find out if the default HOME activity supports CROP_AND_SET_WALLPAPER
1063 Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
1064 ResolveInfo resolvedHome = packageManager.resolveActivity(homeIntent,
1065 PackageManager.MATCH_DEFAULT_ONLY);
1066 if (resolvedHome != null) {
1067 cropAndSetWallpaperIntent.setPackage(resolvedHome.activityInfo.packageName);
1068
1069 List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
1070 cropAndSetWallpaperIntent, 0);
1071 if (cropAppList.size() > 0) {
1072 return cropAndSetWallpaperIntent;
1073 }
1074 }
1075
1076 // fallback crop activity
Oren Blasberg60598ea0a2016-02-26 11:01:23 -08001077 final String cropperPackage = mContext.getString(
1078 com.android.internal.R.string.config_wallpaperCropperPackage);
1079 cropAndSetWallpaperIntent.setPackage(cropperPackage);
Adam Lesinskibba72d12013-10-11 18:10:56 -07001080 List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
1081 cropAndSetWallpaperIntent, 0);
1082 if (cropAppList.size() > 0) {
1083 return cropAndSetWallpaperIntent;
1084 }
1085 // If the URI is not of the right type, or for some reason the system wallpaper
1086 // cropper doesn't exist, return null
1087 throw new IllegalArgumentException("Cannot use passed URI to set wallpaper; " +
1088 "check that the type returned by ContentProvider matches image/*");
Michael Jurkae8d1bf72013-09-09 15:58:54 +02001089 }
1090
Dianne Hackborneb034652009-09-07 00:49:58 -07001091 /**
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001092 * Change the current system wallpaper to the bitmap in the given resource.
1093 * The resource is opened as a raw data stream and copied into the
1094 * wallpaper; it must be a valid PNG or JPEG image. On success, the intent
1095 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
1096 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001097 * <p>This method requires the caller to hold the permission
1098 * {@link android.Manifest.permission#SET_WALLPAPER}.
1099 *
Christopher Tateedf7d042016-03-29 18:24:25 -07001100 * @param resid The resource ID of the bitmap to be used as the wallpaper image
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001101 *
Michael Jurkab668d0b2013-10-04 15:11:05 -07001102 * @throws IOException If an error occurs reverting to the built-in
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001103 * wallpaper.
1104 */
Christopher Tate93252de2017-06-15 14:48:41 -07001105 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Tor Norbye7b9c9122013-05-30 16:48:33 -07001106 public void setResource(@RawRes int resid) throws IOException {
Edward Savage-Jones6009d9d2016-08-30 18:44:19 +02001107 setResource(resid, FLAG_SYSTEM | FLAG_LOCK);
Christopher Tatead3c2592016-01-20 18:13:17 -08001108 }
1109
1110 /**
Christopher Tateedf7d042016-03-29 18:24:25 -07001111 * Version of {@link #setResource(int)} that allows the caller to specify which
1112 * of the supported wallpaper categories to set.
Christopher Tatead3c2592016-01-20 18:13:17 -08001113 *
Christopher Tateedf7d042016-03-29 18:24:25 -07001114 * @param resid The resource ID of the bitmap to be used as the wallpaper image
1115 * @param which Flags indicating which wallpaper(s) to configure with the new imagery
Christopher Tatead3c2592016-01-20 18:13:17 -08001116 *
Christopher Tateedf7d042016-03-29 18:24:25 -07001117 * @see #FLAG_LOCK
1118 * @see #FLAG_SYSTEM
Christopher Tatead3c2592016-01-20 18:13:17 -08001119 *
1120 * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
1121 *
1122 * @throws IOException
1123 */
Christopher Tate93252de2017-06-15 14:48:41 -07001124 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tatead3c2592016-01-20 18:13:17 -08001125 public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
1126 throws IOException {
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001127 if (sGlobals.mService == null) {
1128 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001129 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001130 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001131 final Bundle result = new Bundle();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001132 final WallpaperSetCompletion completion = new WallpaperSetCompletion();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001133 try {
1134 Resources resources = mContext.getResources();
1135 /* Set the wallpaper to the default values */
Dianne Hackborn840c3a22009-09-02 17:35:17 -07001136 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
Christopher Tatead3c2592016-01-20 18:13:17 -08001137 "res:" + resources.getResourceName(resid),
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001138 mContext.getOpPackageName(), null, false, result, which, completion,
1139 UserHandle.myUserId());
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001140 if (fd != null) {
1141 FileOutputStream fos = null;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001142 boolean ok = false;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001143 try {
1144 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
Christopher Tatead3c2592016-01-20 18:13:17 -08001145 copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001146 // The 'close()' is the trigger for any server-side image manipulation,
1147 // so we must do that before waiting for completion.
1148 fos.close();
1149 completion.waitForCompletion();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001150 } finally {
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001151 // Might be redundant but completion shouldn't wait unless the write
1152 // succeeded; this is a fallback if it threw past the close+wait.
Christopher Tateffa6a882015-12-11 15:08:46 -08001153 IoUtils.closeQuietly(fos);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001154 }
1155 }
1156 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001157 throw e.rethrowFromSystemServer();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001158 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001159 return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001160 }
Christopher Tateffa6a882015-12-11 15:08:46 -08001161
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001162 /**
1163 * Change the current system wallpaper to a bitmap. The given bitmap is
1164 * converted to a PNG and stored as the wallpaper. On success, the intent
1165 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
1166 *
Christopher Tateffa6a882015-12-11 15:08:46 -08001167 * <p>This method is equivalent to calling
1168 * {@link #setBitmap(Bitmap, Rect, boolean)} and passing {@code null} for the
1169 * {@code visibleCrop} rectangle and {@code true} for the {@code allowBackup}
1170 * parameter.
1171 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001172 * <p>This method requires the caller to hold the permission
1173 * {@link android.Manifest.permission#SET_WALLPAPER}.
1174 *
Christopher Tatead3c2592016-01-20 18:13:17 -08001175 * @param bitmap The bitmap to be used as the new system wallpaper.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001176 *
Christopher Tateffa6a882015-12-11 15:08:46 -08001177 * @throws IOException If an error occurs when attempting to set the wallpaper
1178 * to the provided image.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001179 */
Christopher Tate93252de2017-06-15 14:48:41 -07001180 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001181 public void setBitmap(Bitmap bitmap) throws IOException {
Christopher Tateffa6a882015-12-11 15:08:46 -08001182 setBitmap(bitmap, null, true);
1183 }
1184
1185 /**
1186 * Change the current system wallpaper to a bitmap, specifying a hint about
1187 * which subrectangle of the full image is to be visible. The OS will then
1188 * try to best present the given portion of the full image as the static system
1189 * wallpaper image. On success, the intent
1190 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
1191 *
1192 * <p>Passing {@code null} as the {@code visibleHint} parameter is equivalent to
1193 * passing (0, 0, {@code fullImage.getWidth()}, {@code fullImage.getHeight()}).
1194 *
1195 * <p>This method requires the caller to hold the permission
1196 * {@link android.Manifest.permission#SET_WALLPAPER}.
1197 *
Christopher Tatead3c2592016-01-20 18:13:17 -08001198 * @param fullImage A bitmap that will supply the wallpaper imagery.
Christopher Tateffa6a882015-12-11 15:08:46 -08001199 * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
1200 * displayed as wallpaper. Passing {@code null} for this parameter means that
1201 * the full image should be displayed if possible given the image's and device's
Christopher Tatead3c2592016-01-20 18:13:17 -08001202 * aspect ratios, etc.
Christopher Tateffa6a882015-12-11 15:08:46 -08001203 * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
1204 * image for restore to a future device; {@code false} otherwise.
1205 *
Christopher Tatead3c2592016-01-20 18:13:17 -08001206 * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
1207 *
Christopher Tateffa6a882015-12-11 15:08:46 -08001208 * @throws IOException If an error occurs when attempting to set the wallpaper
1209 * to the provided image.
1210 * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
1211 * empty or invalid.
1212 */
Christopher Tate93252de2017-06-15 14:48:41 -07001213 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tatead3c2592016-01-20 18:13:17 -08001214 public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
1215 throws IOException {
Edward Savage-Jones6009d9d2016-08-30 18:44:19 +02001216 return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
Christopher Tatead3c2592016-01-20 18:13:17 -08001217 }
1218
1219 /**
Christopher Tatead3c2592016-01-20 18:13:17 -08001220 * Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
1221 * to specify which of the supported wallpaper categories to set.
1222 *
1223 * @param fullImage A bitmap that will supply the wallpaper imagery.
1224 * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
1225 * displayed as wallpaper. Passing {@code null} for this parameter means that
1226 * the full image should be displayed if possible given the image's and device's
1227 * aspect ratios, etc.
1228 * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
1229 * image for restore to a future device; {@code false} otherwise.
1230 * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
1231 *
Christopher Tateedf7d042016-03-29 18:24:25 -07001232 * @see #FLAG_LOCK
1233 * @see #FLAG_SYSTEM
Christopher Tatead3c2592016-01-20 18:13:17 -08001234 *
1235 * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
1236 *
1237 * @throws IOException
1238 */
Christopher Tate93252de2017-06-15 14:48:41 -07001239 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tatead3c2592016-01-20 18:13:17 -08001240 public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
1241 boolean allowBackup, @SetWallpaperFlags int which)
Christopher Tateffa6a882015-12-11 15:08:46 -08001242 throws IOException {
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001243 return setBitmap(fullImage, visibleCropHint, allowBackup, which,
1244 UserHandle.myUserId());
1245 }
1246
1247 /**
1248 * Like {@link #setBitmap(Bitmap, Rect, boolean, int)}, but allows to pass in an explicit user
1249 * id. If the user id doesn't match the user id the process is running under, calling this
1250 * requires permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
1251 * @hide
1252 */
1253 public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
1254 boolean allowBackup, @SetWallpaperFlags int which, int userId)
1255 throws IOException {
Christopher Tateffa6a882015-12-11 15:08:46 -08001256 validateRect(visibleCropHint);
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001257 if (sGlobals.mService == null) {
1258 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001259 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001260 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001261 final Bundle result = new Bundle();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001262 final WallpaperSetCompletion completion = new WallpaperSetCompletion();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001263 try {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001264 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
Christopher Tated7faf532016-02-25 12:43:38 -08001265 mContext.getOpPackageName(), visibleCropHint, allowBackup,
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001266 result, which, completion, userId);
Christopher Tatead3c2592016-01-20 18:13:17 -08001267 if (fd != null) {
1268 FileOutputStream fos = null;
1269 try {
1270 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
1271 fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001272 fos.close();
1273 completion.waitForCompletion();
Christopher Tatead3c2592016-01-20 18:13:17 -08001274 } finally {
1275 IoUtils.closeQuietly(fos);
1276 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001277 }
1278 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001279 throw e.rethrowFromSystemServer();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001280 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001281 return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001282 }
1283
Christopher Tateffa6a882015-12-11 15:08:46 -08001284 private final void validateRect(Rect rect) {
1285 if (rect != null && rect.isEmpty()) {
1286 throw new IllegalArgumentException("visibleCrop rectangle must be valid and non-empty");
1287 }
1288 }
1289
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001290 /**
1291 * Change the current system wallpaper to a specific byte stream. The
1292 * give InputStream is copied into persistent storage and will now be
1293 * used as the wallpaper. Currently it must be either a JPEG or PNG
1294 * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
1295 * is broadcast.
1296 *
Christopher Tateffa6a882015-12-11 15:08:46 -08001297 * <p>This method is equivalent to calling
1298 * {@link #setStream(InputStream, Rect, boolean)} and passing {@code null} for the
1299 * {@code visibleCrop} rectangle and {@code true} for the {@code allowBackup}
1300 * parameter.
1301 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001302 * <p>This method requires the caller to hold the permission
1303 * {@link android.Manifest.permission#SET_WALLPAPER}.
1304 *
Christopher Tate98d609c2016-05-18 17:31:58 -07001305 * @param bitmapData A stream containing the raw data to install as a wallpaper. This
1306 * data can be in any format handled by {@link BitmapRegionDecoder}.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001307 *
Christopher Tateffa6a882015-12-11 15:08:46 -08001308 * @throws IOException If an error occurs when attempting to set the wallpaper
1309 * based on the provided image data.
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001310 */
Christopher Tate93252de2017-06-15 14:48:41 -07001311 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tateffa6a882015-12-11 15:08:46 -08001312 public void setStream(InputStream bitmapData) throws IOException {
1313 setStream(bitmapData, null, true);
1314 }
1315
Christopher Tatead3c2592016-01-20 18:13:17 -08001316 private void copyStreamToWallpaperFile(InputStream data, FileOutputStream fos)
Christopher Tateffa6a882015-12-11 15:08:46 -08001317 throws IOException {
1318 byte[] buffer = new byte[32768];
1319 int amt;
1320 while ((amt=data.read(buffer)) > 0) {
1321 fos.write(buffer, 0, amt);
1322 }
1323 }
1324
1325 /**
1326 * Change the current system wallpaper to a specific byte stream, specifying a
1327 * hint about which subrectangle of the full image is to be visible. The OS will
1328 * then try to best present the given portion of the full image as the static system
1329 * wallpaper image. The data from the given InputStream is copied into persistent
1330 * storage and will then be used as the system wallpaper. Currently the data must
1331 * be either a JPEG or PNG image. On success, the intent
1332 * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
1333 *
1334 * <p>This method requires the caller to hold the permission
1335 * {@link android.Manifest.permission#SET_WALLPAPER}.
1336 *
Christopher Tate98d609c2016-05-18 17:31:58 -07001337 * @param bitmapData A stream containing the raw data to install as a wallpaper. This
1338 * data can be in any format handled by {@link BitmapRegionDecoder}.
Christopher Tateffa6a882015-12-11 15:08:46 -08001339 * @param visibleCropHint The rectangular subregion of the streamed image that should be
1340 * displayed as wallpaper. Passing {@code null} for this parameter means that
1341 * the full image should be displayed if possible given the image's and device's
1342 * aspect ratios, etc.
1343 * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
1344 * image for restore to a future device; {@code false} otherwise.
Christopher Tate98d609c2016-05-18 17:31:58 -07001345 * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
1346 *
1347 * @see #getWallpaperId(int)
Christopher Tateffa6a882015-12-11 15:08:46 -08001348 *
1349 * @throws IOException If an error occurs when attempting to set the wallpaper
1350 * based on the provided image data.
1351 * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
1352 * empty or invalid.
1353 */
Christopher Tate93252de2017-06-15 14:48:41 -07001354 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tatead3c2592016-01-20 18:13:17 -08001355 public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
Christopher Tateffa6a882015-12-11 15:08:46 -08001356 throws IOException {
Edward Savage-Jones6009d9d2016-08-30 18:44:19 +02001357 return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
Christopher Tatead3c2592016-01-20 18:13:17 -08001358 }
1359
1360 /**
1361 * Version of {@link #setStream(InputStream, Rect, boolean)} that allows the caller
1362 * to specify which of the supported wallpaper categories to set.
1363 *
Christopher Tate98d609c2016-05-18 17:31:58 -07001364 * @param bitmapData A stream containing the raw data to install as a wallpaper. This
1365 * data can be in any format handled by {@link BitmapRegionDecoder}.
Christopher Tatead3c2592016-01-20 18:13:17 -08001366 * @param visibleCropHint The rectangular subregion of the streamed image that should be
1367 * displayed as wallpaper. Passing {@code null} for this parameter means that
1368 * the full image should be displayed if possible given the image's and device's
1369 * aspect ratios, etc.
1370 * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
1371 * image for restore to a future device; {@code false} otherwise.
1372 * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
Christopher Tate98d609c2016-05-18 17:31:58 -07001373 * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
Christopher Tatead3c2592016-01-20 18:13:17 -08001374 *
Christopher Tate98d609c2016-05-18 17:31:58 -07001375 * @see #getWallpaperId(int)
Christopher Tateedf7d042016-03-29 18:24:25 -07001376 * @see #FLAG_LOCK
1377 * @see #FLAG_SYSTEM
Christopher Tatead3c2592016-01-20 18:13:17 -08001378 *
1379 * @throws IOException
1380 */
Christopher Tate93252de2017-06-15 14:48:41 -07001381 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tatead3c2592016-01-20 18:13:17 -08001382 public int setStream(InputStream bitmapData, Rect visibleCropHint,
1383 boolean allowBackup, @SetWallpaperFlags int which)
1384 throws IOException {
Christopher Tateffa6a882015-12-11 15:08:46 -08001385 validateRect(visibleCropHint);
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001386 if (sGlobals.mService == null) {
1387 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001388 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001389 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001390 final Bundle result = new Bundle();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001391 final WallpaperSetCompletion completion = new WallpaperSetCompletion();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001392 try {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001393 ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
Christopher Tated7faf532016-02-25 12:43:38 -08001394 mContext.getOpPackageName(), visibleCropHint, allowBackup,
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001395 result, which, completion, UserHandle.myUserId());
Christopher Tatead3c2592016-01-20 18:13:17 -08001396 if (fd != null) {
1397 FileOutputStream fos = null;
1398 try {
1399 fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
1400 copyStreamToWallpaperFile(bitmapData, fos);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001401 fos.close();
1402 completion.waitForCompletion();
Christopher Tatead3c2592016-01-20 18:13:17 -08001403 } finally {
1404 IoUtils.closeQuietly(fos);
1405 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001406 }
1407 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001408 throw e.rethrowFromSystemServer();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001409 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001410
1411 return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001412 }
1413
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001414 /**
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001415 * Return whether any users are currently set to use the wallpaper
1416 * with the given resource ID. That is, their wallpaper has been
1417 * set through {@link #setResource(int)} with the same resource id.
1418 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001419 public boolean hasResourceWallpaper(@RawRes int resid) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001420 if (sGlobals.mService == null) {
1421 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001422 throw new RuntimeException(new DeadSystemException());
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001423 }
1424 try {
1425 Resources resources = mContext.getResources();
1426 String name = "res:" + resources.getResourceName(resid);
1427 return sGlobals.mService.hasNamedWallpaper(name);
1428 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001429 throw e.rethrowFromSystemServer();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001430 }
1431 }
1432
1433 /**
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001434 * Returns the desired minimum width for the wallpaper. Callers of
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001435 * {@link #setBitmap(android.graphics.Bitmap)} or
1436 * {@link #setStream(java.io.InputStream)} should check this value
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001437 * beforehand to make sure the supplied wallpaper respects the desired
1438 * minimum width.
1439 *
1440 * If the returned value is <= 0, the caller should use the width of
1441 * the default display instead.
1442 *
1443 * @return The desired minimum width for the wallpaper. This value should
1444 * be honored by applications that set the wallpaper but it is not
1445 * mandatory.
1446 */
1447 public int getDesiredMinimumWidth() {
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001448 if (sGlobals.mService == null) {
1449 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001450 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001451 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001452 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -07001453 return sGlobals.mService.getWidthHint();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001454 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001455 throw e.rethrowFromSystemServer();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001456 }
1457 }
1458
1459 /**
1460 * Returns the desired minimum height for the wallpaper. Callers of
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001461 * {@link #setBitmap(android.graphics.Bitmap)} or
1462 * {@link #setStream(java.io.InputStream)} should check this value
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001463 * beforehand to make sure the supplied wallpaper respects the desired
1464 * minimum height.
1465 *
1466 * If the returned value is <= 0, the caller should use the height of
1467 * the default display instead.
1468 *
1469 * @return The desired minimum height for the wallpaper. This value should
1470 * be honored by applications that set the wallpaper but it is not
1471 * mandatory.
1472 */
1473 public int getDesiredMinimumHeight() {
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001474 if (sGlobals.mService == null) {
1475 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001476 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001477 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001478 try {
Dianne Hackborn840c3a22009-09-02 17:35:17 -07001479 return sGlobals.mService.getHeightHint();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001480 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001481 throw e.rethrowFromSystemServer();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001482 }
1483 }
1484
1485 /**
1486 * For use only by the current home application, to specify the size of
1487 * wallpaper it would like to use. This allows such applications to have
1488 * a virtual wallpaper that is larger than the physical screen, matching
1489 * the size of their workspace.
Dianne Hackbornc5bf7582012-04-25 19:12:07 -07001490 *
1491 * <p>Note developers, who don't seem to be reading this. This is
Christopher Tateffa6a882015-12-11 15:08:46 -08001492 * for <em>home apps</em> to tell what size wallpaper they would like.
1493 * Nobody else should be calling this! Certainly not other non-home
Dianne Hackbornc5bf7582012-04-25 19:12:07 -07001494 * apps that change the wallpaper. Those apps are supposed to
1495 * <b>retrieve</b> the suggested size so they can construct a wallpaper
1496 * that matches it.
1497 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001498 * <p>This method requires the caller to hold the permission
1499 * {@link android.Manifest.permission#SET_WALLPAPER_HINTS}.
1500 *
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001501 * @param minimumWidth Desired minimum width
1502 * @param minimumHeight Desired minimum height
1503 */
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001504 public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001505 try {
Donghan Ryu289c2732011-11-14 18:56:11 -08001506 /**
1507 * The framework makes no attempt to limit the window size
1508 * to the maximum texture size. Any window larger than this
1509 * cannot be composited.
1510 *
1511 * Read maximum texture size from system property and scale down
1512 * minimumWidth and minimumHeight accordingly.
1513 */
1514 int maximumTextureSize;
1515 try {
1516 maximumTextureSize = SystemProperties.getInt("sys.max_texture_size", 0);
1517 } catch (Exception e) {
1518 maximumTextureSize = 0;
1519 }
1520
1521 if (maximumTextureSize > 0) {
1522 if ((minimumWidth > maximumTextureSize) ||
1523 (minimumHeight > maximumTextureSize)) {
1524 float aspect = (float)minimumHeight / (float)minimumWidth;
1525 if (minimumWidth > minimumHeight) {
1526 minimumWidth = maximumTextureSize;
1527 minimumHeight = (int)((minimumWidth * aspect) + 0.5);
1528 } else {
1529 minimumHeight = maximumTextureSize;
1530 minimumWidth = (int)((minimumHeight / aspect) + 0.5);
1531 }
1532 }
1533 }
1534
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001535 if (sGlobals.mService == null) {
1536 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001537 throw new RuntimeException(new DeadSystemException());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001538 } else {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001539 sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight,
1540 mContext.getOpPackageName());
Mike Lockwoodc067c9c2011-10-31 12:50:12 -04001541 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001542 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001543 throw e.rethrowFromSystemServer();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001544 }
1545 }
Adam Cohen041a0ba2011-11-09 20:10:27 -08001546
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001547 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001548 * Specify extra padding that the wallpaper should have outside of the display.
1549 * That is, the given padding supplies additional pixels the wallpaper should extend
1550 * outside of the display itself.
1551 * @param padding The number of pixels the wallpaper should extend beyond the display,
1552 * on its left, top, right, and bottom sides.
1553 * @hide
1554 */
1555 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001556 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_HINTS)
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001557 public void setDisplayPadding(Rect padding) {
1558 try {
1559 if (sGlobals.mService == null) {
1560 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001561 throw new RuntimeException(new DeadSystemException());
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001562 } else {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001563 sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001564 }
1565 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001566 throw e.rethrowFromSystemServer();
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001567 }
1568 }
1569
1570 /**
1571 * Apply a raw offset to the wallpaper window. Should only be used in
1572 * combination with {@link #setDisplayPadding(android.graphics.Rect)} when you
1573 * have ensured that the wallpaper will extend outside of the display area so that
1574 * it can be moved without leaving part of the display uncovered.
1575 * @param x The offset, in pixels, to apply to the left edge.
1576 * @param y The offset, in pixels, to apply to the top edge.
1577 * @hide
1578 */
1579 @SystemApi
1580 public void setDisplayOffset(IBinder windowToken, int x, int y) {
1581 try {
1582 //Log.v(TAG, "Sending new wallpaper display offsets from app...");
1583 WindowManagerGlobal.getWindowSession().setWallpaperDisplayOffset(
1584 windowToken, x, y);
1585 //Log.v(TAG, "...app returning after sending display offset!");
1586 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001587 throw e.rethrowFromSystemServer();
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001588 }
1589 }
1590
1591 /**
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001592 * Clear the wallpaper.
1593 *
1594 * @hide
1595 */
1596 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001597 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001598 public void clearWallpaper() {
Christopher Tatea2bd5122016-09-22 13:18:05 -07001599 clearWallpaper(FLAG_LOCK, mContext.getUserId());
1600 clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
Christopher Tatebe132e62016-02-10 12:59:49 -08001601 }
1602
1603 /**
1604 * Clear the wallpaper for a specific user. The caller must hold the
1605 * INTERACT_ACROSS_USERS_FULL permission to clear another user's
Christopher Tate11620ed2017-08-28 14:16:22 -07001606 * wallpaper, and must hold the SET_WALLPAPER permission in all
1607 * circumstances.
Christopher Tatebe132e62016-02-10 12:59:49 -08001608 * @hide
1609 */
1610 @SystemApi
Christopher Tate11620ed2017-08-28 14:16:22 -07001611 @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
Christopher Tate5d99d472016-05-06 17:59:27 -07001612 public void clearWallpaper(@SetWallpaperFlags int which, int userId) {
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001613 if (sGlobals.mService == null) {
1614 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001615 throw new RuntimeException(new DeadSystemException());
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001616 }
1617 try {
Christopher Tatebe132e62016-02-10 12:59:49 -08001618 sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId);
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001619 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001620 throw e.rethrowFromSystemServer();
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001621 }
1622 }
1623
1624 /**
1625 * Set the live wallpaper.
1626 *
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001627 * @hide
1628 */
1629 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001630 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001631 public boolean setWallpaperComponent(ComponentName name) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001632 return setWallpaperComponent(name, UserHandle.myUserId());
1633 }
1634
1635 /**
1636 * Set the live wallpaper.
1637 *
1638 * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
1639 * permission. The caller must hold the INTERACT_ACROSS_USERS_FULL permission to change
1640 * another user's wallpaper.
1641 *
1642 * @hide
1643 */
Christopher Tate93252de2017-06-15 14:48:41 -07001644 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
Adrian Roos40ea0832016-07-14 14:19:55 -07001645 public boolean setWallpaperComponent(ComponentName name, int userId) {
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001646 if (sGlobals.mService == null) {
1647 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001648 throw new RuntimeException(new DeadSystemException());
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001649 }
1650 try {
Adrian Roos40ea0832016-07-14 14:19:55 -07001651 sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName(),
1652 userId);
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001653 return true;
1654 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001655 throw e.rethrowFromSystemServer();
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001656 }
Filip Gruszczynski9fedc722015-01-28 15:59:46 -08001657 }
1658
1659 /**
Christopher Tateffa6a882015-12-11 15:08:46 -08001660 * Set the display position of the current wallpaper within any larger space, when
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001661 * that wallpaper is visible behind the given window. The X and Y offsets
1662 * are floating point numbers ranging from 0 to 1, representing where the
1663 * wallpaper should be positioned within the screen space. These only
Christopher Tateffa6a882015-12-11 15:08:46 -08001664 * make sense when the wallpaper is larger than the display.
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001665 *
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001666 * @param windowToken The window who these offsets should be associated
Scott Main8b2e0002009-09-29 18:17:31 -07001667 * with, as returned by {@link android.view.View#getWindowToken()
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001668 * View.getWindowToken()}.
Marco Nelissenbf6956b2009-11-09 15:21:13 -08001669 * @param xOffset The offset along the X dimension, from 0 to 1.
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001670 * @param yOffset The offset along the Y dimension, from 0 to 1.
1671 */
1672 public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
Adam Cohen791a6332012-01-12 14:38:38 -08001673 try {
1674 //Log.v(TAG, "Sending new wallpaper offsets from app...");
Jeff Brownf9e989d2013-04-04 23:04:03 -07001675 WindowManagerGlobal.getWindowSession().setWallpaperPosition(
Adam Cohen791a6332012-01-12 14:38:38 -08001676 windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
1677 //Log.v(TAG, "...app returning after sending offsets!");
1678 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001679 throw e.rethrowFromSystemServer();
Adam Cohen791a6332012-01-12 14:38:38 -08001680 }
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001681 }
Adam Cohen041a0ba2011-11-09 20:10:27 -08001682
Dianne Hackbornc8a0a752009-08-10 23:05:49 -07001683 /**
Marco Nelissenbf6956b2009-11-09 15:21:13 -08001684 * For applications that use multiple virtual screens showing a wallpaper,
1685 * specify the step size between virtual screens. For example, if the
Dianne Hackborn23ef7b42009-11-18 18:20:39 -08001686 * launcher has 3 virtual screens, it would specify an xStep of 0.5,
Marco Nelissenbf6956b2009-11-09 15:21:13 -08001687 * since the X offset for those screens are 0.0, 0.5 and 1.0
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001688 * @param xStep The X offset delta from one screen to the next one
Marco Nelissenbf6956b2009-11-09 15:21:13 -08001689 * @param yStep The Y offset delta from one screen to the next one
1690 */
1691 public void setWallpaperOffsetSteps(float xStep, float yStep) {
1692 mWallpaperXStep = xStep;
1693 mWallpaperYStep = yStep;
1694 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001695
Marco Nelissenbf6956b2009-11-09 15:21:13 -08001696 /**
Dianne Hackborn75804932009-10-20 20:15:20 -07001697 * Send an arbitrary command to the current active wallpaper.
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001698 *
Dianne Hackborn75804932009-10-20 20:15:20 -07001699 * @param windowToken The window who these offsets should be associated
1700 * with, as returned by {@link android.view.View#getWindowToken()
1701 * View.getWindowToken()}.
1702 * @param action Name of the command to perform. This must be a scoped
1703 * name to avoid collisions, such as "com.mycompany.wallpaper.DOIT".
1704 * @param x Arbitrary integer argument based on command.
1705 * @param y Arbitrary integer argument based on command.
1706 * @param z Arbitrary integer argument based on command.
1707 * @param extras Optional additional information for the command, or null.
1708 */
1709 public void sendWallpaperCommand(IBinder windowToken, String action,
1710 int x, int y, int z, Bundle extras) {
1711 try {
1712 //Log.v(TAG, "Sending new wallpaper offsets from app...");
Jeff Brownf9e989d2013-04-04 23:04:03 -07001713 WindowManagerGlobal.getWindowSession().sendWallpaperCommand(
Dianne Hackborn75804932009-10-20 20:15:20 -07001714 windowToken, action, x, y, z, extras, false);
1715 //Log.v(TAG, "...app returning after sending offsets!");
1716 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001717 throw e.rethrowFromSystemServer();
Dianne Hackborn75804932009-10-20 20:15:20 -07001718 }
1719 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001720
1721 /**
1722 * Returns whether wallpapers are supported for the calling user. If this function returns
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001723 * {@code false}, any attempts to changing the wallpaper will have no effect,
1724 * and any attempt to obtain of the wallpaper will return {@code null}.
Benjamin Franzf3ece362015-02-11 10:51:10 +00001725 */
1726 public boolean isWallpaperSupported() {
1727 if (sGlobals.mService == null) {
1728 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001729 throw new RuntimeException(new DeadSystemException());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001730 } else {
1731 try {
1732 return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
1733 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001734 throw e.rethrowFromSystemServer();
Benjamin Franzf3ece362015-02-11 10:51:10 +00001735 }
1736 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001737 }
1738
Dianne Hackborn75804932009-10-20 20:15:20 -07001739 /**
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001740 * Returns whether the calling package is allowed to set the wallpaper for the calling user.
1741 * If this function returns {@code false}, any attempts to change the wallpaper will have
1742 * no effect. Always returns {@code true} for device owner and profile owner.
1743 *
1744 * @see android.os.UserManager#DISALLOW_SET_WALLPAPER
1745 */
Christopher Tate98d609c2016-05-18 17:31:58 -07001746 public boolean isSetWallpaperAllowed() {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001747 if (sGlobals.mService == null) {
1748 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001749 throw new RuntimeException(new DeadSystemException());
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001750 } else {
1751 try {
Christopher Tate98d609c2016-05-18 17:31:58 -07001752 return sGlobals.mService.isSetWallpaperAllowed(mContext.getOpPackageName());
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001753 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001754 throw e.rethrowFromSystemServer();
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001755 }
1756 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001757 }
1758
1759 /**
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001760 * Clear the offsets previously associated with this window through
1761 * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
1762 * the window to its default state, where it does not cause the wallpaper
1763 * to scroll from whatever its last offsets were.
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001764 *
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001765 * @param windowToken The window who these offsets should be associated
Scott Main8b2e0002009-09-29 18:17:31 -07001766 * with, as returned by {@link android.view.View#getWindowToken()
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001767 * View.getWindowToken()}.
1768 */
1769 public void clearWallpaperOffsets(IBinder windowToken) {
1770 try {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001771 WindowManagerGlobal.getWindowSession().setWallpaperPosition(
Marco Nelissenbf6956b2009-11-09 15:21:13 -08001772 windowToken, -1, -1, -1, -1);
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001773 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001774 throw e.rethrowFromSystemServer();
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001775 }
1776 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001777
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07001778 /**
Christopher Tatebe132e62016-02-10 12:59:49 -08001779 * Remove any currently set system wallpaper, reverting to the system's built-in
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001780 * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
1781 * is broadcast.
1782 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001783 * <p>This method requires the caller to hold the permission
1784 * {@link android.Manifest.permission#SET_WALLPAPER}.
1785 *
Michael Jurkab668d0b2013-10-04 15:11:05 -07001786 * @throws IOException If an error occurs reverting to the built-in
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001787 * wallpaper.
1788 */
Christopher Tate93252de2017-06-15 14:48:41 -07001789 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001790 public void clear() throws IOException {
Christopher Tate5d99d472016-05-06 17:59:27 -07001791 setStream(openDefaultWallpaper(mContext, FLAG_SYSTEM), null, false);
Jeff Sharkey28f08772014-04-16 09:41:58 -07001792 }
1793
1794 /**
Christopher Tate79a24572016-03-02 14:42:44 -08001795 * Remove one or more currently set wallpapers, reverting to the system default
Christopher Tateedf7d042016-03-29 18:24:25 -07001796 * display for each one. If {@link #FLAG_SYSTEM} is set in the {@code which}
Christopher Tate79a24572016-03-02 14:42:44 -08001797 * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
1798 * upon success.
1799 *
Christopher Tateedf7d042016-03-29 18:24:25 -07001800 * @param which A bitwise combination of {@link #FLAG_SYSTEM} or
1801 * {@link #FLAG_LOCK}
Christopher Tate79a24572016-03-02 14:42:44 -08001802 * @throws IOException If an error occurs reverting to the built-in wallpaper.
1803 */
Christopher Tate93252de2017-06-15 14:48:41 -07001804 @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
Christopher Tate5d99d472016-05-06 17:59:27 -07001805 public void clear(@SetWallpaperFlags int which) throws IOException {
Christopher Tateedf7d042016-03-29 18:24:25 -07001806 if ((which & FLAG_SYSTEM) != 0) {
Christopher Tate79a24572016-03-02 14:42:44 -08001807 clear();
1808 }
Christopher Tateedf7d042016-03-29 18:24:25 -07001809 if ((which & FLAG_LOCK) != 0) {
1810 clearWallpaper(FLAG_LOCK, mContext.getUserId());
Christopher Tate79a24572016-03-02 14:42:44 -08001811 }
1812 }
1813
1814 /**
Jeff Sharkey28f08772014-04-16 09:41:58 -07001815 * Open stream representing the default static image wallpaper.
1816 *
Christopher Tate5d99d472016-05-06 17:59:27 -07001817 * If the device defines no default wallpaper of the requested kind,
1818 * {@code null} is returned.
1819 *
Jeff Sharkey28f08772014-04-16 09:41:58 -07001820 * @hide
1821 */
Christopher Tate5d99d472016-05-06 17:59:27 -07001822 public static InputStream openDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
1823 final String whichProp;
1824 final int defaultResId;
1825 if (which == FLAG_LOCK) {
Christopher Tate36cb2a7a2016-06-09 13:44:48 -07001826 /* Factory-default lock wallpapers are not yet supported
Christopher Tate5d99d472016-05-06 17:59:27 -07001827 whichProp = PROP_LOCK_WALLPAPER;
1828 defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
Christopher Tate36cb2a7a2016-06-09 13:44:48 -07001829 */
1830 return null;
Christopher Tate5d99d472016-05-06 17:59:27 -07001831 } else {
1832 whichProp = PROP_WALLPAPER;
1833 defaultResId = com.android.internal.R.drawable.default_wallpaper;
1834 }
1835 final String path = SystemProperties.get(whichProp);
Jeff Sharkey28f08772014-04-16 09:41:58 -07001836 if (!TextUtils.isEmpty(path)) {
1837 final File file = new File(path);
1838 if (file.exists()) {
1839 try {
1840 return new FileInputStream(file);
1841 } catch (IOException e) {
1842 // Ignored, fall back to platform default below
1843 }
1844 }
1845 }
Christopher Tate5d99d472016-05-06 17:59:27 -07001846 try {
1847 return context.getResources().openRawResource(defaultResId);
1848 } catch (NotFoundException e) {
1849 // no default defined for this device; this is not a failure
1850 }
1851 return null;
Jeff Sharkey28f08772014-04-16 09:41:58 -07001852 }
1853
1854 /**
1855 * Return {@link ComponentName} of the default live wallpaper, or
1856 * {@code null} if none is defined.
1857 *
1858 * @hide
1859 */
1860 public static ComponentName getDefaultWallpaperComponent(Context context) {
1861 String flat = SystemProperties.get(PROP_WALLPAPER_COMPONENT);
1862 if (!TextUtils.isEmpty(flat)) {
1863 final ComponentName cn = ComponentName.unflattenFromString(flat);
1864 if (cn != null) {
1865 return cn;
1866 }
1867 }
1868
1869 flat = context.getString(com.android.internal.R.string.default_wallpaper_component);
1870 if (!TextUtils.isEmpty(flat)) {
1871 final ComponentName cn = ComponentName.unflattenFromString(flat);
1872 if (cn != null) {
1873 return cn;
1874 }
1875 }
1876
1877 return null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001878 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001879
Christopher Tatebe132e62016-02-10 12:59:49 -08001880 /**
1881 * Register a callback for lock wallpaper observation. Only the OS may use this.
1882 *
1883 * @return true on success; false on error.
1884 * @hide
1885 */
1886 public boolean setLockWallpaperCallback(IWallpaperManagerCallback callback) {
1887 if (sGlobals.mService == null) {
1888 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001889 throw new RuntimeException(new DeadSystemException());
Christopher Tatebe132e62016-02-10 12:59:49 -08001890 }
1891
1892 try {
1893 return sGlobals.mService.setLockWallpaperCallback(callback);
1894 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001895 throw e.rethrowFromSystemServer();
Christopher Tatebe132e62016-02-10 12:59:49 -08001896 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001897 }
1898
Christopher Tated7faf532016-02-25 12:43:38 -08001899 /**
1900 * Is the current system wallpaper eligible for backup?
1901 *
1902 * Only the OS itself may use this method.
1903 * @hide
1904 */
Christopher Tate61722662016-08-10 16:13:14 -07001905 public boolean isWallpaperBackupEligible(int which) {
Christopher Tated7faf532016-02-25 12:43:38 -08001906 if (sGlobals.mService == null) {
1907 Log.w(TAG, "WallpaperService not running");
Christopher Tate98d609c2016-05-18 17:31:58 -07001908 throw new RuntimeException(new DeadSystemException());
Christopher Tated7faf532016-02-25 12:43:38 -08001909 }
1910 try {
Christopher Tate61722662016-08-10 16:13:14 -07001911 return sGlobals.mService.isWallpaperBackupEligible(which, mContext.getUserId());
Christopher Tated7faf532016-02-25 12:43:38 -08001912 } catch (RemoteException e) {
1913 Log.e(TAG, "Exception querying wallpaper backup eligibility: " + e.getMessage());
1914 }
1915 return false;
1916 }
1917
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001918 // Private completion callback for setWallpaper() synchronization
1919 private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
1920 final CountDownLatch mLatch;
1921
1922 public WallpaperSetCompletion() {
1923 mLatch = new CountDownLatch(1);
1924 }
1925
1926 public void waitForCompletion() {
1927 try {
1928 mLatch.await(30, TimeUnit.SECONDS);
1929 } catch (InterruptedException e) {
1930 // This might be legit: the crop may take a very long time. Don't sweat
1931 // it in that case; we are okay with display lagging behind in order to
1932 // keep the caller from locking up indeterminately.
1933 }
1934 }
1935
1936 @Override
1937 public void onWallpaperChanged() throws RemoteException {
1938 mLatch.countDown();
1939 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001940
1941 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001942 public void onWallpaperColorsChanged(WallpaperColors colors, int which, int userId)
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001943 throws RemoteException {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001944 sGlobals.onWallpaperColorsChanged(colors, which, userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001945 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001946 }
Lucas Dupinc40608c2017-04-14 18:33:08 -07001947
1948 /**
1949 * Interface definition for a callback to be invoked when colors change on a wallpaper.
1950 */
1951 public interface OnColorsChangedListener {
1952 /**
1953 * Called when colors change.
1954 * A {@link android.app.WallpaperColors} object containing a simplified
1955 * color histogram will be given.
1956 *
1957 * @param colors Wallpaper color info
1958 * @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
1959 */
1960 void onColorsChanged(WallpaperColors colors, int which);
Lucas Dupin50ba9912017-07-14 11:55:05 -07001961
1962 /**
1963 * Called when colors change.
1964 * A {@link android.app.WallpaperColors} object containing a simplified
1965 * color histogram will be given.
1966 *
1967 * @param colors Wallpaper color info
1968 * @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
1969 * @param userId Owner of the wallpaper
1970 * @hide
1971 */
1972 default void onColorsChanged(WallpaperColors colors, int which, int userId) {
1973 onColorsChanged(colors, which);
1974 }
Lucas Dupinc40608c2017-04-14 18:33:08 -07001975 }
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001976}