Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -27842,6 +27842,7 @@ package android.widget { public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable { ctor public RemoteViews(java.lang.String, int); ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews); ctor public RemoteViews(android.os.Parcel); method public void addView(int, android.widget.RemoteViews); method public android.view.View apply(android.content.Context, android.view.ViewGroup); core/java/android/widget/RemoteViews.java +417 −99 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; Loading Loading @@ -87,6 +88,31 @@ public class RemoteViews implements Parcelable, Filter { */ private MemoryUsageCounter mMemoryUsageCounter; /** * Maps bitmaps to unique indicies to avoid Bitmap duplication. */ private BitmapCache mBitmapCache; /** * Indicates whether or not this RemoteViews object is contained as a child of any other * RemoteViews. */ private boolean mIsRoot = true; /** * Constants to whether or not this RemoteViews is composed of a landscape and portrait * RemoteViews. */ private static final int MODE_NORMAL = 0; private static final int MODE_HAS_LANDSCAPE_AND_PORTRAIT = 1; /** * Used in conjunction with the special constructor * {@link #RemoteViews(RemoteViews, RemoteViews)} to keep track of the landscape and portrait * RemoteViews. */ private RemoteViews mLandscape = null; private RemoteViews mPortrait = null; /** * This flag indicates whether this RemoteViews object is being created from a Loading Loading @@ -163,6 +189,10 @@ public class RemoteViews implements Parcelable, Filter { } return true; } public void setBitmapCache(BitmapCache bitmapCache) { // Do nothing } } private class SetEmptyView extends Action { Loading Loading @@ -643,6 +673,112 @@ public class RemoteViews implements Parcelable, Filter { } } private static class BitmapCache { ArrayList<Bitmap> mBitmaps; public BitmapCache() { mBitmaps = new ArrayList<Bitmap>(); } public BitmapCache(Parcel source) { int count = source.readInt(); mBitmaps = new ArrayList<Bitmap>(); for (int i = 0; i < count; i++) { Bitmap b = Bitmap.CREATOR.createFromParcel(source); mBitmaps.add(b); } } public int getBitmapId(Bitmap b) { if (b == null) { return -1; } else { if (mBitmaps.contains(b)) { return mBitmaps.indexOf(b); } else { mBitmaps.add(b); return (mBitmaps.size() - 1); } } } public Bitmap getBitmapForId(int id) { if (id == -1 || id >= mBitmaps.size()) { return null; } else { return mBitmaps.get(id); } } public void writeBitmapsToParcel(Parcel dest, int flags) { int count = mBitmaps.size(); dest.writeInt(count); for (int i = 0; i < count; i++) { mBitmaps.get(i).writeToParcel(dest, flags); } } public void assimilate(BitmapCache bitmapCache) { ArrayList<Bitmap> bitmapsToBeAdded = bitmapCache.mBitmaps; int count = bitmapsToBeAdded.size(); for (int i = 0; i < count; i++) { Bitmap b = bitmapsToBeAdded.get(i); if (!mBitmaps.contains(b)) { mBitmaps.add(b); } } } public void addBitmapMemory(MemoryUsageCounter memoryCounter) { for (int i = 0; i < mBitmaps.size(); i++) { memoryCounter.addBitmapMemory(mBitmaps.get(i)); } } } private class BitmapReflectionAction extends Action { int bitmapId; int viewId; Bitmap bitmap; String methodName; BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) { this.bitmap = bitmap; this.viewId = viewId; this.methodName = methodName; bitmapId = mBitmapCache.getBitmapId(bitmap); } BitmapReflectionAction(Parcel in) { viewId = in.readInt(); methodName = in.readString(); bitmapId = in.readInt(); bitmap = mBitmapCache.getBitmapForId(bitmapId); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(TAG); dest.writeInt(viewId); dest.writeString(methodName); dest.writeInt(bitmapId); } @Override public void apply(View root, ViewGroup rootParent) throws ActionException { ReflectionAction ra = new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, bitmap); ra.apply(root, rootParent); } @Override public void setBitmapCache(BitmapCache bitmapCache) { bitmapId = bitmapCache.getBitmapId(bitmap); } public final static int TAG = 12; } /** * Base class for the reflection actions. */ Loading Loading @@ -894,24 +1030,7 @@ public class RemoteViews implements Parcelable, Filter { case BITMAP: if (this.value != null) { final Bitmap b = (Bitmap) this.value; final Bitmap.Config c = b.getConfig(); // If we don't know, be pessimistic and assume 4 int bpp = 4; if (c != null) { switch (c) { case ALPHA_8: bpp = 1; break; case RGB_565: case ARGB_4444: bpp = 2; break; case ARGB_8888: bpp = 4; break; } } counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp); counter.addBitmapMemory(b); } break; default: Loading @@ -920,6 +1039,16 @@ public class RemoteViews implements Parcelable, Filter { } } private void configureRemoteViewsAsChild(RemoteViews rv) { mBitmapCache.assimilate(rv.mBitmapCache); rv.setBitmapCache(mBitmapCache); rv.setNotRoot(); } void setNotRoot() { mIsRoot = false; } /** * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()} Loading @@ -929,17 +1058,29 @@ public class RemoteViews implements Parcelable, Filter { public ViewGroupAction(int viewId, RemoteViews nestedViews) { this.viewId = viewId; this.nestedViews = nestedViews; configureRemoteViewsAsChild(nestedViews); } public ViewGroupAction(Parcel parcel) { public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) { viewId = parcel.readInt(); nestedViews = parcel.readParcelable(null); boolean nestedViewsNull = parcel.readInt() == 0; if (!nestedViewsNull) { nestedViews = new RemoteViews(parcel, bitmapCache); } else { nestedViews = null; } } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(TAG); dest.writeInt(viewId); dest.writeParcelable(nestedViews, 0 /* no flags */); if (nestedViews != null) { dest.writeInt(1); nestedViews.writeToParcel(dest, flags); } else { // signifies null dest.writeInt(0); } } @Override Loading @@ -959,7 +1100,14 @@ public class RemoteViews implements Parcelable, Filter { @Override public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { if (nestedViews != null) { counter.bitmapIncrement(nestedViews.estimateBitmapMemoryUsage()); counter.increment(nestedViews.estimateMemoryUsage()); } } @Override public void setBitmapCache(BitmapCache bitmapCache) { if (nestedViews != null) { nestedViews.setBitmapCache(bitmapCache); } } Loading Loading @@ -1027,18 +1175,39 @@ public class RemoteViews implements Parcelable, Filter { */ private class MemoryUsageCounter { public void clear() { mBitmapHeapMemoryUsage = 0; mMemoryUsage = 0; } public void bitmapIncrement(int numBytes) { mBitmapHeapMemoryUsage += numBytes; public void increment(int numBytes) { mMemoryUsage += numBytes; } public int getBitmapHeapMemoryUsage() { return mBitmapHeapMemoryUsage; public int getMemoryUsage() { return mMemoryUsage; } int mBitmapHeapMemoryUsage; public void addBitmapMemory(Bitmap b) { final Bitmap.Config c = b.getConfig(); // If we don't know, be pessimistic and assume 4 int bpp = 4; if (c != null) { switch (c) { case ALPHA_8: bpp = 1; break; case RGB_565: case ARGB_4444: bpp = 2; break; case ARGB_8888: bpp = 4; break; } } increment(b.getWidth() * b.getHeight() * bpp); } int mMemoryUsage; } /** Loading @@ -1051,9 +1220,44 @@ public class RemoteViews implements Parcelable, Filter { public RemoteViews(String packageName, int layoutId) { mPackage = packageName; mLayoutId = layoutId; mBitmapCache = new BitmapCache(); // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); recalculateMemoryUsage(); } private boolean hasLandscapeAndPortraitLayouts() { return (mLandscape != null) && (mPortrait != null); } /** * Create a new RemoteViews object that will inflate as the specified * landspace or portrait RemoteViews, depending on the current configuration. * * @param landscape The RemoteViews to inflate in landscape configuration * @param portrait The RemoteViews to inflate in portrait configuration */ public RemoteViews(RemoteViews landscape, RemoteViews portrait) { if (landscape == null || portrait == null) { throw new RuntimeException("Both RemoteViews must be non-null"); } if (landscape.getPackage().compareTo(portrait.getPackage()) != 0) { throw new RuntimeException("Both RemoteViews must share the same package"); } mPackage = portrait.getPackage(); mLayoutId = portrait.getLayoutId(); mLandscape = landscape; mPortrait = portrait; // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); mBitmapCache = new BitmapCache(); configureRemoteViewsAsChild(landscape); configureRemoteViewsAsChild(portrait); recalculateMemoryUsage(); } Loading @@ -1063,6 +1267,21 @@ public class RemoteViews implements Parcelable, Filter { * @param parcel */ public RemoteViews(Parcel parcel) { this(parcel, null); } private RemoteViews(Parcel parcel, BitmapCache bitmapCache) { int mode = parcel.readInt(); // We only store a bitmap cache in the root of the RemoteViews. if (bitmapCache == null) { mBitmapCache = new BitmapCache(parcel); } else { setBitmapCache(bitmapCache); setNotRoot(); } if (mode == MODE_NORMAL) { mPackage = parcel.readString(); mLayoutId = parcel.readInt(); mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false; Loading @@ -1083,7 +1302,7 @@ public class RemoteViews implements Parcelable, Filter { mActions.add(new ReflectionAction(parcel)); break; case ViewGroupAction.TAG: mActions.add(new ViewGroupAction(parcel)); mActions.add(new ViewGroupAction(parcel, mBitmapCache)); break; case ReflectionActionWithoutParams.TAG: mActions.add(new ReflectionActionWithoutParams(parcel)); Loading @@ -1103,11 +1322,21 @@ public class RemoteViews implements Parcelable, Filter { case TextViewDrawableAction.TAG: mActions.add(new TextViewDrawableAction(parcel)); break; case BitmapReflectionAction.TAG: mActions.add(new BitmapReflectionAction(parcel)); break; default: throw new ActionException("Tag " + tag + " not found"); } } } } else { // MODE_HAS_LANDSCAPE_AND_PORTRAIT mLandscape = new RemoteViews(parcel, mBitmapCache); mPortrait = new RemoteViews(parcel, mBitmapCache); mPackage = mPortrait.getPackage(); mLayoutId = mPortrait.getLayoutId(); } // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); Loading @@ -1116,11 +1345,18 @@ public class RemoteViews implements Parcelable, Filter { @Override public RemoteViews clone() { final RemoteViews that = new RemoteViews(mPackage, mLayoutId); RemoteViews that; if (!hasLandscapeAndPortraitLayouts()) { that = new RemoteViews(mPackage, mLayoutId); if (mActions != null) { that.mActions = (ArrayList<Action>)mActions.clone(); } } else { RemoteViews land = mLandscape.clone(); RemoteViews port = mPortrait.clone(); that = new RemoteViews(land, port); } // update the memory usage stats of the cloned RemoteViews that.recalculateMemoryUsage(); return that; Loading @@ -1130,6 +1366,13 @@ public class RemoteViews implements Parcelable, Filter { return mPackage; } /** * Reutrns the layout id of the root layout associated with this RemoteViews. In the case * that the RemoteViews has both a landscape and portrait root, this will return the layout * id associated with the portrait layout. * * @return the layout id. */ public int getLayoutId() { return mLayoutId; } Loading @@ -1151,6 +1394,7 @@ public class RemoteViews implements Parcelable, Filter { private void recalculateMemoryUsage() { mMemoryUsageCounter.clear(); if (!hasLandscapeAndPortraitLayouts()) { // Accumulate the memory usage for each action if (mActions != null) { final int count = mActions.size(); Loading @@ -1158,13 +1402,39 @@ public class RemoteViews implements Parcelable, Filter { mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter); } } if (mIsRoot) { mBitmapCache.addBitmapMemory(mMemoryUsageCounter); } } else { mMemoryUsageCounter.increment(mLandscape.estimateMemoryUsage()); mMemoryUsageCounter.increment(mPortrait.estimateMemoryUsage()); mBitmapCache.addBitmapMemory(mMemoryUsageCounter); } } /** * Recursively sets BitmapCache in the hierarchy and update the bitmap ids. */ private void setBitmapCache(BitmapCache bitmapCache) { mBitmapCache = bitmapCache; if (!hasLandscapeAndPortraitLayouts()) { if (mActions != null) { final int count = mActions.size(); for (int i= 0; i < count; ++i) { mActions.get(i).setBitmapCache(bitmapCache); } } } else { mLandscape.setBitmapCache(bitmapCache); mPortrait.setBitmapCache(bitmapCache); } } /** * Returns an estimate of the bitmap heap memory usage for this RemoteViews. */ int estimateBitmapMemoryUsage() { return mMemoryUsageCounter.getBitmapHeapMemoryUsage(); int estimateMemoryUsage() { return mMemoryUsageCounter.getMemoryUsage(); } /** Loading @@ -1173,6 +1443,11 @@ public class RemoteViews implements Parcelable, Filter { * @param a The action to add */ private void addAction(Action a) { if (hasLandscapeAndPortraitLayouts()) { throw new RuntimeException("RemoteViews specifying separate landscape and portrait" + " layouts cannot be modified. Instead, fully configure the landscape and" + " portrait layouts individually before constructing the combined layout."); } if (mActions == null) { mActions = new ArrayList<Action>(); } Loading Loading @@ -1644,7 +1919,7 @@ public class RemoteViews implements Parcelable, Filter { * @param value The value to pass to the method. */ public void setBitmap(int viewId, String methodName, Bitmap value) { addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value)); addAction(new BitmapReflectionAction(viewId, methodName, value)); } /** Loading Loading @@ -1679,6 +1954,18 @@ public class RemoteViews implements Parcelable, Filter { setCharSequence(viewId, "setContentDescription", contentDescription); } private RemoteViews getRemoteViewsToApply(Context context) { if (hasLandscapeAndPortraitLayouts()) { int orientation = context.getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { return mLandscape; } else { return mPortrait; } } return this; } /** * Inflates the view hierarchy represented by this object and applies * all of the actions. Loading @@ -1691,6 +1978,8 @@ public class RemoteViews implements Parcelable, Filter { * @return The inflated view hierarchy */ public View apply(Context context, ViewGroup parent) { RemoteViews rvToApply = getRemoteViewsToApply(context); View result; Context c = prepareContext(context); Loading @@ -1701,9 +1990,9 @@ public class RemoteViews implements Parcelable, Filter { inflater = inflater.cloneInContext(c); inflater.setFilter(this); result = inflater.inflate(mLayoutId, parent, false); result = inflater.inflate(rvToApply.getLayoutId(), parent, false); performApply(result, parent); rvToApply.performApply(result, parent); return result; } Loading @@ -1717,8 +2006,20 @@ public class RemoteViews implements Parcelable, Filter { * the {@link #apply(Context,ViewGroup)} call. */ public void reapply(Context context, View v) { RemoteViews rvToApply = getRemoteViewsToApply(context); // In the case that a view has this RemoteViews applied in one orientation, is persisted // across orientation change, and has the RemoteViews re-applied in the new orientation, // we throw an exception, since the layouts may be completely unrelated. if (hasLandscapeAndPortraitLayouts()) { if (v.getId() != rvToApply.getLayoutId()) { throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + " that does not share the same root layout id."); } } prepareContext(context); performApply(v, (ViewGroup) v.getParent()); rvToApply.performApply(v, (ViewGroup) v.getParent()); } private void performApply(View v, ViewGroup parent) { Loading Loading @@ -1763,6 +2064,13 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { if (!hasLandscapeAndPortraitLayouts()) { dest.writeInt(MODE_NORMAL); // We only write the bitmap cache if we are the root RemoteViews, as this cache // is shared by all children. if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); } dest.writeString(mPackage); dest.writeInt(mLayoutId); dest.writeInt(mIsWidgetCollectionChild ? 1 : 0); Loading @@ -1777,6 +2085,16 @@ public class RemoteViews implements Parcelable, Filter { Action a = mActions.get(i); a.writeToParcel(dest, 0); } } else { dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT); // We only write the bitmap cache if we are the root RemoteViews, as this cache // is shared by all children. if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); } mLandscape.writeToParcel(dest, flags); mPortrait.writeToParcel(dest, flags); } } /** Loading core/java/android/widget/RemoteViewsAdapter.java +1 −5 Original line number Diff line number Diff line Loading @@ -595,7 +595,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback for (Integer i : mIndexRemoteViews.keySet()) { final RemoteViews v = mIndexRemoteViews.get(i); if (v != null) { mem += v.estimateBitmapMemoryUsage(); mem += v.estimateMemoryUsage(); } } return mem; Loading Loading @@ -942,10 +942,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * which wouldn't otherwise be possible. */ public void setVisibleRangeHint(int lowerBound, int upperBound) { if (lowerBound < 0 || upperBound < 0) { throw new RuntimeException("Attempted to set invalid range: lowerBound="+lowerBound + "," + "upperBound="+upperBound); } mVisibleWindowLowerBound = lowerBound; mVisibleWindowUpperBound = upperBound; } Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -27842,6 +27842,7 @@ package android.widget { public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable { ctor public RemoteViews(java.lang.String, int); ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews); ctor public RemoteViews(android.os.Parcel); method public void addView(int, android.widget.RemoteViews); method public android.view.View apply(android.content.Context, android.view.ViewGroup);
core/java/android/widget/RemoteViews.java +417 −99 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; Loading Loading @@ -87,6 +88,31 @@ public class RemoteViews implements Parcelable, Filter { */ private MemoryUsageCounter mMemoryUsageCounter; /** * Maps bitmaps to unique indicies to avoid Bitmap duplication. */ private BitmapCache mBitmapCache; /** * Indicates whether or not this RemoteViews object is contained as a child of any other * RemoteViews. */ private boolean mIsRoot = true; /** * Constants to whether or not this RemoteViews is composed of a landscape and portrait * RemoteViews. */ private static final int MODE_NORMAL = 0; private static final int MODE_HAS_LANDSCAPE_AND_PORTRAIT = 1; /** * Used in conjunction with the special constructor * {@link #RemoteViews(RemoteViews, RemoteViews)} to keep track of the landscape and portrait * RemoteViews. */ private RemoteViews mLandscape = null; private RemoteViews mPortrait = null; /** * This flag indicates whether this RemoteViews object is being created from a Loading Loading @@ -163,6 +189,10 @@ public class RemoteViews implements Parcelable, Filter { } return true; } public void setBitmapCache(BitmapCache bitmapCache) { // Do nothing } } private class SetEmptyView extends Action { Loading Loading @@ -643,6 +673,112 @@ public class RemoteViews implements Parcelable, Filter { } } private static class BitmapCache { ArrayList<Bitmap> mBitmaps; public BitmapCache() { mBitmaps = new ArrayList<Bitmap>(); } public BitmapCache(Parcel source) { int count = source.readInt(); mBitmaps = new ArrayList<Bitmap>(); for (int i = 0; i < count; i++) { Bitmap b = Bitmap.CREATOR.createFromParcel(source); mBitmaps.add(b); } } public int getBitmapId(Bitmap b) { if (b == null) { return -1; } else { if (mBitmaps.contains(b)) { return mBitmaps.indexOf(b); } else { mBitmaps.add(b); return (mBitmaps.size() - 1); } } } public Bitmap getBitmapForId(int id) { if (id == -1 || id >= mBitmaps.size()) { return null; } else { return mBitmaps.get(id); } } public void writeBitmapsToParcel(Parcel dest, int flags) { int count = mBitmaps.size(); dest.writeInt(count); for (int i = 0; i < count; i++) { mBitmaps.get(i).writeToParcel(dest, flags); } } public void assimilate(BitmapCache bitmapCache) { ArrayList<Bitmap> bitmapsToBeAdded = bitmapCache.mBitmaps; int count = bitmapsToBeAdded.size(); for (int i = 0; i < count; i++) { Bitmap b = bitmapsToBeAdded.get(i); if (!mBitmaps.contains(b)) { mBitmaps.add(b); } } } public void addBitmapMemory(MemoryUsageCounter memoryCounter) { for (int i = 0; i < mBitmaps.size(); i++) { memoryCounter.addBitmapMemory(mBitmaps.get(i)); } } } private class BitmapReflectionAction extends Action { int bitmapId; int viewId; Bitmap bitmap; String methodName; BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) { this.bitmap = bitmap; this.viewId = viewId; this.methodName = methodName; bitmapId = mBitmapCache.getBitmapId(bitmap); } BitmapReflectionAction(Parcel in) { viewId = in.readInt(); methodName = in.readString(); bitmapId = in.readInt(); bitmap = mBitmapCache.getBitmapForId(bitmapId); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(TAG); dest.writeInt(viewId); dest.writeString(methodName); dest.writeInt(bitmapId); } @Override public void apply(View root, ViewGroup rootParent) throws ActionException { ReflectionAction ra = new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, bitmap); ra.apply(root, rootParent); } @Override public void setBitmapCache(BitmapCache bitmapCache) { bitmapId = bitmapCache.getBitmapId(bitmap); } public final static int TAG = 12; } /** * Base class for the reflection actions. */ Loading Loading @@ -894,24 +1030,7 @@ public class RemoteViews implements Parcelable, Filter { case BITMAP: if (this.value != null) { final Bitmap b = (Bitmap) this.value; final Bitmap.Config c = b.getConfig(); // If we don't know, be pessimistic and assume 4 int bpp = 4; if (c != null) { switch (c) { case ALPHA_8: bpp = 1; break; case RGB_565: case ARGB_4444: bpp = 2; break; case ARGB_8888: bpp = 4; break; } } counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp); counter.addBitmapMemory(b); } break; default: Loading @@ -920,6 +1039,16 @@ public class RemoteViews implements Parcelable, Filter { } } private void configureRemoteViewsAsChild(RemoteViews rv) { mBitmapCache.assimilate(rv.mBitmapCache); rv.setBitmapCache(mBitmapCache); rv.setNotRoot(); } void setNotRoot() { mIsRoot = false; } /** * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()} Loading @@ -929,17 +1058,29 @@ public class RemoteViews implements Parcelable, Filter { public ViewGroupAction(int viewId, RemoteViews nestedViews) { this.viewId = viewId; this.nestedViews = nestedViews; configureRemoteViewsAsChild(nestedViews); } public ViewGroupAction(Parcel parcel) { public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) { viewId = parcel.readInt(); nestedViews = parcel.readParcelable(null); boolean nestedViewsNull = parcel.readInt() == 0; if (!nestedViewsNull) { nestedViews = new RemoteViews(parcel, bitmapCache); } else { nestedViews = null; } } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(TAG); dest.writeInt(viewId); dest.writeParcelable(nestedViews, 0 /* no flags */); if (nestedViews != null) { dest.writeInt(1); nestedViews.writeToParcel(dest, flags); } else { // signifies null dest.writeInt(0); } } @Override Loading @@ -959,7 +1100,14 @@ public class RemoteViews implements Parcelable, Filter { @Override public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { if (nestedViews != null) { counter.bitmapIncrement(nestedViews.estimateBitmapMemoryUsage()); counter.increment(nestedViews.estimateMemoryUsage()); } } @Override public void setBitmapCache(BitmapCache bitmapCache) { if (nestedViews != null) { nestedViews.setBitmapCache(bitmapCache); } } Loading Loading @@ -1027,18 +1175,39 @@ public class RemoteViews implements Parcelable, Filter { */ private class MemoryUsageCounter { public void clear() { mBitmapHeapMemoryUsage = 0; mMemoryUsage = 0; } public void bitmapIncrement(int numBytes) { mBitmapHeapMemoryUsage += numBytes; public void increment(int numBytes) { mMemoryUsage += numBytes; } public int getBitmapHeapMemoryUsage() { return mBitmapHeapMemoryUsage; public int getMemoryUsage() { return mMemoryUsage; } int mBitmapHeapMemoryUsage; public void addBitmapMemory(Bitmap b) { final Bitmap.Config c = b.getConfig(); // If we don't know, be pessimistic and assume 4 int bpp = 4; if (c != null) { switch (c) { case ALPHA_8: bpp = 1; break; case RGB_565: case ARGB_4444: bpp = 2; break; case ARGB_8888: bpp = 4; break; } } increment(b.getWidth() * b.getHeight() * bpp); } int mMemoryUsage; } /** Loading @@ -1051,9 +1220,44 @@ public class RemoteViews implements Parcelable, Filter { public RemoteViews(String packageName, int layoutId) { mPackage = packageName; mLayoutId = layoutId; mBitmapCache = new BitmapCache(); // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); recalculateMemoryUsage(); } private boolean hasLandscapeAndPortraitLayouts() { return (mLandscape != null) && (mPortrait != null); } /** * Create a new RemoteViews object that will inflate as the specified * landspace or portrait RemoteViews, depending on the current configuration. * * @param landscape The RemoteViews to inflate in landscape configuration * @param portrait The RemoteViews to inflate in portrait configuration */ public RemoteViews(RemoteViews landscape, RemoteViews portrait) { if (landscape == null || portrait == null) { throw new RuntimeException("Both RemoteViews must be non-null"); } if (landscape.getPackage().compareTo(portrait.getPackage()) != 0) { throw new RuntimeException("Both RemoteViews must share the same package"); } mPackage = portrait.getPackage(); mLayoutId = portrait.getLayoutId(); mLandscape = landscape; mPortrait = portrait; // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); mBitmapCache = new BitmapCache(); configureRemoteViewsAsChild(landscape); configureRemoteViewsAsChild(portrait); recalculateMemoryUsage(); } Loading @@ -1063,6 +1267,21 @@ public class RemoteViews implements Parcelable, Filter { * @param parcel */ public RemoteViews(Parcel parcel) { this(parcel, null); } private RemoteViews(Parcel parcel, BitmapCache bitmapCache) { int mode = parcel.readInt(); // We only store a bitmap cache in the root of the RemoteViews. if (bitmapCache == null) { mBitmapCache = new BitmapCache(parcel); } else { setBitmapCache(bitmapCache); setNotRoot(); } if (mode == MODE_NORMAL) { mPackage = parcel.readString(); mLayoutId = parcel.readInt(); mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false; Loading @@ -1083,7 +1302,7 @@ public class RemoteViews implements Parcelable, Filter { mActions.add(new ReflectionAction(parcel)); break; case ViewGroupAction.TAG: mActions.add(new ViewGroupAction(parcel)); mActions.add(new ViewGroupAction(parcel, mBitmapCache)); break; case ReflectionActionWithoutParams.TAG: mActions.add(new ReflectionActionWithoutParams(parcel)); Loading @@ -1103,11 +1322,21 @@ public class RemoteViews implements Parcelable, Filter { case TextViewDrawableAction.TAG: mActions.add(new TextViewDrawableAction(parcel)); break; case BitmapReflectionAction.TAG: mActions.add(new BitmapReflectionAction(parcel)); break; default: throw new ActionException("Tag " + tag + " not found"); } } } } else { // MODE_HAS_LANDSCAPE_AND_PORTRAIT mLandscape = new RemoteViews(parcel, mBitmapCache); mPortrait = new RemoteViews(parcel, mBitmapCache); mPackage = mPortrait.getPackage(); mLayoutId = mPortrait.getLayoutId(); } // setup the memory usage statistics mMemoryUsageCounter = new MemoryUsageCounter(); Loading @@ -1116,11 +1345,18 @@ public class RemoteViews implements Parcelable, Filter { @Override public RemoteViews clone() { final RemoteViews that = new RemoteViews(mPackage, mLayoutId); RemoteViews that; if (!hasLandscapeAndPortraitLayouts()) { that = new RemoteViews(mPackage, mLayoutId); if (mActions != null) { that.mActions = (ArrayList<Action>)mActions.clone(); } } else { RemoteViews land = mLandscape.clone(); RemoteViews port = mPortrait.clone(); that = new RemoteViews(land, port); } // update the memory usage stats of the cloned RemoteViews that.recalculateMemoryUsage(); return that; Loading @@ -1130,6 +1366,13 @@ public class RemoteViews implements Parcelable, Filter { return mPackage; } /** * Reutrns the layout id of the root layout associated with this RemoteViews. In the case * that the RemoteViews has both a landscape and portrait root, this will return the layout * id associated with the portrait layout. * * @return the layout id. */ public int getLayoutId() { return mLayoutId; } Loading @@ -1151,6 +1394,7 @@ public class RemoteViews implements Parcelable, Filter { private void recalculateMemoryUsage() { mMemoryUsageCounter.clear(); if (!hasLandscapeAndPortraitLayouts()) { // Accumulate the memory usage for each action if (mActions != null) { final int count = mActions.size(); Loading @@ -1158,13 +1402,39 @@ public class RemoteViews implements Parcelable, Filter { mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter); } } if (mIsRoot) { mBitmapCache.addBitmapMemory(mMemoryUsageCounter); } } else { mMemoryUsageCounter.increment(mLandscape.estimateMemoryUsage()); mMemoryUsageCounter.increment(mPortrait.estimateMemoryUsage()); mBitmapCache.addBitmapMemory(mMemoryUsageCounter); } } /** * Recursively sets BitmapCache in the hierarchy and update the bitmap ids. */ private void setBitmapCache(BitmapCache bitmapCache) { mBitmapCache = bitmapCache; if (!hasLandscapeAndPortraitLayouts()) { if (mActions != null) { final int count = mActions.size(); for (int i= 0; i < count; ++i) { mActions.get(i).setBitmapCache(bitmapCache); } } } else { mLandscape.setBitmapCache(bitmapCache); mPortrait.setBitmapCache(bitmapCache); } } /** * Returns an estimate of the bitmap heap memory usage for this RemoteViews. */ int estimateBitmapMemoryUsage() { return mMemoryUsageCounter.getBitmapHeapMemoryUsage(); int estimateMemoryUsage() { return mMemoryUsageCounter.getMemoryUsage(); } /** Loading @@ -1173,6 +1443,11 @@ public class RemoteViews implements Parcelable, Filter { * @param a The action to add */ private void addAction(Action a) { if (hasLandscapeAndPortraitLayouts()) { throw new RuntimeException("RemoteViews specifying separate landscape and portrait" + " layouts cannot be modified. Instead, fully configure the landscape and" + " portrait layouts individually before constructing the combined layout."); } if (mActions == null) { mActions = new ArrayList<Action>(); } Loading Loading @@ -1644,7 +1919,7 @@ public class RemoteViews implements Parcelable, Filter { * @param value The value to pass to the method. */ public void setBitmap(int viewId, String methodName, Bitmap value) { addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value)); addAction(new BitmapReflectionAction(viewId, methodName, value)); } /** Loading Loading @@ -1679,6 +1954,18 @@ public class RemoteViews implements Parcelable, Filter { setCharSequence(viewId, "setContentDescription", contentDescription); } private RemoteViews getRemoteViewsToApply(Context context) { if (hasLandscapeAndPortraitLayouts()) { int orientation = context.getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { return mLandscape; } else { return mPortrait; } } return this; } /** * Inflates the view hierarchy represented by this object and applies * all of the actions. Loading @@ -1691,6 +1978,8 @@ public class RemoteViews implements Parcelable, Filter { * @return The inflated view hierarchy */ public View apply(Context context, ViewGroup parent) { RemoteViews rvToApply = getRemoteViewsToApply(context); View result; Context c = prepareContext(context); Loading @@ -1701,9 +1990,9 @@ public class RemoteViews implements Parcelable, Filter { inflater = inflater.cloneInContext(c); inflater.setFilter(this); result = inflater.inflate(mLayoutId, parent, false); result = inflater.inflate(rvToApply.getLayoutId(), parent, false); performApply(result, parent); rvToApply.performApply(result, parent); return result; } Loading @@ -1717,8 +2006,20 @@ public class RemoteViews implements Parcelable, Filter { * the {@link #apply(Context,ViewGroup)} call. */ public void reapply(Context context, View v) { RemoteViews rvToApply = getRemoteViewsToApply(context); // In the case that a view has this RemoteViews applied in one orientation, is persisted // across orientation change, and has the RemoteViews re-applied in the new orientation, // we throw an exception, since the layouts may be completely unrelated. if (hasLandscapeAndPortraitLayouts()) { if (v.getId() != rvToApply.getLayoutId()) { throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + " that does not share the same root layout id."); } } prepareContext(context); performApply(v, (ViewGroup) v.getParent()); rvToApply.performApply(v, (ViewGroup) v.getParent()); } private void performApply(View v, ViewGroup parent) { Loading Loading @@ -1763,6 +2064,13 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { if (!hasLandscapeAndPortraitLayouts()) { dest.writeInt(MODE_NORMAL); // We only write the bitmap cache if we are the root RemoteViews, as this cache // is shared by all children. if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); } dest.writeString(mPackage); dest.writeInt(mLayoutId); dest.writeInt(mIsWidgetCollectionChild ? 1 : 0); Loading @@ -1777,6 +2085,16 @@ public class RemoteViews implements Parcelable, Filter { Action a = mActions.get(i); a.writeToParcel(dest, 0); } } else { dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT); // We only write the bitmap cache if we are the root RemoteViews, as this cache // is shared by all children. if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); } mLandscape.writeToParcel(dest, flags); mPortrait.writeToParcel(dest, flags); } } /** Loading
core/java/android/widget/RemoteViewsAdapter.java +1 −5 Original line number Diff line number Diff line Loading @@ -595,7 +595,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback for (Integer i : mIndexRemoteViews.keySet()) { final RemoteViews v = mIndexRemoteViews.get(i); if (v != null) { mem += v.estimateBitmapMemoryUsage(); mem += v.estimateMemoryUsage(); } } return mem; Loading Loading @@ -942,10 +942,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * which wouldn't otherwise be possible. */ public void setVisibleRangeHint(int lowerBound, int upperBound) { if (lowerBound < 0 || upperBound < 0) { throw new RuntimeException("Attempted to set invalid range: lowerBound="+lowerBound + "," + "upperBound="+upperBound); } mVisibleWindowLowerBound = lowerBound; mVisibleWindowUpperBound = upperBound; } Loading