Merge "Reload LockscreenWallpaper and ImageWallpaper on background thread" into nyc-dev

This commit is contained in:
Adrian Roos
2016-04-19 22:06:14 +00:00
committed by Android (Google) Code Review
2 changed files with 197 additions and 109 deletions

View File

@@ -29,6 +29,7 @@ import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.graphics.Region.Op; import android.graphics.Region.Op;
import android.opengl.GLUtils; import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.renderscript.Matrix4f; import android.renderscript.Matrix4f;
import android.service.wallpaper.WallpaperService; import android.service.wallpaper.WallpaperService;
@@ -155,6 +156,8 @@ public class ImageWallpaper extends WallpaperService {
private int mLastRequestedWidth = -1; private int mLastRequestedWidth = -1;
private int mLastRequestedHeight = -1; private int mLastRequestedHeight = -1;
private AsyncTask<Void, Void, Bitmap> mLoader;
private boolean mNeedsDrawAfterLoadingWallpaper;
public DrawableEngine() { public DrawableEngine() {
super(); super();
@@ -184,10 +187,9 @@ public class ImageWallpaper extends WallpaperService {
super.onCreate(surfaceHolder); super.onCreate(surfaceHolder);
mDefaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay(); mDefaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo());
setOffsetNotificationsEnabled(false); setOffsetNotificationsEnabled(false);
updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo(), false /* forDraw */);
} }
@Override @Override
@@ -197,17 +199,19 @@ public class ImageWallpaper extends WallpaperService {
mWallpaperManager.forgetLoadedWallpaper(); 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 // Load background image dimensions, if we haven't saved them yet
if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) { if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
// Need to load the image to get dimensions // Need to load the image to get dimensions
mWallpaperManager.forgetLoadedWallpaper(); mWallpaperManager.forgetLoadedWallpaper();
updateWallpaperLocked(); loadWallpaper(forDraw);
if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) { if (DEBUG) {
// Default to the display size if we can't find the dimensions Log.d(TAG, "Reloading, redoing updateSurfaceSize later.");
mBackgroundWidth = displayInfo.logicalWidth;
mBackgroundHeight = displayInfo.logicalHeight;
} }
hasWallpaper = false;
} }
// Force the wallpaper to cover the screen in both dimensions // Force the wallpaper to cover the screen in both dimensions
@@ -224,6 +228,7 @@ public class ImageWallpaper extends WallpaperService {
} else { } else {
surfaceHolder.setSizeFromLayout(); surfaceHolder.setSizeFromLayout();
} }
return hasWallpaper;
} }
@Override @Override
@@ -299,6 +304,7 @@ public class ImageWallpaper extends WallpaperService {
} }
super.onSurfaceRedrawNeeded(holder); super.onSurfaceRedrawNeeded(holder);
mLastSurfaceHeight = mLastSurfaceWidth = -1;
drawFrame(); drawFrame();
} }
@@ -317,7 +323,9 @@ public class ImageWallpaper extends WallpaperService {
// should change // should change
if (newRotation != mLastRotation) { if (newRotation != mLastRotation) {
// Update surface size (if necessary) // Update surface size (if necessary)
updateSurfaceSize(getSurfaceHolder(), displayInfo); if (!updateSurfaceSize(getSurfaceHolder(), displayInfo, true /* forDraw */)) {
return; // had to reload wallpaper, will retry later
}
mRotationAtLastSurfaceSizeUpdate = newRotation; mRotationAtLastSurfaceSizeUpdate = newRotation;
mDisplayWidthAtLastSurfaceSizeUpdate = displayInfo.logicalWidth; mDisplayWidthAtLastSurfaceSizeUpdate = displayInfo.logicalWidth;
mDisplayHeightAtLastSurfaceSizeUpdate = displayInfo.logicalHeight; mDisplayHeightAtLastSurfaceSizeUpdate = displayInfo.logicalHeight;
@@ -339,8 +347,8 @@ public class ImageWallpaper extends WallpaperService {
} }
mLastRotation = newRotation; mLastRotation = newRotation;
// Load bitmap if it is not yet loaded or if it was loaded at a different size // Load bitmap if it is not yet loaded
if (mBackground == null || surfaceDimensionsChanged) { if (mBackground == null) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " + Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
mBackground + ", " + mBackground + ", " +
@@ -349,20 +357,11 @@ public class ImageWallpaper extends WallpaperService {
dw + ", " + dh); dw + ", " + dh);
} }
mWallpaperManager.forgetLoadedWallpaper(); mWallpaperManager.forgetLoadedWallpaper();
updateWallpaperLocked(); loadWallpaper(true /* needDraw */);
if (mBackground == null) {
if (DEBUG) {
Log.d(TAG, "Unable to load bitmap");
}
return;
}
if (DEBUG) { if (DEBUG) {
if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) { Log.d(TAG, "Reloading, resuming draw later");
Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " +
dw + ", " + dh + ", " + mBackground.getWidth() + ", " +
mBackground.getHeight());
}
} }
return;
} }
// Center the scaled image // Center the scaled image
@@ -422,36 +421,77 @@ public class ImageWallpaper extends WallpaperService {
} }
} }
private void updateWallpaperLocked() { /**
Throwable exception = null; * Loads the wallpaper on background thread and schedules updating the surface frame,
try { * and if {@param needsDraw} is set also draws a frame.
mBackground = null; *
mBackgroundWidth = -1; * If loading is already in-flight, subsequent loads are ignored (but needDraw is or-ed to
mBackgroundHeight = -1; * the active request).
mBackground = mWallpaperManager.getBitmap(); */
mBackgroundWidth = mBackground.getWidth(); private void loadWallpaper(boolean needsDraw) {
mBackgroundHeight = mBackground.getHeight(); mNeedsDrawAfterLoadingWallpaper |= needsDraw;
} catch (RuntimeException e) { if (mLoader != null) {
exception = e; if (DEBUG) {
} catch (OutOfMemoryError e) { Log.d(TAG, "Skipping loadWallpaper, already in flight ");
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);
} }
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 @Override

View File

@@ -27,7 +27,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.DrawableWrapper; import android.graphics.drawable.DrawableWrapper;
import android.os.Bundle; import android.os.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
@@ -46,9 +46,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
private static final String TAG = "LockscreenWallpaper"; private static final String TAG = "LockscreenWallpaper";
private final Context mContext;
private final PhoneStatusBar mBar; private final PhoneStatusBar mBar;
private final IWallpaperManager mService;
private final WallpaperManager mWallpaperManager; private final WallpaperManager mWallpaperManager;
private final Handler mH; private final Handler mH;
@@ -58,69 +56,75 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
// The user selected in the UI, or null if no user is selected or UI doesn't support selecting // The user selected in the UI, or null if no user is selected or UI doesn't support selecting
// users. // users.
private UserHandle mSelectedUser; private UserHandle mSelectedUser;
private AsyncTask<Void, Void, LoaderResult> mLoader;
public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) { public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
mContext = ctx;
mBar = bar; mBar = bar;
mH = h; mH = h;
mService = IWallpaperManager.Stub.asInterface(
ServiceManager.getService(Context.WALLPAPER_SERVICE));
mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE); mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
mCurrentUserId = ActivityManager.getCurrentUser(); mCurrentUserId = ActivityManager.getCurrentUser();
IWallpaperManager service = IWallpaperManager.Stub.asInterface(
ServiceManager.getService(Context.WALLPAPER_SERVICE));
try { try {
mService.setLockWallpaperCallback(this); service.setLockWallpaperCallback(this);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "System dead?" + e); Log.e(TAG, "System dead?" + e);
} }
} }
public Bitmap getBitmap() { public Bitmap getBitmap() {
try { if (mCached) {
if (mCached) { return mCache;
return mCache; }
} if (!mWallpaperManager.isWallpaperSupported()) {
if (!mService.isWallpaperSupported(mContext.getOpPackageName())) { mCached = true;
mCached = true; mCache = null;
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);
return 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) { public void setCurrentUser(int user) {
@@ -135,14 +139,16 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
return; return;
} }
mSelectedUser = selectedUser; mSelectedUser = selectedUser;
postUpdateWallpaper();
mH.removeCallbacks(this);
mH.post(this);
} }
@Override @Override
public void onWallpaperChanged() { public void onWallpaperChanged() {
// Called on Binder thread. // Called on Binder thread.
postUpdateWallpaper();
}
private void postUpdateWallpaper() {
mH.removeCallbacks(this); mH.removeCallbacks(this);
mH.post(this); mH.post(this);
} }
@@ -150,10 +156,52 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
@Override @Override
public void run() { public void run() {
// Called in response to onWallpaperChanged on the main thread. // Called in response to onWallpaperChanged on the main thread.
mCached = false;
mCache = null; if (mLoader != null) {
getBitmap(); mLoader.cancel(false /* interrupt */);
mBar.updateMediaMetaData(true /* metaDataChanged */, true /* allowEnterAnimation */); }
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);
}
} }
/** /**