Skip to content

Commit 11a6450

Browse files
Adam CohenAndroid (Google) Code Review
authored andcommitted
Merge "Fixing partiallyUpdateAppWidget to cache the new changes" into jb-mr1-dev
2 parents 957fadc + fbe44b7 commit 11a6450

File tree

3 files changed

+143
-30
lines changed

3 files changed

+143
-30
lines changed

core/java/android/appwidget/AppWidgetManager.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,10 +436,9 @@ public void updateAppWidget(int appWidgetId, RemoteViews views) {
436436
*
437437
* This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
438438
* RemoteViews object which is passed is understood to be an incomplete representation of the
439-
* widget, and hence is not cached by the AppWidgetService. Note that because these updates are
440-
* not cached, any state that they modify that is not restored by restoreInstanceState will not
441-
* persist in the case that the widgets are restored using the cached version in
442-
* AppWidgetService.
439+
* widget, and hence does not replace the cached representation of the widget. As of API
440+
* level 17, the new properties set within the views objects will be appended to the cached
441+
* representation of the widget, and hence will persist.
443442
*
444443
* Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
445444
* {@link RemoteViews#setScrollPosition(int, int)} and similar commands.

core/java/android/widget/RemoteViews.java

Lines changed: 134 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.lang.annotation.Target;
5353
import java.lang.reflect.Method;
5454
import java.util.ArrayList;
55+
import java.util.HashMap;
5556

5657

5758
/**
@@ -187,6 +188,10 @@ private abstract static class Action implements Parcelable {
187188
public abstract void apply(View root, ViewGroup rootParent,
188189
OnClickHandler handler) throws ActionException;
189190

191+
public static final int MERGE_REPLACE = 0;
192+
public static final int MERGE_APPEND = 1;
193+
public static final int MERGE_IGNORE = 2;
194+
190195
public int describeContents() {
191196
return 0;
192197
}
@@ -203,6 +208,60 @@ public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
203208
public void setBitmapCache(BitmapCache bitmapCache) {
204209
// Do nothing
205210
}
211+
212+
public int mergeBehavior() {
213+
return MERGE_REPLACE;
214+
}
215+
216+
public abstract String getActionName();
217+
218+
public String getUniqueKey() {
219+
return (getActionName() + viewId);
220+
}
221+
222+
int viewId;
223+
}
224+
225+
public void mergeRemoteViews(RemoteViews newRv) {
226+
// We first copy the new RemoteViews, as the process of merging modifies the way the actions
227+
// reference the bitmap cache. We don't want to modify the object as it may need to
228+
// be merged and applied multiple times.
229+
Parcel p = Parcel.obtain();
230+
newRv.writeToParcel(p, 0);
231+
RemoteViews copy = new RemoteViews(p);
232+
233+
HashMap<String, Action> map = new HashMap<String, Action>();
234+
if (mActions == null) {
235+
mActions = new ArrayList<Action>();
236+
}
237+
238+
int count = mActions.size();
239+
for (int i = 0; i < count; i++) {
240+
Action a = mActions.get(i);
241+
map.put(a.getUniqueKey(), a);
242+
}
243+
244+
ArrayList<Action> newActions = copy.mActions;
245+
if (newActions == null) return;
246+
count = newActions.size();
247+
for (int i = 0; i < count; i++) {
248+
Action a = newActions.get(i);
249+
String key = newActions.get(i).getUniqueKey();
250+
int mergeBehavior = map.get(key).mergeBehavior();
251+
if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) {
252+
mActions.remove(map.get(key));
253+
map.remove(key);
254+
}
255+
256+
// If the merge behavior is ignore, we don't bother keeping the extra action
257+
if (mergeBehavior == Action.MERGE_REPLACE || mergeBehavior == Action.MERGE_APPEND) {
258+
mActions.add(a);
259+
}
260+
}
261+
262+
// Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache
263+
mBitmapCache = new BitmapCache();
264+
setBitmapCache(mBitmapCache);
206265
}
207266

208267
private class SetEmptyView extends Action {
@@ -239,6 +298,10 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
239298

240299
adapterView.setEmptyView(emptyView);
241300
}
301+
302+
public String getActionName() {
303+
return "SetEmptyView";
304+
}
242305
}
243306

244307
private class SetOnClickFillInIntent extends Action {
@@ -316,7 +379,10 @@ public void onClick(View v) {
316379
}
317380
}
318381

319-
int viewId;
382+
public String getActionName() {
383+
return "SetOnClickFillInIntent";
384+
}
385+
320386
Intent fillInIntent;
321387

322388
public final static int TAG = 9;
@@ -399,7 +465,10 @@ public void onItemClick(AdapterView<?> parent, View view,
399465
}
400466
}
401467

402-
int viewId;
468+
public String getActionName() {
469+
return "SetPendingIntentTemplate";
470+
}
471+
403472
PendingIntent pendingIntentTemplate;
404473

405474
public final static int TAG = 8;
@@ -453,7 +522,10 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
453522
}
454523
}
455524

456-
int viewId;
525+
public String getActionName() {
526+
return "SetRemoteViewsAdapterIntent";
527+
}
528+
457529
Intent intent;
458530

459531
public final static int TAG = 10;
@@ -539,7 +611,10 @@ public void onClick(View v) {
539611
}
540612
}
541613

542-
int viewId;
614+
public String getActionName() {
615+
return "SetOnClickPendingIntent";
616+
}
617+
543618
PendingIntent pendingIntent;
544619

545620
public final static int TAG = 1;
@@ -625,7 +700,10 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
625700
}
626701
}
627702

628-
int viewId;
703+
public String getActionName() {
704+
return "SetDrawableParameters";
705+
}
706+
629707
boolean targetBackground;
630708
int alpha;
631709
int colorFilter;
@@ -636,7 +714,6 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
636714
}
637715

638716
private class ReflectionActionWithoutParams extends Action {
639-
int viewId;
640717
String methodName;
641718

642719
public final static int TAG = 5;
@@ -688,6 +765,19 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
688765
throw new ActionException(ex);
689766
}
690767
}
768+
769+
public int mergeBehavior() {
770+
// we don't need to build up showNext or showPrevious calls
771+
if (methodName.equals("showNext") || methodName.equals("showPrevious")) {
772+
return MERGE_IGNORE;
773+
} else {
774+
return MERGE_REPLACE;
775+
}
776+
}
777+
778+
public String getActionName() {
779+
return "ReflectionActionWithoutParams";
780+
}
691781
}
692782

693783
private static class BitmapCache {
@@ -755,7 +845,6 @@ public void addBitmapMemory(MemoryUsageCounter memoryCounter) {
755845

756846
private class BitmapReflectionAction extends Action {
757847
int bitmapId;
758-
int viewId;
759848
Bitmap bitmap;
760849
String methodName;
761850

@@ -794,6 +883,10 @@ public void setBitmapCache(BitmapCache bitmapCache) {
794883
bitmapId = bitmapCache.getBitmapId(bitmap);
795884
}
796885

886+
public String getActionName() {
887+
return "BitmapReflectionAction";
888+
}
889+
797890
public final static int TAG = 12;
798891
}
799892

@@ -814,11 +907,12 @@ private class ReflectionAction extends Action {
814907
static final int STRING = 9;
815908
static final int CHAR_SEQUENCE = 10;
816909
static final int URI = 11;
910+
// BITMAP actions are never stored in the list of actions. They are only used locally
911+
// to implement BitmapReflectionAction, which eliminates duplicates using BitmapCache.
817912
static final int BITMAP = 12;
818913
static final int BUNDLE = 13;
819914
static final int INTENT = 14;
820915

821-
int viewId;
822916
String methodName;
823917
int type;
824918
Object value;
@@ -1041,20 +1135,20 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
10411135
}
10421136
}
10431137

1044-
@Override
1045-
public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
1046-
// We currently only calculate Bitmap memory usage
1047-
switch (this.type) {
1048-
case BITMAP:
1049-
if (this.value != null) {
1050-
final Bitmap b = (Bitmap) this.value;
1051-
counter.addBitmapMemory(b);
1052-
}
1053-
break;
1054-
default:
1055-
break;
1138+
public int mergeBehavior() {
1139+
// smoothScrollBy is cumulative, everything else overwites.
1140+
if (methodName.equals("smoothScrollBy")) {
1141+
return MERGE_APPEND;
1142+
} else {
1143+
return MERGE_REPLACE;
10561144
}
10571145
}
1146+
1147+
public String getActionName() {
1148+
// Each type of reflection action corresponds to a setter, so each should be seen as
1149+
// unique from the standpoint of merging.
1150+
return "ReflectionAction" + this.methodName + this.type;
1151+
}
10581152
}
10591153

10601154
private void configureRemoteViewsAsChild(RemoteViews rv) {
@@ -1131,7 +1225,14 @@ public void setBitmapCache(BitmapCache bitmapCache) {
11311225
}
11321226
}
11331227

1134-
int viewId;
1228+
public String getActionName() {
1229+
return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add";
1230+
}
1231+
1232+
public int mergeBehavior() {
1233+
return MERGE_APPEND;
1234+
}
1235+
11351236
RemoteViews nestedViews;
11361237

11371238
public final static int TAG = 4;
@@ -1182,7 +1283,10 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
11821283
}
11831284
}
11841285

1185-
int viewId;
1286+
public String getActionName() {
1287+
return "TextViewDrawableAction";
1288+
}
1289+
11861290
boolean isRelative = false;
11871291
int d1, d2, d3, d4;
11881292

@@ -1220,7 +1324,10 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
12201324
target.setTextSize(units, size);
12211325
}
12221326

1223-
int viewId;
1327+
public String getActionName() {
1328+
return "TextViewSizeAction";
1329+
}
1330+
12241331
int units;
12251332
float size;
12261333

@@ -1264,7 +1371,10 @@ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
12641371
target.setPadding(left, top, right, bottom);
12651372
}
12661373

1267-
int viewId;
1374+
public String getActionName() {
1375+
return "ViewPaddingAction";
1376+
}
1377+
12681378
int left, top, right, bottom;
12691379

12701380
public final static int TAG = 14;

services/java/com/android/server/AppWidgetServiceImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -980,9 +980,13 @@ void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean is
980980
// drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
981981
if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
982982

983-
// We do not want to save this RemoteViews
984-
if (!isPartialUpdate)
983+
if (!isPartialUpdate) {
984+
// For a full update we replace the RemoteViews completely.
985985
id.views = views;
986+
} else {
987+
// For a partial update, we merge the new RemoteViews with the old.
988+
id.views.mergeRemoteViews(views);
989+
}
986990

987991
// is anyone listening?
988992
if (id.host.callbacks != null) {

0 commit comments

Comments
 (0)