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

Commit 5d8bcdf6 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Avoding writing ApplicationInfo multiple times for nested RemoteViews

Bug: 32240818
Test: All tests passing
Change-Id: I00eec4d692763c53709e14b25a338e6320166c4a
parent d50ac516
Loading
Loading
Loading
Loading
+36 −13
Original line number Original line Diff line number Diff line
@@ -324,6 +324,14 @@ public class RemoteViews implements Parcelable, Filter {
            return false;
            return false;
        }
        }


        /**
         * Overridden by subclasses which have (or inherit) an ApplicationInfo instance
         * as member variable
         */
        public boolean hasSameAppInfo(ApplicationInfo parentInfo) {
            return true;
        }

        int viewId;
        int viewId;
    }
    }


@@ -1521,11 +1529,11 @@ public class RemoteViews implements Parcelable, Filter {
            }
            }
        }
        }


        public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) {
        ViewGroupAction(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info) {
            viewId = parcel.readInt();
            viewId = parcel.readInt();
            boolean nestedViewsNull = parcel.readInt() == 0;
            boolean nestedViewsNull = parcel.readInt() == 0;
            if (!nestedViewsNull) {
            if (!nestedViewsNull) {
                nestedViews = new RemoteViews(parcel, bitmapCache);
                nestedViews = new RemoteViews(parcel, bitmapCache, info);
            } else {
            } else {
                nestedViews = null;
                nestedViews = null;
            }
            }
@@ -1543,6 +1551,13 @@ public class RemoteViews implements Parcelable, Filter {
            }
            }
        }
        }


        @Override
        public boolean hasSameAppInfo(ApplicationInfo parentInfo) {
            return nestedViews != null
                    && nestedViews.mApplication.packageName.equals(parentInfo.packageName)
                    && nestedViews.mApplication.uid == parentInfo.uid;
        }

        @Override
        @Override
        public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
        public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
            final Context context = root.getContext();
            final Context context = root.getContext();
@@ -2195,10 +2210,10 @@ public class RemoteViews implements Parcelable, Filter {
     * @param parcel
     * @param parcel
     */
     */
    public RemoteViews(Parcel parcel) {
    public RemoteViews(Parcel parcel) {
        this(parcel, null);
        this(parcel, null, null);
    }
    }


    private RemoteViews(Parcel parcel, BitmapCache bitmapCache) {
    private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info) {
        int mode = parcel.readInt();
        int mode = parcel.readInt();


        // We only store a bitmap cache in the root of the RemoteViews.
        // We only store a bitmap cache in the root of the RemoteViews.
@@ -2210,7 +2225,8 @@ public class RemoteViews implements Parcelable, Filter {
        }
        }


        if (mode == MODE_NORMAL) {
        if (mode == MODE_NORMAL) {
            mApplication = parcel.readParcelable(null);
            mApplication = parcel.readInt() == 0 ? info :
                    ApplicationInfo.CREATOR.createFromParcel(parcel);
            mLayoutId = parcel.readInt();
            mLayoutId = parcel.readInt();
            mIsWidgetCollectionChild = parcel.readInt() == 1;
            mIsWidgetCollectionChild = parcel.readInt() == 1;


@@ -2230,7 +2246,7 @@ public class RemoteViews implements Parcelable, Filter {
                            mActions.add(new ReflectionAction(parcel));
                            mActions.add(new ReflectionAction(parcel));
                            break;
                            break;
                        case ViewGroupAction.TAG:
                        case ViewGroupAction.TAG:
                            mActions.add(new ViewGroupAction(parcel, mBitmapCache));
                            mActions.add(new ViewGroupAction(parcel, mBitmapCache, mApplication));
                            break;
                            break;
                        case ReflectionActionWithoutParams.TAG:
                        case ReflectionActionWithoutParams.TAG:
                            mActions.add(new ReflectionActionWithoutParams(parcel));
                            mActions.add(new ReflectionActionWithoutParams(parcel));
@@ -2278,8 +2294,8 @@ public class RemoteViews implements Parcelable, Filter {
            }
            }
        } else {
        } else {
            // MODE_HAS_LANDSCAPE_AND_PORTRAIT
            // MODE_HAS_LANDSCAPE_AND_PORTRAIT
            mLandscape = new RemoteViews(parcel, mBitmapCache);
            mLandscape = new RemoteViews(parcel, mBitmapCache, info);
            mPortrait = new RemoteViews(parcel, mBitmapCache);
            mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication);
            mApplication = mPortrait.mApplication;
            mApplication = mPortrait.mApplication;
            mLayoutId = mPortrait.getLayoutId();
            mLayoutId = mPortrait.getLayoutId();
        }
        }
@@ -2299,11 +2315,11 @@ public class RemoteViews implements Parcelable, Filter {
        // Do not parcel the Bitmap cache - doing so creates an expensive copy of all bitmaps.
        // Do not parcel the Bitmap cache - doing so creates an expensive copy of all bitmaps.
        // Instead pretend we're not owning the cache while parceling.
        // Instead pretend we're not owning the cache while parceling.
        mIsRoot = false;
        mIsRoot = false;
        writeToParcel(p, 0);
        writeToParcel(p, PARCELABLE_ELIDE_DUPLICATES);
        p.setDataPosition(0);
        p.setDataPosition(0);
        mIsRoot = true;
        mIsRoot = true;


        RemoteViews rv = new RemoteViews(p, mBitmapCache.clone());
        RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication);
        rv.mIsRoot = true;
        rv.mIsRoot = true;


        p.recycle();
        p.recycle();
@@ -3536,7 +3552,12 @@ public class RemoteViews implements Parcelable, Filter {
            if (mIsRoot) {
            if (mIsRoot) {
                mBitmapCache.writeBitmapsToParcel(dest, flags);
                mBitmapCache.writeBitmapsToParcel(dest, flags);
            }
            }
            dest.writeParcelable(mApplication, flags);
            if (!mIsRoot && (flags & PARCELABLE_ELIDE_DUPLICATES) != 0) {
                dest.writeInt(0);
            } else {
                dest.writeInt(1);
                mApplication.writeToParcel(dest, flags);
            }
            dest.writeInt(mLayoutId);
            dest.writeInt(mLayoutId);
            dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
            dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
            int count;
            int count;
@@ -3548,7 +3569,8 @@ public class RemoteViews implements Parcelable, Filter {
            dest.writeInt(count);
            dest.writeInt(count);
            for (int i=0; i<count; i++) {
            for (int i=0; i<count; i++) {
                Action a = mActions.get(i);
                Action a = mActions.get(i);
                a.writeToParcel(dest, 0);
                a.writeToParcel(dest, a.hasSameAppInfo(mApplication)
                        ? PARCELABLE_ELIDE_DUPLICATES : 0);
            }
            }
        } else {
        } else {
            dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
            dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
@@ -3558,7 +3580,8 @@ public class RemoteViews implements Parcelable, Filter {
                mBitmapCache.writeBitmapsToParcel(dest, flags);
                mBitmapCache.writeBitmapsToParcel(dest, flags);
            }
            }
            mLandscape.writeToParcel(dest, flags);
            mLandscape.writeToParcel(dest, flags);
            mPortrait.writeToParcel(dest, flags);
            // Both RemoteViews already share the same package and user
            mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES);
        }
        }
    }
    }


+45 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.support.test.InstrumentationRegistry;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.AndroidJUnit4;
@@ -35,6 +36,7 @@ import org.junit.runner.RunWith;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;


/**
/**
 * Tests for RemoteViews.
 * Tests for RemoteViews.
@@ -43,6 +45,9 @@ import static org.junit.Assert.assertSame;
@SmallTest
@SmallTest
public class RemoteViewsTest {
public class RemoteViewsTest {


    // This can point to any other package which exists on the device.
    private static final String OTHER_PACKAGE = "com.android.systemui";

    @Rule
    @Rule
    public final ExpectedException exception = ExpectedException.none();
    public final ExpectedException exception = ExpectedException.none();


@@ -121,4 +126,44 @@ public class RemoteViewsTest {
        clone.apply(mContext, mContainer);
        clone.apply(mContext, mContainer);
    }
    }


    @Test
    public void parcelSize_nestedViews() {
        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
        // We don't care about the actual layout id.
        RemoteViews child = new RemoteViews(mPackage, 33);
        int expectedSize = getParcelSize(original) + getParcelSize(child);
        original.addView(R.id.layout, child);

        // The application info will get written only once.
        assertTrue(getParcelSize(original) < expectedSize);
        assertEquals(getParcelSize(original), getParcelSize(original.clone()));

        original = new RemoteViews(mPackage, R.layout.remote_views_test);
        child = new RemoteViews(OTHER_PACKAGE, 33);
        expectedSize = getParcelSize(original) + getParcelSize(child);
        original.addView(R.id.layout, child);

        // Both the views will get written completely along with an additional view operation
        assertTrue(getParcelSize(original) > expectedSize);
        assertEquals(getParcelSize(original), getParcelSize(original.clone()));
    }

    @Test
    public void parcelSize_differentOrientation() {
        RemoteViews landscape = new RemoteViews(mPackage, R.layout.remote_views_test);
        RemoteViews portrait = new RemoteViews(mPackage, 33);

        // The application info will get written only once.
        RemoteViews views = new RemoteViews(landscape, portrait);
        assertTrue(getParcelSize(views) < (getParcelSize(landscape) + getParcelSize(portrait)));
        assertEquals(getParcelSize(views), getParcelSize(views.clone()));
    }

    private int getParcelSize(RemoteViews view) {
        Parcel parcel = Parcel.obtain();
        view.writeToParcel(parcel, 0);
        int size = parcel.dataSize();
        parcel.recycle();
        return size;
    }
}
}