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

Commit 80c5f50d authored by Valentin Iftime's avatar Valentin Iftime Committed by Automerger Merge Worker
Browse files

[DO NOT MERGE] Wait for preloading images to complete before inflating notifications am: 733089e7

parents 727c672f 733089e7
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -435,6 +435,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
        CancellationSignal cancellationSignal = new CancellationSignal();
        cancellationSignal.setOnCancelListener(
                () -> runningInflations.values().forEach(CancellationSignal::cancel));

        return cancellationSignal;
    }

@@ -700,6 +701,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
    public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
            implements InflationCallback, InflationTask {

        private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L;
        private final NotificationEntry mEntry;
        private final Context mContext;
        private final boolean mInflateSynchronously;
@@ -786,10 +788,16 @@ public class NotificationContentInflater implements NotificationRowContentBinder
                InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
                        recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
                        mUsesIncreasedHeadsUpHeight, packageContext);
                return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mEntry,

                InflationProgress result = inflateSmartReplyViews(inflationProgress, mReInflateFlags, mEntry,
                        mRow.getContext(), packageContext, mRow.getHeadsUpManager(),
                        mSmartReplyConstants, mSmartReplyController,
                        mRow.getExistingSmartRepliesAndActions());

                // wait for image resolver to finish preloading
                mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);

                return result;
            } catch (Exception e) {
                mError = e;
                return null;
@@ -824,6 +832,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder
                mCallback.handleInflationException(mRow.getEntry(),
                        new InflationException("Couldn't inflate contentViews" + e));
            }

            // Cancel any image loading tasks, not useful any more
            mRow.getImageResolver().cancelRunningTasks();
        }

        @Override
@@ -850,6 +861,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder
            // Notify the resolver that the inflation task has finished,
            // try to purge unnecessary cached entries.
            mRow.getImageResolver().purgeCache();

            // Cancel any image loading tasks that have not completed at this point
            mRow.getImageResolver().cancelRunningTasks();
        }

        private class RtlEnabledContext extends ContextWrapper {
+18 −6
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * A cache for inline images of image messages.
@@ -57,12 +59,13 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso
    }

    @Override
    public Drawable get(Uri uri) {
    public Drawable get(Uri uri, long timeoutMs) {
        Drawable result = null;
        try {
            result = mCache.get(uri).get();
        } catch (InterruptedException | ExecutionException ex) {
            Log.d(TAG, "get: Failed get image from " + uri);
            result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException
                | TimeoutException | CancellationException ex) {
            Log.d(TAG, "get: Failed get image from " + uri + " " + ex);
        }
        return result;
    }
@@ -73,6 +76,15 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso
        mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey()));
    }

    @Override
    public void cancelRunningTasks() {
        mCache.forEach((key, value) -> {
            if (value.getStatus() != AsyncTask.Status.FINISHED) {
                value.cancel(true);
            }
        });
    }

    private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> {
        private final NotificationInlineImageResolver mResolver;

@@ -87,7 +99,7 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso

            try {
                drawable = mResolver.resolveImage(target);
            } catch (IOException | SecurityException ex) {
            } catch (Exception ex) {
                Log.d(TAG, "PreloadImageTask: Resolve failed from " + target, ex);
            }

+51 −6
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.Log;

import com.android.internal.R;
@@ -49,6 +50,9 @@ import java.util.Set;
public class NotificationInlineImageResolver implements ImageResolver {
    private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();

    // Timeout for loading images from ImageCache when calling from UI thread
    private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L;

    private final Context mContext;
    private final ImageCache mImageCache;
    private Set<Uri> mWantedUriSet;
@@ -132,16 +136,20 @@ public class NotificationInlineImageResolver implements ImageResolver {
        return image;
    }

    /**
     * Loads an image from the Uri.
     * This method is synchronous and is usually called from the Main thread.
     * It will time-out after MAX_UI_THREAD_TIMEOUT_MS.
     *
     * @param uri Uri of the target image.
     * @return drawable of the image, null if loading failed/timeout
     */
    @Override
    public Drawable loadImage(Uri uri) {
        Drawable result = null;
        try {
            if (hasCache()) {
                // if the uri isn't currently cached, try caching it first
                if (!mImageCache.hasEntry(uri)) {
                    mImageCache.preload((uri));
                }
                result = mImageCache.get(uri);
                result = loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS);
            } else {
                result = resolveImage(uri);
            }
@@ -151,6 +159,14 @@ public class NotificationInlineImageResolver implements ImageResolver {
        return result;
    }

    private Drawable loadImageFromCache(Uri uri, long timeoutMs) {
        // if the uri isn't currently cached, try caching it first
        if (!mImageCache.hasEntry(uri)) {
            mImageCache.preload((uri));
        }
        return mImageCache.get(uri, timeoutMs);
    }

    /**
     * Resolve the message list from specified notification and
     * refresh internal cache according to the result.
@@ -222,6 +238,30 @@ public class NotificationInlineImageResolver implements ImageResolver {
        return mWantedUriSet;
    }

    /**
     * Wait for a maximum timeout for images to finish preloading
     * @param timeoutMs total timeout time
     */
    void waitForPreloadedImages(long timeoutMs) {
        if (!hasCache()) {
            return;
        }
        Set<Uri> preloadedUris = getWantedUriSet();
        if (preloadedUris != null) {
            // Decrement remaining timeout after each image check
            long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs;
            preloadedUris.forEach(
                    uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime()));
        }
    }

    void cancelRunningTasks() {
        if (!hasCache()) {
            return;
        }
        mImageCache.cancelRunningTasks();
    }

    /**
     * A interface for internal cache implementation of this resolver.
     */
@@ -231,7 +271,7 @@ public class NotificationInlineImageResolver implements ImageResolver {
         * @param uri The uri of the image.
         * @return Drawable of the image.
         */
        Drawable get(Uri uri);
        Drawable get(Uri uri, long timeoutMs);

        /**
         * Set the image resolver that actually resolves image from specified uri.
@@ -256,6 +296,11 @@ public class NotificationInlineImageResolver implements ImageResolver {
         * Purge unnecessary entries in the cache.
         */
        void purge();

        /**
         * Cancel all unfinished image loading tasks
         */
        void cancelRunningTasks();
    }

}