Loading core/java/android/appwidget/AppWidgetManager.java +3 −4 Original line number Diff line number Diff line Loading @@ -436,10 +436,9 @@ public class AppWidgetManager { * * This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the * RemoteViews object which is passed is understood to be an incomplete representation of the * widget, and hence is not cached by the AppWidgetService. Note that because these updates are * not cached, any state that they modify that is not restored by restoreInstanceState will not * persist in the case that the widgets are restored using the cached version in * AppWidgetService. * widget, and hence does not replace the cached representation of the widget. As of API * level 17, the new properties set within the views objects will be appended to the cached * representation of the widget, and hence will persist. * * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)}, * {@link RemoteViews#setScrollPosition(int, int)} and similar commands. Loading core/java/android/widget/RemoteViews.java +134 −24 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; /** Loading Loading @@ -187,6 +188,10 @@ public class RemoteViews implements Parcelable, Filter { public abstract void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException; public static final int MERGE_REPLACE = 0; public static final int MERGE_APPEND = 1; public static final int MERGE_IGNORE = 2; public int describeContents() { return 0; } Loading @@ -203,6 +208,60 @@ public class RemoteViews implements Parcelable, Filter { public void setBitmapCache(BitmapCache bitmapCache) { // Do nothing } public int mergeBehavior() { return MERGE_REPLACE; } public abstract String getActionName(); public String getUniqueKey() { return (getActionName() + viewId); } int viewId; } public void mergeRemoteViews(RemoteViews newRv) { // We first copy the new RemoteViews, as the process of merging modifies the way the actions // reference the bitmap cache. We don't want to modify the object as it may need to // be merged and applied multiple times. Parcel p = Parcel.obtain(); newRv.writeToParcel(p, 0); RemoteViews copy = new RemoteViews(p); HashMap<String, Action> map = new HashMap<String, Action>(); if (mActions == null) { mActions = new ArrayList<Action>(); } int count = mActions.size(); for (int i = 0; i < count; i++) { Action a = mActions.get(i); map.put(a.getUniqueKey(), a); } ArrayList<Action> newActions = copy.mActions; if (newActions == null) return; count = newActions.size(); for (int i = 0; i < count; i++) { Action a = newActions.get(i); String key = newActions.get(i).getUniqueKey(); int mergeBehavior = map.get(key).mergeBehavior(); if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) { mActions.remove(map.get(key)); map.remove(key); } // If the merge behavior is ignore, we don't bother keeping the extra action if (mergeBehavior == Action.MERGE_REPLACE || mergeBehavior == Action.MERGE_APPEND) { mActions.add(a); } } // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache mBitmapCache = new BitmapCache(); setBitmapCache(mBitmapCache); } private class SetEmptyView extends Action { Loading Loading @@ -239,6 +298,10 @@ public class RemoteViews implements Parcelable, Filter { adapterView.setEmptyView(emptyView); } public String getActionName() { return "SetEmptyView"; } } private class SetOnClickFillInIntent extends Action { Loading Loading @@ -316,7 +379,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetOnClickFillInIntent"; } Intent fillInIntent; public final static int TAG = 9; Loading Loading @@ -399,7 +465,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetPendingIntentTemplate"; } PendingIntent pendingIntentTemplate; public final static int TAG = 8; Loading Loading @@ -453,7 +522,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetRemoteViewsAdapterIntent"; } Intent intent; public final static int TAG = 10; Loading Loading @@ -539,7 +611,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetOnClickPendingIntent"; } PendingIntent pendingIntent; public final static int TAG = 1; Loading Loading @@ -625,7 +700,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetDrawableParameters"; } boolean targetBackground; int alpha; int colorFilter; Loading @@ -636,7 +714,6 @@ public class RemoteViews implements Parcelable, Filter { } private class ReflectionActionWithoutParams extends Action { int viewId; String methodName; public final static int TAG = 5; Loading Loading @@ -688,6 +765,19 @@ public class RemoteViews implements Parcelable, Filter { throw new ActionException(ex); } } public int mergeBehavior() { // we don't need to build up showNext or showPrevious calls if (methodName.equals("showNext") || methodName.equals("showPrevious")) { return MERGE_IGNORE; } else { return MERGE_REPLACE; } } public String getActionName() { return "ReflectionActionWithoutParams"; } } private static class BitmapCache { Loading Loading @@ -755,7 +845,6 @@ public class RemoteViews implements Parcelable, Filter { private class BitmapReflectionAction extends Action { int bitmapId; int viewId; Bitmap bitmap; String methodName; Loading Loading @@ -794,6 +883,10 @@ public class RemoteViews implements Parcelable, Filter { bitmapId = bitmapCache.getBitmapId(bitmap); } public String getActionName() { return "BitmapReflectionAction"; } public final static int TAG = 12; } Loading @@ -814,11 +907,12 @@ public class RemoteViews implements Parcelable, Filter { static final int STRING = 9; static final int CHAR_SEQUENCE = 10; static final int URI = 11; // BITMAP actions are never stored in the list of actions. They are only used locally // to implement BitmapReflectionAction, which eliminates duplicates using BitmapCache. static final int BITMAP = 12; static final int BUNDLE = 13; static final int INTENT = 14; int viewId; String methodName; int type; Object value; Loading Loading @@ -1041,19 +1135,19 @@ public class RemoteViews implements Parcelable, Filter { } } @Override public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { // We currently only calculate Bitmap memory usage switch (this.type) { case BITMAP: if (this.value != null) { final Bitmap b = (Bitmap) this.value; counter.addBitmapMemory(b); public int mergeBehavior() { // smoothScrollBy is cumulative, everything else overwites. if (methodName.equals("smoothScrollBy")) { return MERGE_APPEND; } else { return MERGE_REPLACE; } break; default: break; } public String getActionName() { // Each type of reflection action corresponds to a setter, so each should be seen as // unique from the standpoint of merging. return "ReflectionAction" + this.methodName + this.type; } } Loading Loading @@ -1131,7 +1225,14 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add"; } public int mergeBehavior() { return MERGE_APPEND; } RemoteViews nestedViews; public final static int TAG = 4; Loading Loading @@ -1182,7 +1283,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "TextViewDrawableAction"; } boolean isRelative = false; int d1, d2, d3, d4; Loading Loading @@ -1220,7 +1324,10 @@ public class RemoteViews implements Parcelable, Filter { target.setTextSize(units, size); } int viewId; public String getActionName() { return "TextViewSizeAction"; } int units; float size; Loading Loading @@ -1264,7 +1371,10 @@ public class RemoteViews implements Parcelable, Filter { target.setPadding(left, top, right, bottom); } int viewId; public String getActionName() { return "ViewPaddingAction"; } int left, top, right, bottom; public final static int TAG = 14; Loading services/java/com/android/server/AppWidgetServiceImpl.java +6 −2 Original line number Diff line number Diff line Loading @@ -980,9 +980,13 @@ class AppWidgetServiceImpl { // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { // We do not want to save this RemoteViews if (!isPartialUpdate) if (!isPartialUpdate) { // For a full update we replace the RemoteViews completely. id.views = views; } else { // For a partial update, we merge the new RemoteViews with the old. id.views.mergeRemoteViews(views); } // is anyone listening? if (id.host.callbacks != null) { Loading Loading
core/java/android/appwidget/AppWidgetManager.java +3 −4 Original line number Diff line number Diff line Loading @@ -436,10 +436,9 @@ public class AppWidgetManager { * * This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the * RemoteViews object which is passed is understood to be an incomplete representation of the * widget, and hence is not cached by the AppWidgetService. Note that because these updates are * not cached, any state that they modify that is not restored by restoreInstanceState will not * persist in the case that the widgets are restored using the cached version in * AppWidgetService. * widget, and hence does not replace the cached representation of the widget. As of API * level 17, the new properties set within the views objects will be appended to the cached * representation of the widget, and hence will persist. * * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)}, * {@link RemoteViews#setScrollPosition(int, int)} and similar commands. Loading
core/java/android/widget/RemoteViews.java +134 −24 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; /** Loading Loading @@ -187,6 +188,10 @@ public class RemoteViews implements Parcelable, Filter { public abstract void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException; public static final int MERGE_REPLACE = 0; public static final int MERGE_APPEND = 1; public static final int MERGE_IGNORE = 2; public int describeContents() { return 0; } Loading @@ -203,6 +208,60 @@ public class RemoteViews implements Parcelable, Filter { public void setBitmapCache(BitmapCache bitmapCache) { // Do nothing } public int mergeBehavior() { return MERGE_REPLACE; } public abstract String getActionName(); public String getUniqueKey() { return (getActionName() + viewId); } int viewId; } public void mergeRemoteViews(RemoteViews newRv) { // We first copy the new RemoteViews, as the process of merging modifies the way the actions // reference the bitmap cache. We don't want to modify the object as it may need to // be merged and applied multiple times. Parcel p = Parcel.obtain(); newRv.writeToParcel(p, 0); RemoteViews copy = new RemoteViews(p); HashMap<String, Action> map = new HashMap<String, Action>(); if (mActions == null) { mActions = new ArrayList<Action>(); } int count = mActions.size(); for (int i = 0; i < count; i++) { Action a = mActions.get(i); map.put(a.getUniqueKey(), a); } ArrayList<Action> newActions = copy.mActions; if (newActions == null) return; count = newActions.size(); for (int i = 0; i < count; i++) { Action a = newActions.get(i); String key = newActions.get(i).getUniqueKey(); int mergeBehavior = map.get(key).mergeBehavior(); if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) { mActions.remove(map.get(key)); map.remove(key); } // If the merge behavior is ignore, we don't bother keeping the extra action if (mergeBehavior == Action.MERGE_REPLACE || mergeBehavior == Action.MERGE_APPEND) { mActions.add(a); } } // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache mBitmapCache = new BitmapCache(); setBitmapCache(mBitmapCache); } private class SetEmptyView extends Action { Loading Loading @@ -239,6 +298,10 @@ public class RemoteViews implements Parcelable, Filter { adapterView.setEmptyView(emptyView); } public String getActionName() { return "SetEmptyView"; } } private class SetOnClickFillInIntent extends Action { Loading Loading @@ -316,7 +379,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetOnClickFillInIntent"; } Intent fillInIntent; public final static int TAG = 9; Loading Loading @@ -399,7 +465,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetPendingIntentTemplate"; } PendingIntent pendingIntentTemplate; public final static int TAG = 8; Loading Loading @@ -453,7 +522,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetRemoteViewsAdapterIntent"; } Intent intent; public final static int TAG = 10; Loading Loading @@ -539,7 +611,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetOnClickPendingIntent"; } PendingIntent pendingIntent; public final static int TAG = 1; Loading Loading @@ -625,7 +700,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "SetDrawableParameters"; } boolean targetBackground; int alpha; int colorFilter; Loading @@ -636,7 +714,6 @@ public class RemoteViews implements Parcelable, Filter { } private class ReflectionActionWithoutParams extends Action { int viewId; String methodName; public final static int TAG = 5; Loading Loading @@ -688,6 +765,19 @@ public class RemoteViews implements Parcelable, Filter { throw new ActionException(ex); } } public int mergeBehavior() { // we don't need to build up showNext or showPrevious calls if (methodName.equals("showNext") || methodName.equals("showPrevious")) { return MERGE_IGNORE; } else { return MERGE_REPLACE; } } public String getActionName() { return "ReflectionActionWithoutParams"; } } private static class BitmapCache { Loading Loading @@ -755,7 +845,6 @@ public class RemoteViews implements Parcelable, Filter { private class BitmapReflectionAction extends Action { int bitmapId; int viewId; Bitmap bitmap; String methodName; Loading Loading @@ -794,6 +883,10 @@ public class RemoteViews implements Parcelable, Filter { bitmapId = bitmapCache.getBitmapId(bitmap); } public String getActionName() { return "BitmapReflectionAction"; } public final static int TAG = 12; } Loading @@ -814,11 +907,12 @@ public class RemoteViews implements Parcelable, Filter { static final int STRING = 9; static final int CHAR_SEQUENCE = 10; static final int URI = 11; // BITMAP actions are never stored in the list of actions. They are only used locally // to implement BitmapReflectionAction, which eliminates duplicates using BitmapCache. static final int BITMAP = 12; static final int BUNDLE = 13; static final int INTENT = 14; int viewId; String methodName; int type; Object value; Loading Loading @@ -1041,19 +1135,19 @@ public class RemoteViews implements Parcelable, Filter { } } @Override public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { // We currently only calculate Bitmap memory usage switch (this.type) { case BITMAP: if (this.value != null) { final Bitmap b = (Bitmap) this.value; counter.addBitmapMemory(b); public int mergeBehavior() { // smoothScrollBy is cumulative, everything else overwites. if (methodName.equals("smoothScrollBy")) { return MERGE_APPEND; } else { return MERGE_REPLACE; } break; default: break; } public String getActionName() { // Each type of reflection action corresponds to a setter, so each should be seen as // unique from the standpoint of merging. return "ReflectionAction" + this.methodName + this.type; } } Loading Loading @@ -1131,7 +1225,14 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add"; } public int mergeBehavior() { return MERGE_APPEND; } RemoteViews nestedViews; public final static int TAG = 4; Loading Loading @@ -1182,7 +1283,10 @@ public class RemoteViews implements Parcelable, Filter { } } int viewId; public String getActionName() { return "TextViewDrawableAction"; } boolean isRelative = false; int d1, d2, d3, d4; Loading Loading @@ -1220,7 +1324,10 @@ public class RemoteViews implements Parcelable, Filter { target.setTextSize(units, size); } int viewId; public String getActionName() { return "TextViewSizeAction"; } int units; float size; Loading Loading @@ -1264,7 +1371,10 @@ public class RemoteViews implements Parcelable, Filter { target.setPadding(left, top, right, bottom); } int viewId; public String getActionName() { return "ViewPaddingAction"; } int left, top, right, bottom; public final static int TAG = 14; Loading
services/java/com/android/server/AppWidgetServiceImpl.java +6 −2 Original line number Diff line number Diff line Loading @@ -980,9 +980,13 @@ class AppWidgetServiceImpl { // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { // We do not want to save this RemoteViews if (!isPartialUpdate) if (!isPartialUpdate) { // For a full update we replace the RemoteViews completely. id.views = views; } else { // For a partial update, we merge the new RemoteViews with the old. id.views.mergeRemoteViews(views); } // is anyone listening? if (id.host.callbacks != null) { Loading