1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.hotspot2.osu; 2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.util.Log; 4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.HSIconFileElement; 6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.IconInfo; 7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.Utils; 8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.ProtocolException; 10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.nio.BufferUnderflowException; 11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.nio.ByteBuffer; 12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.nio.ByteOrder; 13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.ArrayList; 14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Arrays; 15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collections; 16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap; 17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Iterator; 18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.LinkedHashMap; 19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.LinkedList; 20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.List; 21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map; 22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport static com.android.anqp.Constants.ANQPElementType.HSIconFile; 24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class IconCache extends Thread { 26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final int CacheSize = 64; 27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final int RetryCount = 3; 28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final OSUManager mOSUManager; 30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final Map<Long, LinkedList<QuerySet>> mBssQueues = new HashMap<>(); 31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final Map<IconKey, HSIconFileElement> mCache = 33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist new LinkedHashMap<IconKey, HSIconFileElement>() { 34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist protected boolean removeEldestEntry(Map.Entry eldest) { 36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return size() > CacheSize; 37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist }; 39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static class IconKey { 41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final long mBSSID; 42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final long mHESSID; 43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final String mSSID; 44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final int mAnqpDomID; 45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final String mFileName; 46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private IconKey(OSUInfo osuInfo, String fileName) { 48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBSSID = osuInfo.getBSSID(); 49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mHESSID = osuInfo.getHESSID(); 50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mSSID = osuInfo.getAdvertisingSSID(); 51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mAnqpDomID = osuInfo.getAnqpDomID(); 52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mFileName = fileName; 53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String getFileName() { 56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mFileName; 57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public boolean equals(Object thatObject) { 61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (this == thatObject) { 62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return true; 63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (thatObject == null || getClass() != thatObject.getClass()) { 65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return false; 66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist IconKey that = (IconKey) thatObject; 69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mFileName.equals(that.mFileName) && ((mBSSID == that.mBSSID) || 71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist ((mAnqpDomID == that.mAnqpDomID) && (mAnqpDomID != 0) && 72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist (mHESSID == that.mHESSID) && ((mHESSID != 0) 73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist || mSSID.equals(that.mSSID)))); 74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public int hashCode() { 78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist int result = (int) (mBSSID ^ (mBSSID >>> 32)); 79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist result = 31 * result + (int) (mHESSID ^ (mHESSID >>> 32)); 80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist result = 31 * result + mSSID.hashCode(); 81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist result = 31 * result + mAnqpDomID; 82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist result = 31 * result + mFileName.hashCode(); 83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return result; 84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String toString() { 88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return String.format("%012x:%012x '%s' [%d] + '%s'", 89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBSSID, mHESSID, mSSID, mAnqpDomID, mFileName); 90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static class QueryEntry { 94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final IconKey mKey; 95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private int mRetry; 96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private long mLastSent; 97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private QueryEntry(IconKey key) { 99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mKey = key; 100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mLastSent = System.currentTimeMillis(); 101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private IconKey getKey() { 104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mKey; 105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private int bumpRetry() { 108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mLastSent = System.currentTimeMillis(); 109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mRetry++; 110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private long age(long now) { 113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return now - mLastSent; 114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String toString() { 118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return String.format("Entry %s, retry %d", mKey, mRetry); 119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static class QuerySet { 123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final OSUInfo mOsuInfo; 124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final LinkedList<QueryEntry> mEntries; 125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private QuerySet(OSUInfo osuInfo, List<IconInfo> icons) { 127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOsuInfo = osuInfo; 128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mEntries = new LinkedList<>(); 129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (IconInfo iconInfo : icons) { 130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mEntries.addLast(new QueryEntry(new IconKey(osuInfo, iconInfo.getFileName()))); 131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private QueryEntry peek() { 135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mEntries.getFirst(); 136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private QueryEntry pop() { 139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mEntries.removeFirst(); 140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mEntries.isEmpty() ? null : mEntries.getFirst(); 141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private boolean isEmpty() { 144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mEntries.isEmpty(); 145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private List<QueryEntry> getAllEntries() { 148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return Collections.unmodifiableList(mEntries); 149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 150ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 151ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private long getBssid() { 152ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mOsuInfo.getBSSID(); 153ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 154ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 155ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private OSUInfo getOsuInfo() { 156ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mOsuInfo; 157ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 158ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 159ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private IconKey updateIcon(String fileName, HSIconFileElement iconFileElement) { 160ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist IconKey key = null; 161ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (QueryEntry queryEntry : mEntries) { 162ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queryEntry.getKey().getFileName().equals(fileName)) { 163ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist key = queryEntry.getKey(); 164ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 165ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 166ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (key == null) { 167ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return null; 168ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 169ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 170ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (iconFileElement != null) { 171ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOsuInfo.setIconFileElement(iconFileElement, fileName); 172ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 173ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOsuInfo.setIconStatus(OSUInfo.IconStatus.NotAvailable); 174ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 175ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return key; 176ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 177ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 178ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private boolean updateIcon(IconKey key, HSIconFileElement iconFileElement) { 179ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist boolean match = false; 180ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (QueryEntry queryEntry : mEntries) { 181ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queryEntry.getKey().equals(key)) { 182ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist match = true; 183ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 184ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 185ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 186ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (!match) { 187ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return false; 188ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 189ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 190ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (iconFileElement != null) { 191ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOsuInfo.setIconFileElement(iconFileElement, key.getFileName()); 192ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 193ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOsuInfo.setIconStatus(OSUInfo.IconStatus.NotAvailable); 194ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 195ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return true; 196ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 197ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 198ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 199ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String toString() { 200ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return "OSU " + mOsuInfo + ": " + mEntries; 201ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 202ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 203ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 204ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public IconCache(OSUManager osuManager) { 205ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOSUManager = osuManager; 206ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 207ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 208ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void clear() { 209ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.clear(); 210ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mCache.clear(); 211ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 212ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 213ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private boolean enqueue(QuerySet querySet) { 214ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist boolean newEntry = false; 215ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist LinkedList<QuerySet> queries = mBssQueues.get(querySet.getBssid()); 216ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queries == null) { 217ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist queries = new LinkedList<>(); 218ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.put(querySet.getBssid(), queries); 219ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist newEntry = true; 220ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 221ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist queries.addLast(querySet); 222ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return newEntry; 223ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 224ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 225ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void startIconQuery(OSUInfo osuInfo, List<IconInfo> icons) { 226ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d("ZXZ", String.format("Icon query on %012x for %s", osuInfo.getBSSID(), icons)); 227ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (icons == null || icons.isEmpty()) { 228ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 229ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 230ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 231ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QuerySet querySet = new QuerySet(osuInfo, icons); 232ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (QueryEntry entry : querySet.getAllEntries()) { 233ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist HSIconFileElement iconElement = mCache.get(entry.getKey()); 234ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (iconElement != null) { 235ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist osuInfo.setIconFileElement(iconElement, entry.getKey().getFileName()); 236ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOSUManager.iconResults(Arrays.asList(osuInfo)); 237ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 238ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 239ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 240ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (enqueue(querySet)) { 241ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist initiateQuery(querySet.getBssid()); 242ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 243ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 244ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 245ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private void initiateQuery(long bssid) { 246ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist LinkedList<QuerySet> queryEntries = mBssQueues.get(bssid); 247ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queryEntries == null) { 248ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 249ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else if (queryEntries.isEmpty()) { 250ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.remove(bssid); 251ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 252ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 253ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 254ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QuerySet querySet = queryEntries.getFirst(); 255ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QueryEntry queryEntry = querySet.peek(); 256ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queryEntry.bumpRetry() >= RetryCount) { 257ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QueryEntry newEntry = querySet.pop(); 258ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (newEntry == null) { 259ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // No more entries in this QuerySet, advance to the next set. 260ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist querySet.getOsuInfo().setIconStatus(OSUInfo.IconStatus.NotAvailable); 261ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist queryEntries.removeFirst(); 262ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queryEntries.isEmpty()) { 263ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // No further QuerySet on this BSSID, drop the bucket and bail. 264ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.remove(bssid); 265ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 266ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 267ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist querySet = queryEntries.getFirst(); 268ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist queryEntry = querySet.peek(); 269ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist queryEntry.bumpRetry(); 270ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 271ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 272ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 273ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOSUManager.doIconQuery(bssid, queryEntry.getKey().getFileName()); 274ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 275ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 276ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void notifyIconReceived(long bssid, String fileName, byte[] iconData) { 277ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d("ZXZ", String.format("Icon '%s':%d received from %012x", 278ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist fileName, iconData != null ? iconData.length : -1, bssid)); 279ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist IconKey key; 280ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist HSIconFileElement iconFileElement = null; 281ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist List<OSUInfo> updates = new ArrayList<>(); 282ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 283ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist LinkedList<QuerySet> querySets = mBssQueues.get(bssid); 284ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (querySets == null || querySets.isEmpty()) { 285ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d(OSUManager.TAG, 286ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String.format("Spurious icon response from %012x for '%s' (%d) bytes", 287ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist bssid, fileName, iconData != null ? iconData.length : -1)); 288ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d("ZXZ", "query set: " + querySets 289ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist + ", BSS queues: " + Utils.bssidsToString(mBssQueues.keySet())); 290ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 291ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 292ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QuerySet querySet = querySets.removeFirst(); 293ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (iconData != null) { 294ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist try { 295ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist iconFileElement = new HSIconFileElement(HSIconFile, 296ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist ByteBuffer.wrap(iconData).order(ByteOrder.LITTLE_ENDIAN)); 297ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } catch (ProtocolException | BufferUnderflowException e) { 298ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.e(OSUManager.TAG, "Failed to parse ANQP icon file: " + e); 299ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 300ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 301ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist key = querySet.updateIcon(fileName, iconFileElement); 302ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (key == null) { 303ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d(OSUManager.TAG, 304ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String.format("Spurious icon response from %012x for '%s' (%d) bytes", 305ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist bssid, fileName, iconData != null ? iconData.length : -1)); 306ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Log.d("ZXZ", "query set: " + querySets + ", BSS queues: " 307ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist + Utils.bssidsToString(mBssQueues.keySet())); 308ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist querySets.addFirst(querySet); 309ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 310ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 311ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 312ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (iconFileElement != null) { 313ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mCache.put(key, iconFileElement); 314ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 315ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 316ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (querySet.isEmpty()) { 317ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.remove(bssid); 318ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 319ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist updates.add(querySet.getOsuInfo()); 320ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 321ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 322ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Update any other pending entries that matches the ESS of the currently resolved icon 323ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Iterator<Map.Entry<Long, LinkedList<QuerySet>>> bssIterator = 324ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.entrySet().iterator(); 325ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist while (bssIterator.hasNext()) { 326ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Map.Entry<Long, LinkedList<QuerySet>> bssEntries = bssIterator.next(); 327ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Iterator<QuerySet> querySetIterator = bssEntries.getValue().iterator(); 328ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist while (querySetIterator.hasNext()) { 329ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QuerySet querySet = querySetIterator.next(); 330ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (querySet.updateIcon(key, iconFileElement)) { 331ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist querySetIterator.remove(); 332ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist updates.add(querySet.getOsuInfo()); 333ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 334ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 335ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (bssEntries.getValue().isEmpty()) { 336ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist bssIterator.remove(); 337ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 338ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 339ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 340ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist initiateQuery(bssid); 341ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 342ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mOSUManager.iconResults(updates); 343ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 344ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 345ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final long RequeryTimeLow = 6000L; 346ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final long RequeryTimeHigh = 15000L; 347ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 348ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void tickle(boolean wifiOff) { 349ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist synchronized (mCache) { 350ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (wifiOff) { 351ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.clear(); 352ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 353ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist long now = System.currentTimeMillis(); 354ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 355ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Iterator<Map.Entry<Long, LinkedList<QuerySet>>> bssIterator = 356ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mBssQueues.entrySet().iterator(); 357ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist while (bssIterator.hasNext()) { 358ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Get the list of entries for this BSSID 359ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Map.Entry<Long, LinkedList<QuerySet>> bssEntries = bssIterator.next(); 360ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Iterator<QuerySet> querySetIterator = bssEntries.getValue().iterator(); 361ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist while (querySetIterator.hasNext()) { 362ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QuerySet querySet = querySetIterator.next(); 363ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist QueryEntry queryEntry = querySet.peek(); 364ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist long age = queryEntry.age(now); 365ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (age > RequeryTimeHigh) { 366ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Timed out entry, move on to the next. 367ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist queryEntry = querySet.pop(); 368ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (queryEntry == null) { 369ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Empty query set, update status and remove it. 370ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist querySet.getOsuInfo() 371ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist .setIconStatus(OSUInfo.IconStatus.NotAvailable); 372ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist querySetIterator.remove(); 373ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 374ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Start a query on the next entry and bail out of the set iteration 375ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist initiateQuery(querySet.getBssid()); 376ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 377ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 378ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else if (age > RequeryTimeLow) { 379ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Re-issue queries for qualified entries and bail out of set iteration 380ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist initiateQuery(querySet.getBssid()); 381ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 382ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 383ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 384ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (bssEntries.getValue().isEmpty()) { 385ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Kill the whole bucket if the set list is empty 386ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist bssIterator.remove(); 387ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 388ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 389ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 390ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 391ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 392ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist} 393