Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e9dec28 authored by Adrian Roos's avatar Adrian Roos
Browse files

Reload LockscreenWallpaper and ImageWallpaper on background thread

Fixes: 27148260
Change-Id: I426712024ec1a82fccd48154c65da31d3e610525
parent f91cbc7f
Loading
Loading
Loading
Loading
+91 −51
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.graphics.Rect;
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 @@ public class ImageWallpaper extends WallpaperService {

        private int mLastRequestedWidth = -1;
        private int mLastRequestedHeight = -1;
        private AsyncTask<Void, Void, Bitmap> mLoader;
        private boolean mNeedsDrawAfterLoadingWallpaper;

        public DrawableEngine() {
            super();
@@ -184,10 +187,9 @@ public class ImageWallpaper extends WallpaperService {
            super.onCreate(surfaceHolder);

            mDefaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();

            updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo());

            setOffsetNotificationsEnabled(false);

            updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo(), false /* forDraw */);
        }

        @Override
@@ -197,17 +199,19 @@ public class ImageWallpaper extends WallpaperService {
            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 @@ public class ImageWallpaper extends WallpaperService {
            } else {
                surfaceHolder.setSizeFromLayout();
            }
            return hasWallpaper;
        }

        @Override
@@ -299,6 +304,7 @@ public class ImageWallpaper extends WallpaperService {
            }
            super.onSurfaceRedrawNeeded(holder);

            mLastSurfaceHeight = mLastSurfaceWidth = -1;
            drawFrame();
        }

@@ -317,7 +323,9 @@ public class ImageWallpaper extends WallpaperService {
                // 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 @@ public class ImageWallpaper extends WallpaperService {
                }
                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,21 +357,12 @@ public class ImageWallpaper extends WallpaperService {
                                dw + ", " + dh);
                    }
                    mWallpaperManager.forgetLoadedWallpaper();
                    updateWallpaperLocked();
                    if (mBackground == null) {
                    loadWallpaper(true /* needDraw */);
                    if (DEBUG) {
                            Log.d(TAG, "Unable to load bitmap");
                        Log.d(TAG, "Reloading, resuming draw later");
                    }
                    return;
                }
                    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());
                        }
                    }
                }

                // Center the scaled image
                mScale = Math.max(1f, Math.max(dw / (float) mBackground.getWidth(),
@@ -422,25 +421,32 @@ public class ImageWallpaper extends WallpaperService {
            }
        }

        private void updateWallpaperLocked() {
            Throwable exception = null;
        /**
         * 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 {
                mBackground = null;
                mBackgroundWidth = -1;
                mBackgroundHeight = -1;
                mBackground = mWallpaperManager.getBitmap();
                mBackgroundWidth = mBackground.getWidth();
                mBackgroundHeight = mBackground.getHeight();
            } catch (RuntimeException e) {
                exception = e;
            } catch (OutOfMemoryError e) {
                        return mWallpaperManager.getBitmap();
                    } catch (RuntimeException | 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.
@@ -451,7 +457,41 @@ public class ImageWallpaper extends WallpaperService {
                            // 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
+103 −55
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ import android.graphics.BitmapFactory;
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 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen

    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,68 +56,74 @@ 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
    // 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())) {
        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 =
                    mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
            ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_LOCK,
                    new Bundle(), lockWallpaperUserId);
                selectedUser != null ? selectedUser.getIdentifier() : currentUserId;
        ParcelFileDescriptor fd = mWallpaperManager.getWallpaperFile(
                WallpaperManager.FLAG_LOCK, lockWallpaperUserId);

        if (fd != null) {
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                    mCache = BitmapFactory.decodeFileDescriptor(
                            fd.getFileDescriptor(), null, options);
                    mCached = true;
                    return mCache;
                return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
                        fd.getFileDescriptor(), null, options));
            } catch (OutOfMemoryError e) {
                Log.w(TAG, "Can't decode file", e);
                    return null;
                return LoaderResult.fail();
            } finally {
                IoUtils.closeQuietly(fd);
            }
        } else {
                mCached = true;
                if (mSelectedUser != null && mSelectedUser.getIdentifier() != mCurrentUserId) {
            if (selectedUser != null && selectedUser.getIdentifier() != currentUserId) {
                // When selected user is different from the current user, show the selected
                // user's static wallpaper.
                    mCache = mWallpaperManager.getBitmapAsUser(mSelectedUser.getIdentifier());
                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.
                    mCache = null;
                }
                return mCache;
                return LoaderResult.success(null);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "System dead?" + e);
            return null;
        }
    }

@@ -135,14 +139,16 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
            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 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
    @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);
        }
    }

    /**