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

Commit 18b714c7 authored by Selim Cinek's avatar Selim Cinek Committed by android-build-merger
Browse files

Merge "Retrying the remoteview application on the ui thread" into oc-dev am: 07b93779

am: 12a9c8ea

Change-Id: I65434b26ed8129bd8d1a105f7c4773996b9f9b32
parents 5f0110cc 12a9c8ea
Loading
Loading
Loading
Loading
+32 −7
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 */
public class NotificationInflater {

    public static final String TAG = "NotificationInflater";
    @VisibleForTesting
    static final int FLAG_REINFLATE_ALL = ~0;
    private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
@@ -315,7 +316,8 @@ public class NotificationInflater {
        return cancellationSignal;
    }

    private static void applyRemoteView(final InflationProgress result,
    @VisibleForTesting
    static void applyRemoteView(final InflationProgress result,
            final int reInflateFlags, int inflationId,
            final ExpandableNotificationRow row,
            final boolean redactAmbient, boolean isNewView,
@@ -325,6 +327,7 @@ public class NotificationInflater {
            NotificationViewWrapper existingWrapper,
            final HashMap<Integer, CancellationSignal> runningInflations,
            ApplyCallback applyCallback) {
        RemoteViews newContentView = applyCallback.getRemoteView();
        RemoteViews.OnViewAppliedListener listener
                = new RemoteViews.OnViewAppliedListener() {

@@ -343,12 +346,31 @@ public class NotificationInflater {

            @Override
            public void onError(Exception e) {
                // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this could
                // actually also be a system issue, so let's try on the UI thread again to be safe.
                try {
                    View newView = existingView;
                    if (isNewView) {
                        newView = newContentView.apply(
                                result.packageContext,
                                parentLayout,
                                remoteViewClickHandler);
                    } else {
                        newContentView.reapply(
                                result.packageContext,
                                existingView,
                                remoteViewClickHandler);
                    }
                    Log.wtf(TAG, "Async Inflation failed but normal inflation finished normally.",
                            e);
                    onViewApplied(newView);
                } catch (Exception anotherException) {
                    runningInflations.remove(inflationId);
                    handleInflationError(runningInflations, e, entry.notification, callback);
                }
            }
        };
        CancellationSignal cancellationSignal;
        RemoteViews newContentView = applyCallback.getRemoteView();
        if (isNewView) {
            cancellationSignal = newContentView.applyAsync(
                    result.packageContext,
@@ -620,14 +642,16 @@ public class NotificationInflater {
        }
    }

    private static class InflationProgress {
    @VisibleForTesting
    static class InflationProgress {
        private RemoteViews newContentView;
        private RemoteViews newHeadsUpView;
        private RemoteViews newExpandedView;
        private RemoteViews newAmbientView;
        private RemoteViews newPublicView;

        private Context packageContext;
        @VisibleForTesting
        Context packageContext;

        private View inflatedContentView;
        private View inflatedHeadsUpView;
@@ -636,7 +660,8 @@ public class NotificationInflater {
        private View inflatedPublicView;
    }

    private abstract static class ApplyCallback {
    @VisibleForTesting
    abstract static class ApplyCallback {
        public abstract void setResultView(View v);
        public abstract RemoteViews getRemoteView();
    }
+68 −0
Original line number Diff line number Diff line
@@ -24,12 +24,17 @@ import static org.mockito.Mockito.verify;

import android.app.Notification;
import android.content.Context;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;

import com.android.systemui.R;
@@ -45,7 +50,9 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;

@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -142,6 +149,41 @@ public class NotificationInflaterTest extends SysuiTestCase {
        Assert.assertNull(mRow.getEntry().getRunningTask());
    }

    @Test
    public void testInflationIsRetriedIfAsyncFails() throws Exception {
        NotificationInflater.InflationProgress result =
                new NotificationInflater.InflationProgress();
        result.packageContext = mContext;
        CountDownLatch countDownLatch = new CountDownLatch(1);
        NotificationInflater.applyRemoteView(result,
                NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW, 0, mRow,
                false /* redactAmbient */, true /* isNewView */, new RemoteViews.OnClickHandler(),
                new NotificationInflater.InflationCallback() {
                    @Override
                    public void handleInflationException(StatusBarNotification notification,
                            Exception e) {
                        countDownLatch.countDown();
                        throw new RuntimeException("No Exception expected");
                    }

                    @Override
                    public void onAsyncInflationFinished(NotificationData.Entry entry) {
                        countDownLatch.countDown();
                    }
                }, mRow.getEntry(), mRow.getPrivateLayout(), null, null, new HashMap<>(),
                new NotificationInflater.ApplyCallback() {
                    @Override
                    public void setResultView(View v) {
                    }

                    @Override
                    public RemoteViews getRemoteView() {
                        return new AsyncFailRemoteView(mContext.getPackageName(),
                                R.layout.custom_view_dark);
                    }
                });
        countDownLatch.await();
    }

    @Test
    public void testSupersedesExistingTask() throws Exception {
@@ -200,4 +242,30 @@ public class NotificationInflaterTest extends SysuiTestCase {
            mException = exception;
        }
    }

    private class AsyncFailRemoteView extends RemoteViews {
        Handler mHandler = new Handler(Looper.getMainLooper());

        public AsyncFailRemoteView(String packageName, int layoutId) {
            super(packageName, layoutId);
        }

        @Override
        public View apply(Context context, ViewGroup parent) {
            return super.apply(context, parent);
        }

        @Override
        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
                OnViewAppliedListener listener, OnClickHandler handler) {
            mHandler.post(() -> listener.onError(new RuntimeException("Failed to inflate async")));
            return new CancellationSignal();
        }

        @Override
        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
                OnViewAppliedListener listener) {
            return applyAsync(context, parent, executor, listener, null);
        }
    }
}