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 Original line Diff line number Diff line
@@ -48,6 +48,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 */
 */
public class NotificationInflater {
public class NotificationInflater {


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


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


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


            @Override
            @Override
            public void onError(Exception e) {
            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);
                    runningInflations.remove(inflationId);
                    handleInflationError(runningInflations, e, entry.notification, callback);
                    handleInflationError(runningInflations, e, entry.notification, callback);
                }
                }
            }
        };
        };
        CancellationSignal cancellationSignal;
        CancellationSignal cancellationSignal;
        RemoteViews newContentView = applyCallback.getRemoteView();
        if (isNewView) {
        if (isNewView) {
            cancellationSignal = newContentView.applyAsync(
            cancellationSignal = newContentView.applyAsync(
                    result.packageContext,
                    result.packageContext,
@@ -620,14 +642,16 @@ public class NotificationInflater {
        }
        }
    }
    }


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


        private Context packageContext;
        @VisibleForTesting
        Context packageContext;


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


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


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


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


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


@SmallTest
@SmallTest
@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
@@ -142,6 +149,41 @@ public class NotificationInflaterTest extends SysuiTestCase {
        Assert.assertNull(mRow.getEntry().getRunningTask());
        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
    @Test
    public void testSupersedesExistingTask() throws Exception {
    public void testSupersedesExistingTask() throws Exception {
@@ -200,4 +242,30 @@ public class NotificationInflaterTest extends SysuiTestCase {
            mException = exception;
            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);
        }
    }
}
}