package com.android.hotspot2.osu;
import android.net.wifi.ScanResult;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class OSUInfo {
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 mSSID;
private final String mAdvertisingSSID;
private final OSUProvider mOSUProvider;
private final int mOsuID;
private long mOSUBssid;
private IconStatus mIconStatus = IconStatus.NotQueried;
private HSIconFileElement mIconFileElement;
private IconInfo mIconInfo;
public OSUInfo(ScanResult scanResult, String ssid, OSUProvider osuProvider, int osuID) {
mOsuID = osuID;
mBSSID = Utils.parseMac(scanResult.BSSID);
mHESSID = scanResult.hessid;
mAnqpDomID = scanResult.anqpDomainId;
mAdvertisingSSID = scanResult.SSID;
mSSID = 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<String>(name.getText(),
languageScore(name.getLanguage(), locale)));
}
Collections.sort(scoreList);
return scoreList.isEmpty() ? null : scoreList.iterator().next().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.iterator().next().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 void setIconFileElement(HSIconFileElement iconFileElement, String fileName) {
synchronized (mOSUProvider) {
mIconFileElement = iconFileElement;
for (IconInfo iconInfo : mOSUProvider.getIcons()) {
if (iconInfo.getFileName().equals(fileName)) {
mIconInfo = iconInfo;
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);
}
}
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());
for (ScoreEntry<IconInfo> scoredIcon : matches) {
icons.add(scoredIcon.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 getSSID() {
return mSSID;
}
public OSUProvider getOSUProvider() {
return mOSUProvider;
}
@Override
public String toString() {
return String.format("OSU Info '%s' %012x -> %s, icon %s",
mSSID, mBSSID, getServiceDescription(null), mIconStatus);
}
}