| package com.android.hotspot2.flow; |
| |
| import android.net.wifi.ScanResult; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.util.Log; |
| |
| import com.android.anqp.HSIconFileElement; |
| import com.android.anqp.I18Name; |
| import com.android.anqp.IconInfo; |
| import com.android.anqp.OSUProvider; |
| import com.android.hotspot2.Utils; |
| import com.android.hotspot2.osu.OSUManager; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| public class OSUInfo implements Parcelable { |
| public static final String GenericLocale = "zxx"; |
| |
| public enum IconStatus { |
| NotQueried, // |
| InProgress, // Query pending |
| NotAvailable, // Deterministically unavailable |
| Available // Icon data retrieved |
| } |
| |
| private final long mBSSID; |
| private final long mHESSID; |
| private final int mAnqpDomID; |
| private final String mAdvertisingSSID; |
| private final OSUProvider mOSUProvider; |
| private final int mOsuID; |
| private long mOSUBssid; |
| private IconStatus mIconStatus = IconStatus.NotQueried; |
| private HSIconFileElement mIconFileElement; |
| private String mIconFileName; |
| private IconInfo mIconInfo; |
| |
| public OSUInfo(ScanResult scanResult, OSUProvider osuProvider, int osuID) { |
| mOsuID = osuID; |
| mBSSID = Utils.parseMac(scanResult.BSSID); |
| mHESSID = scanResult.hessid; |
| mAnqpDomID = scanResult.anqpDomainId; |
| mAdvertisingSSID = scanResult.SSID; |
| mOSUProvider = osuProvider; |
| } |
| |
| public long getOSUBssid() { |
| return mOSUBssid; |
| } |
| |
| public void setOSUBssid(long OSUBssid) { |
| mOSUBssid = OSUBssid; |
| } |
| |
| public long getHESSID() { |
| return mHESSID; |
| } |
| |
| public int getAnqpDomID() { |
| return mAnqpDomID; |
| } |
| |
| public String getAdvertisingSsid() { |
| return mAdvertisingSSID; |
| } |
| |
| public Set<Locale> getNameLocales() { |
| Set<Locale> locales = new HashSet<>(mOSUProvider.getNames().size()); |
| for (I18Name name : mOSUProvider.getNames()) { |
| locales.add(name.getLocale()); |
| } |
| return locales; |
| } |
| |
| public Set<Locale> getServiceLocales() { |
| Set<Locale> locales = new HashSet<>(mOSUProvider.getServiceDescriptions().size()); |
| for (I18Name name : mOSUProvider.getServiceDescriptions()) { |
| locales.add(name.getLocale()); |
| } |
| return locales; |
| } |
| |
| public Set<String> getIconLanguages() { |
| Set<String> locales = new HashSet<>(mOSUProvider.getIcons().size()); |
| for (IconInfo iconInfo : mOSUProvider.getIcons()) { |
| locales.add(iconInfo.getLanguage()); |
| } |
| return locales; |
| } |
| |
| public String getName(Locale locale) { |
| List<ScoreEntry<String>> scoreList = new ArrayList<>(); |
| for (I18Name name : mOSUProvider.getNames()) { |
| if (locale == null || name.getLocale().equals(locale)) { |
| return name.getText(); |
| } |
| scoreList.add(new ScoreEntry<>(name.getText(), |
| languageScore(name.getLanguage(), locale))); |
| } |
| Collections.sort(scoreList); |
| return scoreList.isEmpty() ? null : scoreList.get(scoreList.size() - 1).getData(); |
| } |
| |
| public String getServiceDescription(Locale locale) { |
| List<ScoreEntry<String>> scoreList = new ArrayList<>(); |
| for (I18Name service : mOSUProvider.getServiceDescriptions()) { |
| if (locale == null || service.getLocale().equals(locale)) { |
| return service.getText(); |
| } |
| scoreList.add(new ScoreEntry<>(service.getText(), |
| languageScore(service.getLanguage(), locale))); |
| } |
| Collections.sort(scoreList); |
| return scoreList.isEmpty() ? null : scoreList.get(scoreList.size() - 1).getData(); |
| } |
| |
| public int getOsuID() { |
| return mOsuID; |
| } |
| |
| public void setIconStatus(IconStatus iconStatus) { |
| synchronized (mOSUProvider) { |
| mIconStatus = iconStatus; |
| } |
| } |
| |
| public IconStatus getIconStatus() { |
| synchronized (mOSUProvider) { |
| return mIconStatus; |
| } |
| } |
| |
| public HSIconFileElement getIconFileElement() { |
| synchronized (mOSUProvider) { |
| return mIconFileElement; |
| } |
| } |
| |
| public IconInfo getIconInfo() { |
| synchronized (mOSUProvider) { |
| return mIconInfo; |
| } |
| } |
| |
| public String getIconFileName() { |
| return mIconFileName; |
| } |
| |
| public void setIconFileElement(HSIconFileElement iconFileElement, String fileName) { |
| synchronized (mOSUProvider) { |
| mIconFileElement = iconFileElement; |
| for (IconInfo iconInfo : mOSUProvider.getIcons()) { |
| if (iconInfo.getFileName().equals(fileName)) { |
| mIconInfo = iconInfo; |
| mIconFileName = fileName; |
| break; |
| } |
| } |
| mIconStatus = IconStatus.Available; |
| } |
| } |
| |
| private static class ScoreEntry<T> implements Comparable<ScoreEntry> { |
| private final T mData; |
| private final int mScore; |
| |
| private ScoreEntry(T data, int score) { |
| mData = data; |
| mScore = score; |
| } |
| |
| public T getData() { |
| return mData; |
| } |
| |
| @Override |
| public int compareTo(ScoreEntry other) { |
| return Integer.compare(mScore, other.mScore); |
| } |
| |
| @Override |
| public String toString() { |
| return String.format("%d for '%s'", mScore, mData); |
| } |
| } |
| |
| public List<IconInfo> getIconInfo(Locale locale, Set<String> types, int width, int height) { |
| if (mOSUProvider.getIcons().isEmpty()) { |
| return null; |
| } |
| Log.d(OSUManager.TAG, "Matching icons against " + locale |
| + ", types " + types + ", " + width + "*" + height); |
| |
| List<ScoreEntry<IconInfo>> matches = new ArrayList<>(); |
| for (IconInfo iconInfo : mOSUProvider.getIcons()) { |
| Log.d(OSUManager.TAG, "Checking icon " + iconInfo.toString()); |
| if (!types.contains(iconInfo.getIconType())) { |
| continue; |
| } |
| |
| int score = languageScore(iconInfo.getLanguage(), locale); |
| int delta = iconInfo.getWidth() - width; |
| // Best size score is 1024 for a exact match, i.e. 2048 if both sides match |
| if (delta >= 0) { |
| score += (256 - delta) * 4; // Prefer down-scaling |
| } else { |
| score += 256 + delta; // Before up-scaling |
| } |
| delta = iconInfo.getHeight() - height; |
| if (delta >= 0) { |
| score += (256 - delta) * 4; |
| } else { |
| score += 256 + delta; |
| } |
| matches.add(new ScoreEntry<>(iconInfo, score)); |
| } |
| if (matches.isEmpty()) { |
| return Collections.emptyList(); |
| } |
| Collections.sort(matches); |
| List<IconInfo> icons = new ArrayList<>(matches.size()); |
| ListIterator<ScoreEntry<IconInfo>> matchIterator = matches.listIterator(matches.size()); |
| while (matchIterator.hasPrevious()) { |
| icons.add(matchIterator.previous().getData()); |
| } |
| return icons; |
| } |
| |
| private static int languageScore(String language, Locale locale) { |
| if (language.length() == 3 && language.equalsIgnoreCase(locale.getISO3Language()) || |
| language.length() == 2 && language.equalsIgnoreCase(locale.getLanguage())) { |
| return 4096; |
| } else if (language.equalsIgnoreCase(GenericLocale)) { |
| return 3072; |
| } else if (language.equalsIgnoreCase("eng")) { |
| return 2048; |
| } else { |
| return 1024; |
| } |
| } |
| |
| public long getBSSID() { |
| return mBSSID; |
| } |
| |
| public String getOsuSsid() { |
| return mOSUProvider.getSSID(); |
| } |
| |
| public OSUProvider getOSUProvider() { |
| return mOSUProvider; |
| } |
| |
| @Override |
| public String toString() { |
| return String.format("OSU Info '%s' %012x -> %s, icon %s", |
| getOsuSsid(), mBSSID, getServiceDescription(null), mIconStatus); |
| } |
| |
| private OSUInfo(Parcel in) { |
| mBSSID = in.readLong(); |
| mHESSID = in.readLong(); |
| mAnqpDomID = in.readInt(); |
| mAdvertisingSSID = in.readString(); |
| mOsuID = in.readInt(); |
| mOSUBssid = in.readLong(); |
| mIconFileName = in.readString(); |
| mIconStatus = Utils.mapEnum(in.readInt(), IconStatus.class); |
| OSUProvider osuProvider; |
| try { |
| osuProvider = new OSUProvider(in); |
| } catch (IOException ioe) { |
| osuProvider = null; |
| } |
| mOSUProvider = osuProvider; |
| if (osuProvider == null) { |
| return; |
| } |
| mIconFileElement = new HSIconFileElement(in); |
| int iconIndex = in.readInt(); |
| mIconInfo = iconIndex >= 0 && iconIndex < mOSUProvider.getIcons().size() |
| ? mOSUProvider.getIcons().get(iconIndex) : null; |
| } |
| |
| public static final Parcelable.Creator<OSUInfo> CREATOR = new Parcelable.Creator<OSUInfo>() { |
| public OSUInfo createFromParcel(Parcel in) { |
| return new OSUInfo(in); |
| } |
| |
| public OSUInfo[] newArray(int size) { |
| return new OSUInfo[size]; |
| } |
| }; |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeLong(mBSSID); |
| dest.writeLong(mHESSID); |
| dest.writeInt(mAnqpDomID); |
| dest.writeString(mAdvertisingSSID); |
| dest.writeInt(mOsuID); |
| dest.writeLong(mOSUBssid); |
| dest.writeString(mIconFileName); |
| dest.writeInt(mIconStatus.ordinal()); |
| mOSUProvider.writeParcel(dest); |
| mIconFileElement.writeParcel(dest); |
| } |
| } |