1 /*
2  * Copyright (C) 2015 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 com.android.server.wifi;
18 
19 import android.net.wifi.AnqpInformationElement;
20 import android.net.wifi.ScanResult;
21 import android.net.wifi.WifiSsid;
22 
23 import com.android.server.wifi.hotspot2.anqp.ANQPElement;
24 import com.android.server.wifi.hotspot2.anqp.Constants;
25 import com.android.server.wifi.hotspot2.anqp.HSFriendlyNameElement;
26 import com.android.server.wifi.hotspot2.anqp.RawByteElement;
27 import com.android.server.wifi.hotspot2.anqp.VenueNameElement;
28 import com.android.server.wifi.hotspot2.NetworkDetail;
29 import com.android.server.wifi.hotspot2.Utils;
30 
31 import java.util.List;
32 import java.util.Map;
33 
34 /**
35  * Wifi scan result details.
36  */
37 public class ScanDetail {
38     private final ScanResult mScanResult;
39     private volatile NetworkDetail mNetworkDetail;
40     private long mSeen = 0;
41 
ScanDetail(NetworkDetail networkDetail, WifiSsid wifiSsid, String bssid, String caps, int level, int frequency, long tsf, ScanResult.InformationElement[] informationElements, List<String> anqpLines)42     public ScanDetail(NetworkDetail networkDetail, WifiSsid wifiSsid, String bssid,
43             String caps, int level, int frequency, long tsf,
44             ScanResult.InformationElement[] informationElements, List<String> anqpLines) {
45         mNetworkDetail = networkDetail;
46         mScanResult = new ScanResult(wifiSsid, bssid, networkDetail.getHESSID(),
47                 networkDetail.getAnqpDomainID(), networkDetail.getOsuProviders(),
48                 caps, level, frequency, tsf);
49         mSeen = System.currentTimeMillis();
50         mScanResult.seen = mSeen;
51         mScanResult.channelWidth = networkDetail.getChannelWidth();
52         mScanResult.centerFreq0 = networkDetail.getCenterfreq0();
53         mScanResult.centerFreq1 = networkDetail.getCenterfreq1();
54         mScanResult.informationElements = informationElements;
55         mScanResult.anqpLines = anqpLines;
56         if (networkDetail.is80211McResponderSupport()) {
57             mScanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
58         }
59         if (networkDetail.isInterworking()) {
60             mScanResult.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
61         }
62     }
63 
ScanDetail(WifiSsid wifiSsid, String bssid, String caps, int level, int frequency, long tsf, long seen)64     public ScanDetail(WifiSsid wifiSsid, String bssid, String caps, int level, int frequency,
65                       long tsf, long seen) {
66         mNetworkDetail = null;
67         mScanResult = new ScanResult(wifiSsid, bssid, 0L, -1, null, caps, level, frequency, tsf);
68         mSeen = seen;
69         mScanResult.seen = mSeen;
70         mScanResult.channelWidth = 0;
71         mScanResult.centerFreq0 = 0;
72         mScanResult.centerFreq1 = 0;
73         mScanResult.flags = 0;
74     }
75 
ScanDetail(ScanResult scanResult, NetworkDetail networkDetail)76     public ScanDetail(ScanResult scanResult, NetworkDetail networkDetail) {
77         mScanResult = scanResult;
78         mNetworkDetail = networkDetail;
79         // Only inherit |mScanResult.seen| if it was previously set. This ensures that |mSeen|
80         // will always contain a valid timestamp.
81         mSeen = (mScanResult.seen == 0) ? System.currentTimeMillis() : mScanResult.seen;
82     }
83 
84     /**
85      * Store ANQ element information
86      *
87      * @param anqpElements Map<Constants.ANQPElementType, ANQPElement>
88      */
propagateANQPInfo(Map<Constants.ANQPElementType, ANQPElement> anqpElements)89     public void propagateANQPInfo(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
90         if (anqpElements.isEmpty()) {
91             return;
92         }
93         mNetworkDetail = mNetworkDetail.complete(anqpElements);
94         HSFriendlyNameElement fne = (HSFriendlyNameElement) anqpElements.get(
95                 Constants.ANQPElementType.HSFriendlyName);
96         // !!! Match with language
97         if (fne != null && !fne.getNames().isEmpty()) {
98             mScanResult.venueName = fne.getNames().get(0).getText();
99         } else {
100             VenueNameElement vne =
101                     (((VenueNameElement) anqpElements.get(
102                             Constants.ANQPElementType.ANQPVenueName)));
103             if (vne != null && !vne.getNames().isEmpty()) {
104                 mScanResult.venueName = vne.getNames().get(0).getText();
105             }
106         }
107         RawByteElement osuProviders = (RawByteElement) anqpElements
108                 .get(Constants.ANQPElementType.HSOSUProviders);
109         if (osuProviders != null) {
110             mScanResult.anqpElements = new AnqpInformationElement[1];
111             mScanResult.anqpElements[0] =
112                     new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
113                             AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders.getPayload());
114         }
115     }
116 
getScanResult()117     public ScanResult getScanResult() {
118         return mScanResult;
119     }
120 
getNetworkDetail()121     public NetworkDetail getNetworkDetail() {
122         return mNetworkDetail;
123     }
124 
getSSID()125     public String getSSID() {
126         return mNetworkDetail == null ? mScanResult.SSID : mNetworkDetail.getSSID();
127     }
128 
getBSSIDString()129     public String getBSSIDString() {
130         return  mNetworkDetail == null ? mScanResult.BSSID : mNetworkDetail.getBSSIDString();
131     }
132 
133     /**
134      *  Return the network detail key string.
135      */
toKeyString()136     public String toKeyString() {
137         NetworkDetail networkDetail = mNetworkDetail;
138         if (networkDetail != null) {
139             return networkDetail.toKeyString();
140         } else {
141             return String.format("'%s':%012x",
142                                  mScanResult.BSSID,
143                                  Utils.parseMac(mScanResult.BSSID));
144         }
145     }
146 
147     /**
148      * Return the time this network was last seen.
149      */
getSeen()150     public long getSeen() {
151         return mSeen;
152     }
153 
154     /**
155      * Update the time this network was last seen to the current system time.
156      */
setSeen()157     public long setSeen() {
158         mSeen = System.currentTimeMillis();
159         mScanResult.seen = mSeen;
160         return mSeen;
161     }
162 
163     @Override
toString()164     public String toString() {
165         try {
166             return String.format("'%s'/%012x",
167                                  mScanResult.SSID,
168                                  Utils.parseMac(mScanResult.BSSID));
169         } catch (IllegalArgumentException iae) {
170             return String.format("'%s'/----", mScanResult.BSSID);
171         }
172     }
173 }
174