Avoding writing ApplicationInfo multiple times for nested RemoteViews
Bug: 32240818 Test: All tests passing Change-Id: I00eec4d692763c53709e14b25a338e6320166c4a
This commit is contained in:
@@ -324,6 +324,14 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by subclasses which have (or inherit) an ApplicationInfo instance
|
||||
* as member variable
|
||||
*/
|
||||
public boolean hasSameAppInfo(ApplicationInfo parentInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
boolean nestedViewsNull = parcel.readInt() == 0;
|
||||
if (!nestedViewsNull) {
|
||||
nestedViews = new RemoteViews(parcel, bitmapCache);
|
||||
nestedViews = new RemoteViews(parcel, bitmapCache, info);
|
||||
} else {
|
||||
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
|
||||
public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
|
||||
final Context context = root.getContext();
|
||||
@@ -2195,10 +2210,10 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
* @param 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();
|
||||
|
||||
// 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) {
|
||||
mApplication = parcel.readParcelable(null);
|
||||
mApplication = parcel.readInt() == 0 ? info :
|
||||
ApplicationInfo.CREATOR.createFromParcel(parcel);
|
||||
mLayoutId = parcel.readInt();
|
||||
mIsWidgetCollectionChild = parcel.readInt() == 1;
|
||||
|
||||
@@ -2230,7 +2246,7 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
mActions.add(new ReflectionAction(parcel));
|
||||
break;
|
||||
case ViewGroupAction.TAG:
|
||||
mActions.add(new ViewGroupAction(parcel, mBitmapCache));
|
||||
mActions.add(new ViewGroupAction(parcel, mBitmapCache, mApplication));
|
||||
break;
|
||||
case ReflectionActionWithoutParams.TAG:
|
||||
mActions.add(new ReflectionActionWithoutParams(parcel));
|
||||
@@ -2278,8 +2294,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
} else {
|
||||
// MODE_HAS_LANDSCAPE_AND_PORTRAIT
|
||||
mLandscape = new RemoteViews(parcel, mBitmapCache);
|
||||
mPortrait = new RemoteViews(parcel, mBitmapCache);
|
||||
mLandscape = new RemoteViews(parcel, mBitmapCache, info);
|
||||
mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication);
|
||||
mApplication = mPortrait.mApplication;
|
||||
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.
|
||||
// Instead pretend we're not owning the cache while parceling.
|
||||
mIsRoot = false;
|
||||
writeToParcel(p, 0);
|
||||
writeToParcel(p, PARCELABLE_ELIDE_DUPLICATES);
|
||||
p.setDataPosition(0);
|
||||
mIsRoot = true;
|
||||
|
||||
RemoteViews rv = new RemoteViews(p, mBitmapCache.clone());
|
||||
RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication);
|
||||
rv.mIsRoot = true;
|
||||
|
||||
p.recycle();
|
||||
@@ -3536,7 +3552,12 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
if (mIsRoot) {
|
||||
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(mIsWidgetCollectionChild ? 1 : 0);
|
||||
int count;
|
||||
@@ -3548,7 +3569,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
dest.writeInt(count);
|
||||
for (int i=0; i<count; i++) {
|
||||
Action a = mActions.get(i);
|
||||
a.writeToParcel(dest, 0);
|
||||
a.writeToParcel(dest, a.hasSameAppInfo(mApplication)
|
||||
? PARCELABLE_ELIDE_DUPLICATES : 0);
|
||||
}
|
||||
} else {
|
||||
dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
|
||||
@@ -3558,7 +3580,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
mBitmapCache.writeBitmapsToParcel(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Parcel;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
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.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for RemoteViews.
|
||||
@@ -43,6 +45,9 @@ import static org.junit.Assert.assertSame;
|
||||
@SmallTest
|
||||
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
|
||||
public final ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@@ -121,4 +126,44 @@ public class RemoteViewsTest {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user