1/*
2 * Copyright (C) 2014 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
17package android.net;
18
19import android.annotation.Nullable;
20import android.annotation.SystemApi;
21import android.net.wifi.ScanResult;
22import android.net.wifi.WifiInfo;
23import android.net.wifi.WifiSsid;
24import android.os.Parcel;
25import android.os.Parcelable;
26import android.text.TextUtils;
27import android.util.Log;
28
29import java.util.Objects;
30
31/**
32 * Information which identifies a specific network.
33 *
34 * @hide
35 */
36@SystemApi
37// NOTE: Ideally, we would abstract away the details of what identifies a network of a specific
38// type, so that all networks appear the same and can be scored without concern to the network type
39// itself. However, because no such cross-type identifier currently exists in the Android framework,
40// and because systems might obtain information about networks from sources other than Android
41// devices, we need to provide identifying details about each specific network type (wifi, cell,
42// etc.) so that clients can pull out these details depending on the type of network.
43public class NetworkKey implements Parcelable {
44
45    private static final String TAG = "NetworkKey";
46
47    /** A wifi network, for which {@link #wifiKey} will be populated. */
48    public static final int TYPE_WIFI = 1;
49
50    /**
51     * The type of this network.
52     * @see #TYPE_WIFI
53     */
54    public final int type;
55
56    /**
57     * Information identifying a Wi-Fi network. Only set when {@link #type} equals
58     * {@link #TYPE_WIFI}.
59     */
60    public final WifiKey wifiKey;
61
62    /**
63     * Constructs a new NetworkKey for the given wifi {@link ScanResult}.
64     *
65     * @return  A new {@link NetworkKey} instance or <code>null</code> if the given
66     *          {@link ScanResult} instance is malformed.
67     * @hide
68     */
69    @Nullable
70    public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
71        if (result != null && result.wifiSsid != null) {
72            final String ssid = result.wifiSsid.toString();
73            final String bssid = result.BSSID;
74            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
75                    && !TextUtils.isEmpty(bssid)) {
76                WifiKey wifiKey;
77                try {
78                    wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
79                } catch (IllegalArgumentException e) {
80                    Log.e(TAG, "Unable to create WifiKey.", e);
81                    return null;
82                }
83                return new NetworkKey(wifiKey);
84            }
85        }
86        return null;
87    }
88
89    /**
90     * Constructs a new NetworkKey for the given {@link WifiInfo}.
91     *
92     * @param wifiInfo the {@link WifiInfo} to create a {@link NetworkKey} for.
93     * @return A new {@link NetworkKey} instance or <code>null</code> if the given {@link WifiInfo}
94     *         instance doesn't represent a connected WiFi network.
95     * @hide
96     */
97    @Nullable
98    public static NetworkKey createFromWifiInfo(@Nullable WifiInfo wifiInfo) {
99        if (wifiInfo != null) {
100            final String ssid = wifiInfo.getSSID();
101            final String bssid = wifiInfo.getBSSID();
102            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
103                    && !TextUtils.isEmpty(bssid)) {
104                WifiKey wifiKey;
105                try {
106                    wifiKey = new WifiKey(ssid, bssid);
107                } catch (IllegalArgumentException e) {
108                    Log.e(TAG, "Unable to create WifiKey.", e);
109                    return null;
110                }
111                return new NetworkKey(wifiKey);
112            }
113        }
114        return null;
115    }
116
117    /**
118     * Construct a new {@link NetworkKey} for a Wi-Fi network.
119     * @param wifiKey the {@link WifiKey} identifying this Wi-Fi network.
120     */
121    public NetworkKey(WifiKey wifiKey) {
122        this.type = TYPE_WIFI;
123        this.wifiKey = wifiKey;
124    }
125
126    private NetworkKey(Parcel in) {
127        type = in.readInt();
128        switch (type) {
129            case TYPE_WIFI:
130                wifiKey = WifiKey.CREATOR.createFromParcel(in);
131                break;
132            default:
133                throw new IllegalArgumentException("Parcel has unknown type: " + type);
134        }
135    }
136
137    @Override
138    public int describeContents() {
139        return 0;
140    }
141
142    @Override
143    public void writeToParcel(Parcel out, int flags) {
144        out.writeInt(type);
145        switch (type) {
146            case TYPE_WIFI:
147                wifiKey.writeToParcel(out, flags);
148                break;
149            default:
150                throw new IllegalStateException("NetworkKey has unknown type " + type);
151        }
152    }
153
154    @Override
155    public boolean equals(Object o) {
156        if (this == o) return true;
157        if (o == null || getClass() != o.getClass()) return false;
158
159        NetworkKey that = (NetworkKey) o;
160
161        return type == that.type && Objects.equals(wifiKey, that.wifiKey);
162    }
163
164    @Override
165    public int hashCode() {
166        return Objects.hash(type, wifiKey);
167    }
168
169    @Override
170    public String toString() {
171        switch (type) {
172            case TYPE_WIFI:
173                return wifiKey.toString();
174            default:
175                // Don't throw an exception here in case someone is logging this object in a catch
176                // block for debugging purposes.
177                return "InvalidKey";
178        }
179    }
180
181    public static final Parcelable.Creator<NetworkKey> CREATOR =
182            new Parcelable.Creator<NetworkKey>() {
183                @Override
184                public NetworkKey createFromParcel(Parcel in) {
185                    return new NetworkKey(in);
186                }
187
188                @Override
189                public NetworkKey[] newArray(int size) {
190                    return new NetworkKey[size];
191                }
192            };
193}
194