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