1 /* 2 * Copyright (C) 2020 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 17 package androidx.constraintlayout.widget; 18 19 import android.util.SparseIntArray; 20 21 import java.lang.ref.WeakReference; 22 import java.util.ArrayList; 23 import java.util.HashMap; 24 import java.util.HashSet; 25 import java.util.List; 26 27 /** 28 * Shared values 29 */ 30 public class SharedValues { 31 public static final int UNSET = -1; 32 33 private SparseIntArray mValues = new SparseIntArray(); 34 private HashMap<Integer, HashSet<WeakReference<SharedValuesListener>>> mValuesListeners = 35 new HashMap<>(); 36 37 /** 38 * interface for listeners 39 */ 40 public interface SharedValuesListener { 41 // @TODO: add description 42 43 /** 44 * 45 * @param key 46 * @param newValue 47 * @param oldValue 48 */ onNewValue(int key, int newValue, int oldValue)49 void onNewValue(int key, int newValue, int oldValue); 50 } 51 52 /** 53 * Add a listener for a key 54 * @param key 55 * @param listener 56 */ addListener(int key, SharedValuesListener listener)57 public void addListener(int key, SharedValuesListener listener) { 58 HashSet<WeakReference<SharedValuesListener>> listeners = mValuesListeners.get(key); 59 if (listeners == null) { 60 listeners = new HashSet<>(); 61 mValuesListeners.put(key, listeners); 62 } 63 listeners.add(new WeakReference<>(listener)); 64 } 65 66 /** 67 * Remove listener for a key (will not be removed for other keys) 68 * @param key 69 * @param listener 70 */ removeListener(int key, SharedValuesListener listener)71 public void removeListener(int key, SharedValuesListener listener) { 72 HashSet<WeakReference<SharedValuesListener>> listeners = mValuesListeners.get(key); 73 if (listeners == null) { 74 return; 75 } 76 List<WeakReference<SharedValuesListener>> toRemove = new ArrayList<>(); 77 for (WeakReference<SharedValuesListener> listenerWeakReference : listeners) { 78 SharedValuesListener l = listenerWeakReference.get(); 79 if (l == null || l == listener) { 80 toRemove.add(listenerWeakReference); 81 } 82 } 83 listeners.removeAll(toRemove); 84 } 85 86 /** 87 * Remove a listener 88 * @param listener 89 */ removeListener(SharedValuesListener listener)90 public void removeListener(SharedValuesListener listener) { 91 for (Integer key : mValuesListeners.keySet()) { 92 removeListener(key, listener); 93 } 94 } 95 96 /** 97 * remove all listeners 98 */ clearListeners()99 public void clearListeners() { 100 mValuesListeners.clear(); 101 } 102 103 /** 104 * get the value from the map 105 * @param key 106 * @return 107 */ getValue(int key)108 public int getValue(int key) { 109 return mValues.get(key, UNSET); 110 } 111 112 /** 113 * notify that value has changed 114 * @param key 115 * @param value 116 */ fireNewValue(int key, int value)117 public void fireNewValue(int key, int value) { 118 boolean needsCleanup = false; 119 int previousValue = mValues.get(key, UNSET); 120 if (previousValue == value) { 121 // don't send the value to listeners if it's the same one. 122 return; 123 } 124 mValues.put(key, value); 125 HashSet<WeakReference<SharedValuesListener>> listeners = mValuesListeners.get(key); 126 if (listeners == null) { 127 return; 128 } 129 130 for (WeakReference<SharedValuesListener> listenerWeakReference : listeners) { 131 SharedValuesListener l = listenerWeakReference.get(); 132 if (l != null) { 133 l.onNewValue(key, value, previousValue); 134 } else { 135 needsCleanup = true; 136 } 137 } 138 139 if (needsCleanup) { 140 List<WeakReference<SharedValuesListener>> toRemove = new ArrayList<>(); 141 for (WeakReference<SharedValuesListener> listenerWeakReference : listeners) { 142 SharedValuesListener listener = listenerWeakReference.get(); 143 if (listener == null) { 144 toRemove.add(listenerWeakReference); 145 } 146 } 147 listeners.removeAll(toRemove); 148 } 149 } 150 } 151