1 /* 2 * Copyright (C) 2019 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 android.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.TestApi; 22 23 import java.util.function.Consumer; 24 25 /** 26 * A sparse array of ArrayMaps, which is suitable for holding (userId, packageName)->object 27 * associations. 28 * 29 * @param <T> Any class 30 * @hide 31 */ 32 @TestApi 33 public class SparseArrayMap<T> { 34 private final SparseArray<ArrayMap<String, T>> mData = new SparseArray<>(); 35 36 /** Add an entry associating obj with the int-String pair. */ add(int key, @NonNull String mapKey, @Nullable T obj)37 public void add(int key, @NonNull String mapKey, @Nullable T obj) { 38 ArrayMap<String, T> data = mData.get(key); 39 if (data == null) { 40 data = new ArrayMap<>(); 41 mData.put(key, data); 42 } 43 data.put(mapKey, obj); 44 } 45 46 /** Remove all entries from the map. */ clear()47 public void clear() { 48 for (int i = 0; i < mData.size(); ++i) { 49 mData.valueAt(i).clear(); 50 } 51 } 52 53 /** Return true if the structure contains an explicit entry for the int-String pair. */ contains(int key, @NonNull String mapKey)54 public boolean contains(int key, @NonNull String mapKey) { 55 return mData.contains(key) && mData.get(key).containsKey(mapKey); 56 } 57 58 /** Removes all the data for the key, if there was any. */ delete(int key)59 public void delete(int key) { 60 mData.delete(key); 61 } 62 63 /** 64 * Removes the data for the key and mapKey, if there was any. 65 * 66 * @return Returns the value that was stored under the keys, or null if there was none. 67 */ 68 @Nullable delete(int key, @NonNull String mapKey)69 public T delete(int key, @NonNull String mapKey) { 70 ArrayMap<String, T> data = mData.get(key); 71 if (data != null) { 72 return data.remove(mapKey); 73 } 74 return null; 75 } 76 77 /** 78 * Get the value associated with the int-String pair. 79 */ 80 @Nullable get(int key, @NonNull String mapKey)81 public T get(int key, @NonNull String mapKey) { 82 ArrayMap<String, T> data = mData.get(key); 83 if (data != null) { 84 return data.get(mapKey); 85 } 86 return null; 87 } 88 89 /** 90 * Returns the value to which the specified key and mapKey are mapped, or defaultValue if this 91 * map contains no mapping for them. 92 */ 93 @Nullable getOrDefault(int key, @NonNull String mapKey, T defaultValue)94 public T getOrDefault(int key, @NonNull String mapKey, T defaultValue) { 95 if (mData.contains(key)) { 96 ArrayMap<String, T> data = mData.get(key); 97 if (data != null && data.containsKey(mapKey)) { 98 return data.get(mapKey); 99 } 100 } 101 return defaultValue; 102 } 103 104 /** @see SparseArray#indexOfKey */ indexOfKey(int key)105 public int indexOfKey(int key) { 106 return mData.indexOfKey(key); 107 } 108 109 /** 110 * Returns the index of the mapKey. 111 * 112 * @see SparseArray#indexOfKey 113 */ indexOfKey(int key, @NonNull String mapKey)114 public int indexOfKey(int key, @NonNull String mapKey) { 115 ArrayMap<String, T> data = mData.get(key); 116 if (data != null) { 117 return data.indexOfKey(mapKey); 118 } 119 return -1; 120 } 121 122 /** Returns the key at the given index. */ keyAt(int index)123 public int keyAt(int index) { 124 return mData.keyAt(index); 125 } 126 127 /** Returns the map's key at the given mapIndex for the given keyIndex. */ 128 @NonNull keyAt(int keyIndex, int mapIndex)129 public String keyAt(int keyIndex, int mapIndex) { 130 return mData.valueAt(keyIndex).keyAt(mapIndex); 131 } 132 133 /** Returns the size of the outer array. */ numMaps()134 public int numMaps() { 135 return mData.size(); 136 } 137 138 /** Returns the number of elements in the map of the given key. */ numElementsForKey(int key)139 public int numElementsForKey(int key) { 140 ArrayMap<String, T> data = mData.get(key); 141 return data == null ? 0 : data.size(); 142 } 143 144 /** Returns the value T at the given key and map index. */ 145 @Nullable valueAt(int keyIndex, int mapIndex)146 public T valueAt(int keyIndex, int mapIndex) { 147 return mData.valueAt(keyIndex).valueAt(mapIndex); 148 } 149 150 /** Iterate through all int-String pairs and operate on all of the values. */ forEach(@onNull Consumer<T> consumer)151 public void forEach(@NonNull Consumer<T> consumer) { 152 for (int i = numMaps() - 1; i >= 0; --i) { 153 ArrayMap<String, T> data = mData.valueAt(i); 154 for (int j = data.size() - 1; j >= 0; --j) { 155 consumer.accept(data.valueAt(j)); 156 } 157 } 158 } 159 } 160