5252import java .lang .annotation .Target ;
5353import java .lang .reflect .Method ;
5454import 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 ;
0 commit comments