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

Commit fc8073c4 authored by Selim Cinek's avatar Selim Cinek
Browse files

Fixed a bug with decorated custom views

Even if their layout still maches, the content was unrecoverably
destroyed, so we can't just reapply it anymore.

Fixes: 62911941
Test: runtest -x packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java

Change-Id: I3a50c96484686958570ac5e4949df3ad4b8a421a
parent d836c4f8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -6935,6 +6935,7 @@ public class Notification implements Parcelable
                customContent = customContent.clone();
                remoteViews.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress);
                remoteViews.addView(R.id.notification_main_column, customContent, 0 /* index */);
                remoteViews.setReapplyDisallowed();
            }
            // also update the end margin if there is an image
            int endMargin = R.dimen.notification_content_margin_end;
@@ -7041,6 +7042,7 @@ public class Notification implements Parcelable
                customContent = customContent.clone();
                remoteViews.removeAllViews(id);
                remoteViews.addView(id, customContent);
                remoteViews.setReapplyDisallowed();
            }
            return remoteViews;
        }
+28 −0
Original line number Diff line number Diff line
@@ -153,6 +153,12 @@ public class RemoteViews implements Parcelable, Filter {
     */
    private boolean mIsRoot = true;

    /**
     * Whether reapply is disallowed on this remoteview. This maybe be true if some actions modify
     * the layout in a way that isn't recoverable, since views are being removed.
     */
    private boolean mReapplyDisallowed;

    /**
     * Constants to whether or not this RemoteViews is composed of a landscape and portrait
     * RemoteViews.
@@ -214,6 +220,26 @@ public class RemoteViews implements Parcelable, Filter {
        }
    }

    /**
     * Set that it is disallowed to reapply another remoteview with the same layout as this view.
     * This should be done if an action is destroying the view tree of the base layout.
     *
     * @hide
     */
    public void setReapplyDisallowed() {
        mReapplyDisallowed = true;
    }

    /**
     * @return Whether it is disallowed to reapply another remoteview with the same layout as this
     * view. True if this remoteview has actions that destroyed view tree of the base layout.
     *
     * @hide
     */
    public boolean isReapplyDisallowed() {
        return mReapplyDisallowed;
    }

    /**
     * Handle with care!
     */
@@ -2429,6 +2455,7 @@ public class RemoteViews implements Parcelable, Filter {
            mApplication = mPortrait.mApplication;
            mLayoutId = mPortrait.getLayoutId();
        }
        mReapplyDisallowed = parcel.readInt() == 0;

        // setup the memory usage statistics
        mMemoryUsageCounter = new MemoryUsageCounter();
@@ -3738,6 +3765,7 @@ public class RemoteViews implements Parcelable, Filter {
            // Both RemoteViews already share the same package and user
            mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES);
        }
        dest.writeInt(mReapplyDisallowed ? 1 : 0);
    }

    private static ApplicationInfo getApplicationInfo(String packageName, int userId) {
+20 −13
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ public class NotificationInflater {

        int flag = FLAG_REINFLATE_CONTENT_VIEW;
        if ((reInflateFlags & flag) != 0) {
            boolean isNewView = !compareRemoteViews(result.newContentView, entry.cachedContentView);
            boolean isNewView = !canReapplyRemoteView(result.newContentView, entry.cachedContentView);
            ApplyCallback applyCallback = new ApplyCallback() {
                @Override
                public void setResultView(View v) {
@@ -215,7 +215,7 @@ public class NotificationInflater {
        flag = FLAG_REINFLATE_EXPANDED_VIEW;
        if ((reInflateFlags & flag) != 0) {
            if (result.newExpandedView != null) {
                boolean isNewView = !compareRemoteViews(result.newExpandedView,
                boolean isNewView = !canReapplyRemoteView(result.newExpandedView,
                        entry.cachedBigContentView);
                ApplyCallback applyCallback = new ApplyCallback() {
                    @Override
@@ -240,7 +240,7 @@ public class NotificationInflater {
        flag = FLAG_REINFLATE_HEADS_UP_VIEW;
        if ((reInflateFlags & flag) != 0) {
            if (result.newHeadsUpView != null) {
                boolean isNewView = !compareRemoteViews(result.newHeadsUpView,
                boolean isNewView = !canReapplyRemoteView(result.newHeadsUpView,
                        entry.cachedHeadsUpContentView);
                ApplyCallback applyCallback = new ApplyCallback() {
                    @Override
@@ -264,7 +264,7 @@ public class NotificationInflater {

        flag = FLAG_REINFLATE_PUBLIC_VIEW;
        if ((reInflateFlags & flag) != 0) {
            boolean isNewView = !compareRemoteViews(result.newPublicView,
            boolean isNewView = !canReapplyRemoteView(result.newPublicView,
                    entry.cachedPublicContentView);
            ApplyCallback applyCallback = new ApplyCallback() {
                @Override
@@ -288,7 +288,7 @@ public class NotificationInflater {
        if ((reInflateFlags & flag) != 0) {
            NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
            boolean isNewView = !canReapplyAmbient(row, redactAmbient) ||
                    !compareRemoteViews(result.newAmbientView, entry.cachedAmbientContentView);
                    !canReapplyRemoteView(result.newAmbientView, entry.cachedAmbientContentView);
            ApplyCallback applyCallback = new ApplyCallback() {
                @Override
                public void setResultView(View v) {
@@ -486,14 +486,21 @@ public class NotificationInflater {
        return builder.createContentView(useLarge);
    }

    // Returns true if the RemoteViews are the same.
    private static boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
        return (a == null && b == null) ||
                (a != null && b != null
                        && b.getPackage() != null
                        && a.getPackage() != null
                        && a.getPackage().equals(b.getPackage())
                        && a.getLayoutId() == b.getLayoutId());
    /**
     * @param newView The new view that will be applied
     * @param oldView The old view that was applied to the existing view before
     * @return {@code true} if the RemoteViews are the same and the view can be reused to reapply.
     */
     @VisibleForTesting
     static boolean canReapplyRemoteView(final RemoteViews newView,
            final RemoteViews oldView) {
        return (newView == null && oldView == null) ||
                (newView != null && oldView != null
                        && oldView.getPackage() != null
                        && newView.getPackage() != null
                        && newView.getPackage().equals(oldView.getPackage())
                        && newView.getLayoutId() == oldView.getLayoutId()
                        && !oldView.isReapplyDisallowed());
    }

    public void setInflationCallback(InflationCallback callback) {
+12 −0
Original line number Diff line number Diff line
@@ -199,6 +199,18 @@ public class NotificationInflaterTest extends SysuiTestCase {
        runningTask.abort();
    }

    @Test
    public void doesntReapplyDisallowedRemoteView() throws Exception {
        mBuilder.setStyle(new Notification.MediaStyle());
        RemoteViews mediaView = mBuilder.createContentView();
        mBuilder.setStyle(new Notification.DecoratedCustomViewStyle());
        mBuilder.setCustomContentView(new RemoteViews(getContext().getPackageName(),
                R.layout.custom_view_dark));
        RemoteViews decoratedMediaView = mBuilder.createContentView();
        Assert.assertFalse("The decorated media style doesn't allow a view to be reapplied!",
                NotificationInflater.canReapplyRemoteView(mediaView, decoratedMediaView));
    }

    public static void runThenWaitForInflation(Runnable block,
            NotificationInflater inflater) throws Exception {
        runThenWaitForInflation(block, false /* expectingException */, inflater);