1 /*
2  * Copyright (C) 2020 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.libraries.tv.tvsystem.wifi;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.net.MacAddress;
23 import android.net.wifi.WifiConfiguration;
24 import android.net.wifi.WifiManager;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import com.android.internal.util.Preconditions;
29 
30 import java.nio.charset.StandardCharsets;
31 import java.util.Objects;
32 import java.util.concurrent.Executor;
33 
34 /**
35  * WiFi configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
36  *
37  * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
38  * framework how it should open a hotspot.  It is not meant to describe the network as it will be
39  * seen by clients; this role is currently served by {@link WifiConfiguration} (see
40  * {@link WifiManager.LocalOnlyHotspotReservation#getWifiConfiguration()}).
41  *
42  * Apps can use this to configure a local-only hotspot using
43  * {@link TvWifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
44  * WifiManager.LocalOnlyHotspotCallback)}.
45  *
46  * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to
47  * create a new instance.
48  *
49  * @hide
50  */
51 @SystemApi
52 public final class SoftApConfiguration implements Parcelable {
53     /**
54      * SSID for the AP, or null for a framework-determined SSID.
55      */
56     private final @Nullable
57     String mSsid;
58     /**
59      * BSSID for the AP, or null to use a framework-determined BSSID.
60      */
61     private final @Nullable
62     MacAddress mBssid;
63     /**
64      * Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
65      */
66     private final @Nullable
67     String mWpa2Passphrase;
68 
69     /** Private constructor for Builder and Parcelable implementation. */
SoftApConfiguration( @ullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase)70     private SoftApConfiguration(
71             @Nullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase) {
72         mSsid = ssid;
73         mBssid = bssid;
74         mWpa2Passphrase = wpa2Passphrase;
75     }
76 
77     @Override
equals(Object otherObj)78     public boolean equals(Object otherObj) {
79         if (this == otherObj) {
80             return true;
81         }
82         if (!(otherObj instanceof SoftApConfiguration)) {
83             return false;
84         }
85         SoftApConfiguration other = (SoftApConfiguration) otherObj;
86         return Objects.equals(mSsid, other.mSsid)
87                 && Objects.equals(mBssid, other.mBssid)
88                 && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase);
89     }
90 
91     @Override
hashCode()92     public int hashCode() {
93         return Objects.hash(mSsid, mBssid, mWpa2Passphrase);
94     }
95 
96     @Override
writeToParcel(@onNull Parcel dest, int flags)97     public void writeToParcel(@NonNull Parcel dest, int flags) {
98         dest.writeString(mSsid);
99         dest.writeParcelable(mBssid, flags);
100         dest.writeString(mWpa2Passphrase);
101     }
102 
103     @Override
describeContents()104     public int describeContents() {
105         return 0;
106     }
107 
108     @NonNull
109     public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() {
110         @Override
111         public SoftApConfiguration createFromParcel(Parcel in) {
112             return new SoftApConfiguration(
113                     in.readString(),
114                     in.readParcelable(MacAddress.class.getClassLoader()),
115                     in.readString());
116         }
117 
118         @Override
119         public SoftApConfiguration[] newArray(int size) {
120             return new SoftApConfiguration[size];
121         }
122     };
123 
124     @Nullable
getSsid()125     public String getSsid() {
126         return mSsid;
127     }
128 
129     @Nullable
getBssid()130     public MacAddress getBssid() {
131         return mBssid;
132     }
133 
134     @Nullable
getWpa2Passphrase()135     public String getWpa2Passphrase() {
136         return mWpa2Passphrase;
137     }
138 
139     /**
140      * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
141      * Soft AP.
142      *
143      * All fields are optional. By default, SSID and BSSID are automatically chosen by the
144      * framework, and an open network is created.
145      */
146     public static final class Builder {
147         private String mSsid;
148         private MacAddress mBssid;
149         private String mWpa2Passphrase;
150 
151         /**
152          * Constructs a Builder with default values (see {@link Builder}).
153          */
Builder()154         public Builder() {
155             mSsid = null;
156             mBssid = null;
157             mWpa2Passphrase = null;
158         }
159 
160         /**
161          * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance.
162          */
Builder(@onNull SoftApConfiguration other)163         public Builder(@NonNull SoftApConfiguration other) {
164             Objects.requireNonNull(other);
165 
166             mSsid = other.mSsid;
167             mBssid = other.mBssid;
168             mWpa2Passphrase = other.mWpa2Passphrase;
169         }
170 
171         /**
172          * Builds the {@link SoftApConfiguration}.
173          *
174          * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
175          */
176         @NonNull
build()177         public SoftApConfiguration build() {
178             return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase);
179         }
180 
181         /**
182          * Specifies an SSID for the AP.
183          *
184          * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
185          *             chosen by the framework.
186          * @return Builder for chaining.
187          * @throws IllegalArgumentException when the SSID is empty or not valid Unicode.
188          */
189         @NonNull
setSsid(@ullable String ssid)190         public Builder setSsid(@Nullable String ssid) {
191             if (ssid != null) {
192                 Preconditions.checkStringNotEmpty(ssid);
193                 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
194             }
195             mSsid = ssid;
196             return this;
197         }
198 
199         /**
200          * Specifies a BSSID for the AP.
201          *
202          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
203          *              responsible for avoiding collisions.
204          * @return Builder for chaining.
205          * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC
206          *                                  address.
207          */
208         @NonNull
setBssid(@ullable MacAddress bssid)209         public Builder setBssid(@Nullable MacAddress bssid) {
210             if (bssid != null) {
211                 Preconditions.checkArgument(!bssid.equals(MacAddress.ALL_ZEROS_ADDRESS));
212                 Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS));
213             }
214             mBssid = bssid;
215             return this;
216         }
217 
218         /**
219          * Specifies that this AP should use WPA2-PSK with the given passphrase.  When set to null
220          * and no other encryption method is configured, an open network is created.
221          *
222          * @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK
223          *                   configuration.
224          * @return Builder for chaining.
225          * @throws IllegalArgumentException when the passphrase is the empty string
226          */
227         @NonNull
setWpa2Passphrase(@ullable String passphrase)228         public Builder setWpa2Passphrase(@Nullable String passphrase) {
229             if (passphrase != null) {
230                 Preconditions.checkStringNotEmpty(passphrase);
231             }
232             mWpa2Passphrase = passphrase;
233             return this;
234         }
235     }
236 }
237