Reload LockscreenWallpaper and ImageWallpaper on background thread
Fixes: 27148260
Change-Id: I426712024ec1a82fccd48154c65da31d3e610525
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 1306284..c72f5d2 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -29,6 +29,7 @@
import android.graphics.RectF;
import android.graphics.Region.Op;
import android.opengl.GLUtils;
+import android.os.AsyncTask;
import android.os.SystemProperties;
import android.renderscript.Matrix4f;
import android.service.wallpaper.WallpaperService;
@@ -155,6 +156,8 @@
private int mLastRequestedWidth = -1;
private int mLastRequestedHeight = -1;
+ private AsyncTask<Void, Void, Bitmap> mLoader;
+ private boolean mNeedsDrawAfterLoadingWallpaper;
public DrawableEngine() {
super();
@@ -184,10 +187,9 @@
super.onCreate(surfaceHolder);
mDefaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
-
- updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo());
-
setOffsetNotificationsEnabled(false);
+
+ updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo(), false /* forDraw */);
}
@Override
@@ -197,17 +199,19 @@
mWallpaperManager.forgetLoadedWallpaper();
}
- void updateSurfaceSize(SurfaceHolder surfaceHolder, DisplayInfo displayInfo) {
+ boolean updateSurfaceSize(SurfaceHolder surfaceHolder, DisplayInfo displayInfo,
+ boolean forDraw) {
+ boolean hasWallpaper = true;
+
// Load background image dimensions, if we haven't saved them yet
if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
// Need to load the image to get dimensions
mWallpaperManager.forgetLoadedWallpaper();
- updateWallpaperLocked();
- if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
- // Default to the display size if we can't find the dimensions
- mBackgroundWidth = displayInfo.logicalWidth;
- mBackgroundHeight = displayInfo.logicalHeight;
+ loadWallpaper(forDraw);
+ if (DEBUG) {
+ Log.d(TAG, "Reloading, redoing updateSurfaceSize later.");
}
+ hasWallpaper = false;
}
// Force the wallpaper to cover the screen in both dimensions
@@ -224,6 +228,7 @@
} else {
surfaceHolder.setSizeFromLayout();
}
+ return hasWallpaper;
}
@Override
@@ -299,6 +304,7 @@
}
super.onSurfaceRedrawNeeded(holder);
+ mLastSurfaceHeight = mLastSurfaceWidth = -1;
drawFrame();
}
@@ -317,7 +323,9 @@
// should change
if (newRotation != mLastRotation) {
// Update surface size (if necessary)
- updateSurfaceSize(getSurfaceHolder(), displayInfo);
+ if (!updateSurfaceSize(getSurfaceHolder(), displayInfo, true /* forDraw */)) {
+ return; // had to reload wallpaper, will retry later
+ }
mRotationAtLastSurfaceSizeUpdate = newRotation;
mDisplayWidthAtLastSurfaceSizeUpdate = displayInfo.logicalWidth;
mDisplayHeightAtLastSurfaceSizeUpdate = displayInfo.logicalHeight;
@@ -339,8 +347,8 @@
}
mLastRotation = newRotation;
- // Load bitmap if it is not yet loaded or if it was loaded at a different size
- if (mBackground == null || surfaceDimensionsChanged) {
+ // Load bitmap if it is not yet loaded
+ if (mBackground == null) {
if (DEBUG) {
Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
mBackground + ", " +
@@ -349,20 +357,11 @@
dw + ", " + dh);
}
mWallpaperManager.forgetLoadedWallpaper();
- updateWallpaperLocked();
- if (mBackground == null) {
- if (DEBUG) {
- Log.d(TAG, "Unable to load bitmap");
- }
- return;
- }
+ loadWallpaper(true /* needDraw */);
if (DEBUG) {
- if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) {
- Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " +
- dw + ", " + dh + ", " + mBackground.getWidth() + ", " +
- mBackground.getHeight());
- }
+ Log.d(TAG, "Reloading, resuming draw later");
}
+ return;
}
// Center the scaled image
@@ -422,36 +421,77 @@
}
}
- private void updateWallpaperLocked() {
- Throwable exception = null;
- try {
- mBackground = null;
- mBackgroundWidth = -1;
- mBackgroundHeight = -1;
- mBackground = mWallpaperManager.getBitmap();
- mBackgroundWidth = mBackground.getWidth();
- mBackgroundHeight = mBackground.getHeight();
- } catch (RuntimeException e) {
- exception = e;
- } catch (OutOfMemoryError e) {
- exception = e;
- }
-
- if (exception != null) {
- mBackground = null;
- mBackgroundWidth = -1;
- mBackgroundHeight = -1;
- // Note that if we do fail at this, and the default wallpaper can't
- // be loaded, we will go into a cycle. Don't do a build where the
- // default wallpaper can't be loaded.
- Log.w(TAG, "Unable to load wallpaper!", exception);
- try {
- mWallpaperManager.clear();
- } catch (IOException ex) {
- // now we're really screwed.
- Log.w(TAG, "Unable reset to default wallpaper!", ex);
+ /**
+ * Loads the wallpaper on background thread and schedules updating the surface frame,
+ * and if {@param needsDraw} is set also draws a frame.
+ *
+ * If loading is already in-flight, subsequent loads are ignored (but needDraw is or-ed to
+ * the active request).
+ */
+ private void loadWallpaper(boolean needsDraw) {
+ mNeedsDrawAfterLoadingWallpaper |= needsDraw;
+ if (mLoader != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Skipping loadWallpaper, already in flight ");
}
+ return;
}
+ mLoader = new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ Throwable exception;
+ try {
+ return mWallpaperManager.getBitmap();
+ } catch (RuntimeException | OutOfMemoryError e) {
+ exception = e;
+ }
+
+ if (exception != null) {
+ // Note that if we do fail at this, and the default wallpaper can't
+ // be loaded, we will go into a cycle. Don't do a build where the
+ // default wallpaper can't be loaded.
+ Log.w(TAG, "Unable to load wallpaper!", exception);
+ try {
+ mWallpaperManager.clear();
+ } catch (IOException ex) {
+ // now we're really screwed.
+ Log.w(TAG, "Unable reset to default wallpaper!", ex);
+ }
+
+ try {
+ return mWallpaperManager.getBitmap();
+ } catch (RuntimeException | OutOfMemoryError e) {
+ Log.w(TAG, "Unable to load default wallpaper!", e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap b) {
+ mBackground = null;
+ mBackgroundWidth = -1;
+ mBackgroundHeight = -1;
+
+ if (b != null) {
+ mBackground = b;
+ mBackgroundWidth = mBackground.getWidth();
+ mBackgroundHeight = mBackground.getHeight();
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Wallpaper loaded: " + mBackground);
+ }
+ updateSurfaceSize(getSurfaceHolder(), getDefaultDisplayInfo(),
+ false /* forDraw */);
+ if (mNeedsDrawAfterLoadingWallpaper) {
+ drawFrame();
+ }
+
+ mLoader = null;
+ mNeedsDrawAfterLoadingWallpaper = false;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 92f3585..c423b67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -27,7 +27,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.DrawableWrapper;
-import android.os.Bundle;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -46,9 +46,7 @@
private static final String TAG = "LockscreenWallpaper";
- private final Context mContext;
private final PhoneStatusBar mBar;
- private final IWallpaperManager mService;
private final WallpaperManager mWallpaperManager;
private final Handler mH;
@@ -58,69 +56,75 @@
// The user selected in the UI, or null if no user is selected or UI doesn't support selecting
// users.
private UserHandle mSelectedUser;
+ private AsyncTask<Void, Void, LoaderResult> mLoader;
public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
- mContext = ctx;
mBar = bar;
mH = h;
- mService = IWallpaperManager.Stub.asInterface(
- ServiceManager.getService(Context.WALLPAPER_SERVICE));
mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
mCurrentUserId = ActivityManager.getCurrentUser();
+ IWallpaperManager service = IWallpaperManager.Stub.asInterface(
+ ServiceManager.getService(Context.WALLPAPER_SERVICE));
try {
- mService.setLockWallpaperCallback(this);
+ service.setLockWallpaperCallback(this);
} catch (RemoteException e) {
Log.e(TAG, "System dead?" + e);
}
}
public Bitmap getBitmap() {
- try {
- if (mCached) {
- return mCache;
- }
- if (!mService.isWallpaperSupported(mContext.getOpPackageName())) {
- mCached = true;
- mCache = null;
- return null;
- }
- // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
- // wallpaper.
- final int lockWallpaperUserId =
- mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
- ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_LOCK,
- new Bundle(), lockWallpaperUserId);
- if (fd != null) {
- try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- mCache = BitmapFactory.decodeFileDescriptor(
- fd.getFileDescriptor(), null, options);
- mCached = true;
- return mCache;
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "Can't decode file", e);
- return null;
- } finally {
- IoUtils.closeQuietly(fd);
- }
- } else {
- mCached = true;
- if (mSelectedUser != null && mSelectedUser.getIdentifier() != mCurrentUserId) {
- // When selected user is different from the current user, show the selected
- // user's static wallpaper.
- mCache = mWallpaperManager.getBitmapAsUser(mSelectedUser.getIdentifier());
- } else {
- // When there is no selected user, or it's same as the current user, show the
- // system (possibly dynamic) wallpaper for the selected user.
- mCache = null;
- }
- return mCache;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "System dead?" + e);
+ if (mCached) {
+ return mCache;
+ }
+ if (!mWallpaperManager.isWallpaperSupported()) {
+ mCached = true;
+ mCache = null;
return null;
}
+
+ LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser);
+ if (result.success) {
+ mCached = true;
+ mCache = result.bitmap;
+ }
+ return mCache;
+ }
+
+ public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
+ // May be called on any thread - only use thread safe operations.
+
+ // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
+ // wallpaper.
+ final int lockWallpaperUserId =
+ selectedUser != null ? selectedUser.getIdentifier() : currentUserId;
+ ParcelFileDescriptor fd = mWallpaperManager.getWallpaperFile(
+ WallpaperManager.FLAG_LOCK, lockWallpaperUserId);
+
+ if (fd != null) {
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options));
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't decode file", e);
+ return LoaderResult.fail();
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ } else {
+ if (selectedUser != null && selectedUser.getIdentifier() != currentUserId) {
+ // When selected user is different from the current user, show the selected
+ // user's static wallpaper.
+ return LoaderResult.success(
+ mWallpaperManager.getBitmapAsUser(selectedUser.getIdentifier()));
+
+ } else {
+ // When there is no selected user, or it's same as the current user, show the
+ // system (possibly dynamic) wallpaper for the selected user.
+ return LoaderResult.success(null);
+ }
+ }
}
public void setCurrentUser(int user) {
@@ -135,14 +139,16 @@
return;
}
mSelectedUser = selectedUser;
-
- mH.removeCallbacks(this);
- mH.post(this);
+ postUpdateWallpaper();
}
@Override
public void onWallpaperChanged() {
// Called on Binder thread.
+ postUpdateWallpaper();
+ }
+
+ private void postUpdateWallpaper() {
mH.removeCallbacks(this);
mH.post(this);
}
@@ -150,10 +156,52 @@
@Override
public void run() {
// Called in response to onWallpaperChanged on the main thread.
- mCached = false;
- mCache = null;
- getBitmap();
- mBar.updateMediaMetaData(true /* metaDataChanged */, true /* allowEnterAnimation */);
+
+ if (mLoader != null) {
+ mLoader.cancel(false /* interrupt */);
+ }
+
+ final int currentUser = mCurrentUserId;
+ final UserHandle selectedUser = mSelectedUser;
+ mLoader = new AsyncTask<Void, Void, LoaderResult>() {
+ @Override
+ protected LoaderResult doInBackground(Void... params) {
+ return loadBitmap(currentUser, selectedUser);
+ }
+
+ @Override
+ protected void onPostExecute(LoaderResult result) {
+ super.onPostExecute(result);
+ if (isCancelled()) {
+ return;
+ }
+ if (result.success) {
+ mCached = true;
+ mCache = result.bitmap;
+ mBar.updateMediaMetaData(
+ true /* metaDataChanged */, true /* allowEnterAnimation */);
+ }
+ mLoader = null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private static class LoaderResult {
+ public final boolean success;
+ public final Bitmap bitmap;
+
+ LoaderResult(boolean success, Bitmap bitmap) {
+ this.success = success;
+ this.bitmap = bitmap;
+ }
+
+ static LoaderResult success(Bitmap b) {
+ return new LoaderResult(true, b);
+ }
+
+ static LoaderResult fail() {
+ return new LoaderResult(false, null);
+ }
}
/**