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 */
16package android.databinding;
17
18import android.support.v4.util.Pools;
19
20/**
21 * Utility class for managing ObservableList callbacks.
22 */
23public class ListChangeRegistry
24        extends
25        CallbackRegistry<ObservableList.OnListChangedCallback, ObservableList,
26                ListChangeRegistry.ListChanges> {
27    private static final Pools.SynchronizedPool<ListChanges> sListChanges =
28            new Pools.SynchronizedPool<ListChanges>(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     */
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     */
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     */
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     */
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     */
116    public void notifyRemoved(ObservableList list, int start, int count) {
117        ListChanges listChanges = acquire(start, 0, count);
118        notifyCallbacks(list, REMOVED, listChanges);
119    }
120
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
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
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