223 lines
8.1 KiB
Java
223 lines
8.1 KiB
Java
|
/*
|
||
|
* Copyright (C) 2015 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package com.android.server.wifi;
|
||
|
|
||
|
import android.net.wifi.AnqpInformationElement;
|
||
|
import android.net.wifi.ScanResult;
|
||
|
import android.net.wifi.WifiSsid;
|
||
|
|
||
|
import androidx.annotation.NonNull;
|
||
|
import androidx.annotation.Nullable;
|
||
|
|
||
|
import com.android.internal.annotations.VisibleForTesting;
|
||
|
import com.android.server.wifi.hotspot2.NetworkDetail;
|
||
|
import com.android.server.wifi.hotspot2.Utils;
|
||
|
import com.android.server.wifi.hotspot2.anqp.ANQPElement;
|
||
|
import com.android.server.wifi.hotspot2.anqp.Constants;
|
||
|
import com.android.server.wifi.hotspot2.anqp.HSFriendlyNameElement;
|
||
|
import com.android.server.wifi.hotspot2.anqp.RawByteElement;
|
||
|
import com.android.server.wifi.hotspot2.anqp.VenueNameElement;
|
||
|
|
||
|
import java.util.List;
|
||
|
import java.util.Map;
|
||
|
|
||
|
/**
|
||
|
* Wifi scan result details.
|
||
|
*/
|
||
|
public class ScanDetail {
|
||
|
private final ScanResult mScanResult;
|
||
|
private volatile NetworkDetail mNetworkDetail;
|
||
|
private long mSeen = 0;
|
||
|
private byte[] mInformationElementRawData;
|
||
|
|
||
|
/**
|
||
|
* Main constructor used when converting from NativeScanResult
|
||
|
*/
|
||
|
public ScanDetail(@Nullable NetworkDetail networkDetail, @Nullable WifiSsid wifiSsid,
|
||
|
@Nullable String bssid, @Nullable String caps, int level, int frequency, long tsf,
|
||
|
@Nullable ScanResult.InformationElement[] informationElements,
|
||
|
@Nullable List<String> anqpLines, @Nullable byte[] informationElementRawData) {
|
||
|
mNetworkDetail = networkDetail;
|
||
|
long hessid = 0L;
|
||
|
int anqpDomainId = ScanResult.UNSPECIFIED;
|
||
|
byte[] osuProviders = null;
|
||
|
int channelWidth = ScanResult.UNSPECIFIED;
|
||
|
int centerFreq0 = ScanResult.UNSPECIFIED;
|
||
|
int centerFreq1 = ScanResult.UNSPECIFIED;
|
||
|
boolean isPasspoint = false;
|
||
|
boolean is80211McResponder = false;
|
||
|
if (networkDetail != null) {
|
||
|
hessid = networkDetail.getHESSID();
|
||
|
anqpDomainId = networkDetail.getAnqpDomainID();
|
||
|
osuProviders = networkDetail.getOsuProviders();
|
||
|
channelWidth = networkDetail.getChannelWidth();
|
||
|
centerFreq0 = networkDetail.getCenterfreq0();
|
||
|
centerFreq1 = networkDetail.getCenterfreq1();
|
||
|
isPasspoint = caps.contains("EAP")
|
||
|
&& networkDetail.isInterworking() && networkDetail.getHSRelease() != null;
|
||
|
is80211McResponder = networkDetail.is80211McResponderSupport();
|
||
|
}
|
||
|
mScanResult = new ScanResult(wifiSsid, bssid, hessid, anqpDomainId, osuProviders, caps,
|
||
|
level, frequency, tsf);
|
||
|
mSeen = System.currentTimeMillis();
|
||
|
mScanResult.seen = mSeen;
|
||
|
mScanResult.channelWidth = channelWidth;
|
||
|
mScanResult.centerFreq0 = centerFreq0;
|
||
|
mScanResult.centerFreq1 = centerFreq1;
|
||
|
mScanResult.informationElements = informationElements;
|
||
|
mScanResult.anqpLines = anqpLines;
|
||
|
if (is80211McResponder) {
|
||
|
mScanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
|
||
|
}
|
||
|
if (isPasspoint) {
|
||
|
mScanResult.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
|
||
|
}
|
||
|
mInformationElementRawData = informationElementRawData;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a ScanDetail without NetworkDetail for unit testing
|
||
|
*/
|
||
|
@VisibleForTesting
|
||
|
public ScanDetail(@Nullable WifiSsid wifiSsid, @Nullable String bssid, String caps, int level,
|
||
|
int frequency, long tsf, long seen) {
|
||
|
this(null, wifiSsid, bssid, caps, level, frequency, tsf, null, null, null);
|
||
|
mSeen = seen;
|
||
|
mScanResult.seen = seen;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a ScanDetail from a ScanResult
|
||
|
*/
|
||
|
public ScanDetail(@NonNull ScanResult scanResult) {
|
||
|
mScanResult = scanResult;
|
||
|
mNetworkDetail = new NetworkDetail(
|
||
|
scanResult.BSSID,
|
||
|
scanResult.informationElements,
|
||
|
scanResult.anqpLines,
|
||
|
scanResult.frequency);
|
||
|
// Only inherit |mScanResult.seen| if it was previously set. This ensures that |mSeen|
|
||
|
// will always contain a valid timestamp.
|
||
|
mSeen = (mScanResult.seen == 0) ? System.currentTimeMillis() : mScanResult.seen;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Copy constructor
|
||
|
*/
|
||
|
public ScanDetail(@NonNull ScanDetail scanDetail) {
|
||
|
mScanResult = new ScanResult(scanDetail.mScanResult);
|
||
|
mNetworkDetail = new NetworkDetail(scanDetail.mNetworkDetail);
|
||
|
mSeen = scanDetail.mSeen;
|
||
|
mInformationElementRawData = scanDetail.mInformationElementRawData;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Store ANQ element information
|
||
|
*
|
||
|
* @param anqpElements Map<Constants.ANQPElementType, ANQPElement>
|
||
|
*/
|
||
|
public void propagateANQPInfo(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
|
||
|
if (anqpElements.isEmpty()) {
|
||
|
return;
|
||
|
}
|
||
|
mNetworkDetail = mNetworkDetail.complete(anqpElements);
|
||
|
HSFriendlyNameElement fne = (HSFriendlyNameElement) anqpElements.get(
|
||
|
Constants.ANQPElementType.HSFriendlyName);
|
||
|
// !!! Match with language
|
||
|
if (fne != null && !fne.getNames().isEmpty()) {
|
||
|
mScanResult.venueName = fne.getNames().get(0).getText();
|
||
|
} else {
|
||
|
VenueNameElement vne =
|
||
|
(((VenueNameElement) anqpElements.get(
|
||
|
Constants.ANQPElementType.ANQPVenueName)));
|
||
|
if (vne != null && !vne.getNames().isEmpty()) {
|
||
|
mScanResult.venueName = vne.getNames().get(0).getText();
|
||
|
}
|
||
|
}
|
||
|
RawByteElement osuProviders = (RawByteElement) anqpElements
|
||
|
.get(Constants.ANQPElementType.HSOSUProviders);
|
||
|
if (osuProviders != null) {
|
||
|
mScanResult.anqpElements = new AnqpInformationElement[1];
|
||
|
mScanResult.anqpElements[0] =
|
||
|
new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
|
||
|
AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders.getPayload());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ScanResult getScanResult() {
|
||
|
return mScanResult;
|
||
|
}
|
||
|
|
||
|
public NetworkDetail getNetworkDetail() {
|
||
|
return mNetworkDetail;
|
||
|
}
|
||
|
|
||
|
public String getSSID() {
|
||
|
return mNetworkDetail == null ? mScanResult.SSID : mNetworkDetail.getSSID();
|
||
|
}
|
||
|
|
||
|
public String getBSSIDString() {
|
||
|
return mNetworkDetail == null ? mScanResult.BSSID : mNetworkDetail.getBSSIDString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the network detail key string.
|
||
|
*/
|
||
|
public String toKeyString() {
|
||
|
NetworkDetail networkDetail = mNetworkDetail;
|
||
|
if (networkDetail != null) {
|
||
|
return networkDetail.toKeyString();
|
||
|
} else {
|
||
|
return "'" + mScanResult.BSSID + "':" + Utils.macToSimpleString(
|
||
|
Utils.parseMac(mScanResult.BSSID));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the time this network was last seen.
|
||
|
*/
|
||
|
public long getSeen() {
|
||
|
return mSeen;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Update the time this network was last seen to the current system time.
|
||
|
*/
|
||
|
public long setSeen() {
|
||
|
mSeen = System.currentTimeMillis();
|
||
|
mScanResult.seen = mSeen;
|
||
|
return mSeen;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the network information element raw data.
|
||
|
*/
|
||
|
public byte[] getInformationElementRawData() {
|
||
|
return mInformationElementRawData;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
try {
|
||
|
return "'" + mScanResult.BSSID + "'/" + Utils.macToSimpleString(
|
||
|
Utils.parseMac(mScanResult.BSSID));
|
||
|
} catch (IllegalArgumentException iae) {
|
||
|
return "'" + mScanResult.BSSID + "'/----";
|
||
|
}
|
||
|
}
|
||
|
}
|