1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.databinding;
17 
18 import android.support.v4.util.Pools;
19 
20 /**
21  * Utility class for managing ObservableList callbacks.
22  */
23 public class ListChangeRegistry
24         extends
25         CallbackRegistry<ObservableList.OnListChangedCallback, ObservableList,
26                 ListChangeRegistry.ListChanges> {
27     private static final Pools.SynchronizedPool<ListChanges> sListChanges =
28             new Pools.SynchronizedPool<>(10);
29 
30     private static final int ALL = 0;
31     private static final int CHANGED = 1;
32     private static final int INSERTED = 2;
33     private static final int MOVED = 3;
34     private static final int REMOVED = 4;
35 
36     private static final CallbackRegistry.NotifierCallback<ObservableList.OnListChangedCallback,
37             ObservableList, ListChanges> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<
38             ObservableList.OnListChangedCallback, ObservableList, ListChanges>() {
39         @Override
40         public void onNotifyCallback(ObservableList.OnListChangedCallback callback,
41                 ObservableList sender, int notificationType, ListChanges listChanges) {
42             switch (notificationType) {
43                 case CHANGED:
44                     callback.onItemRangeChanged(sender, listChanges.start, listChanges.count);
45                     break;
46                 case INSERTED:
47                     callback.onItemRangeInserted(sender, listChanges.start, listChanges.count);
48                     break;
49                 case MOVED:
50                     callback.onItemRangeMoved(sender, listChanges.start, listChanges.to,
51                             listChanges.count);
52                     break;
53                 case REMOVED:
54                     callback.onItemRangeRemoved(sender, listChanges.start, listChanges.count);
55                     break;
56                 default:
57                     callback.onChanged(sender);
58                     break;
59             }
60         }
61     };
62 
63     /**
64      * Notify registered callbacks that there was an unknown or whole-list change.
65      *
66      * @param list The list that changed.
67      */
notifyChanged(ObservableList list)68     public void notifyChanged(ObservableList list) {
69         notifyCallbacks(list, ALL, null);
70     }
71 
72     /**
73      * Notify registered callbacks that some elements have changed.
74      *
75      * @param list The list that changed.
76      * @param start The index of the first changed element.
77      * @param count The number of changed elements.
78      */
notifyChanged(ObservableList list, int start, int count)79     public void notifyChanged(ObservableList list, int start, int count) {
80         ListChanges listChanges = acquire(start, 0, count);
81         notifyCallbacks(list, CHANGED, listChanges);
82     }
83 
84     /**
85      * Notify registered callbacks that elements were inserted.
86      *
87      * @param list The list that changed.
88      * @param start The index where the elements were inserted.
89      * @param count The number of elements that were inserted.
90      */
notifyInserted(ObservableList list, int start, int count)91     public void notifyInserted(ObservableList list, int start, int count) {
92         ListChanges listChanges = acquire(start, 0, count);
93         notifyCallbacks(list, INSERTED, listChanges);
94     }
95 
96     /**
97      * Notify registered callbacks that elements were moved.
98      *
99      * @param list The list that changed.
100      * @param from The index of the first element moved.
101      * @param to The index of where the element was moved to.
102      * @param count The number of elements moved.
103      */
notifyMoved(ObservableList list, int from, int to, int count)104     public void notifyMoved(ObservableList list, int from, int to, int count) {
105         ListChanges listChanges = acquire(from, to, count);
106         notifyCallbacks(list, MOVED, listChanges);
107     }
108 
109     /**
110      * Notify registered callbacks that elements were deleted.
111      *
112      * @param list The list that changed.
113      * @param start The index of the first element to be removed.
114      * @param count The number of elements removed.
115      */
notifyRemoved(ObservableList list, int start, int count)116     public void notifyRemoved(ObservableList list, int start, int count) {
117         ListChanges listChanges = acquire(start, 0, count);
118         notifyCallbacks(list, REMOVED, listChanges);
119     }
120 
acquire(int start, int to, int count)121     private static ListChanges acquire(int start, int to, int count) {
122         ListChanges listChanges = sListChanges.acquire();
123         if (listChanges == null) {
124             listChanges = new ListChanges();
125         }
126         listChanges.start = start;
127         listChanges.to = to;
128         listChanges.count = count;
129         return listChanges;
130     }
131 
132     @Override
notifyCallbacks(ObservableList sender, int notificationType, ListChanges listChanges)133     public synchronized void notifyCallbacks(ObservableList sender, int notificationType,
134             ListChanges listChanges) {
135         super.notifyCallbacks(sender, notificationType, listChanges);
136         if (listChanges != null) {
137             sListChanges.release(listChanges);
138         }
139     }
140 
ListChangeRegistry()141     public ListChangeRegistry() {
142         super(NOTIFIER_CALLBACK);
143     }
144 
145     static class ListChanges {
146         public int start;
147         public int count;
148         public int to;
149     }
150 }
151