Merge "Fixing partiallyUpdateAppWidget to cache the new changes" into jb-mr1-dev

This commit is contained in:
Adam Cohen
2012-09-20 18:09:11 -07:00
committed by Android (Google) Code Review
3 changed files with 143 additions and 30 deletions

View File

@@ -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.

View File

@@ -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;
/**
@@ -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;
}
@@ -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 {
@@ -239,6 +298,10 @@ public class RemoteViews implements Parcelable, Filter {
adapterView.setEmptyView(emptyView);
}
public String getActionName() {
return "SetEmptyView";
}
}
private class SetOnClickFillInIntent extends Action {
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -625,7 +700,10 @@ public class RemoteViews implements Parcelable, Filter {
}
}
int viewId;
public String getActionName() {
return "SetDrawableParameters";
}
boolean targetBackground;
int alpha;
int colorFilter;
@@ -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;
@@ -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 {
@@ -755,7 +845,6 @@ public class RemoteViews implements Parcelable, Filter {
private class BitmapReflectionAction extends Action {
int bitmapId;
int viewId;
Bitmap bitmap;
String methodName;
@@ -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;
}
@@ -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;
@@ -1041,20 +1135,20 @@ 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);
}
break;
default:
break;
public int mergeBehavior() {
// smoothScrollBy is cumulative, everything else overwites.
if (methodName.equals("smoothScrollBy")) {
return MERGE_APPEND;
} else {
return MERGE_REPLACE;
}
}
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;
}
}
private void configureRemoteViewsAsChild(RemoteViews rv) {
@@ -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;
@@ -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;
@@ -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;
@@ -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;

View File

@@ -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) {