723 lines
29 KiB
Java
723 lines
29 KiB
Java
/*
|
|
* Copyright (C) 2011 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 android.net.wifi.p2p;
|
|
|
|
import android.annotation.FlaggedApi;
|
|
import android.annotation.IntDef;
|
|
import android.annotation.IntRange;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.SystemApi;
|
|
import android.compat.annotation.UnsupportedAppUsage;
|
|
import android.net.MacAddress;
|
|
import android.net.wifi.OuiKeyedData;
|
|
import android.net.wifi.ParcelUtil;
|
|
import android.net.wifi.WpsInfo;
|
|
import android.os.Build;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.text.TextUtils;
|
|
|
|
import androidx.annotation.RequiresApi;
|
|
|
|
import com.android.modules.utils.build.SdkLevel;
|
|
import com.android.wifi.flags.Flags;
|
|
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.regex.PatternSyntaxException;
|
|
|
|
/**
|
|
* A class representing a Wi-Fi P2p configuration for setting up a connection
|
|
*
|
|
* {@see WifiP2pManager}
|
|
*/
|
|
public class WifiP2pConfig implements Parcelable {
|
|
|
|
/**
|
|
* The device MAC address uniquely identifies a Wi-Fi p2p device
|
|
*/
|
|
public String deviceAddress = "";
|
|
|
|
/**
|
|
* Wi-Fi Protected Setup information
|
|
*/
|
|
public WpsInfo wps;
|
|
|
|
/** Get the network name of this P2P configuration, or null if unset. */
|
|
@Nullable
|
|
public String getNetworkName() {
|
|
return networkName;
|
|
}
|
|
|
|
/** @hide */
|
|
public String networkName = "";
|
|
|
|
/** Get the passphrase of this P2P configuration, or null if unset. */
|
|
@Nullable
|
|
public String getPassphrase() {
|
|
return passphrase;
|
|
}
|
|
|
|
/** @hide */
|
|
public String passphrase = "";
|
|
|
|
/**
|
|
* Get the required band for the group owner.
|
|
* The result will be one of the following:
|
|
* {@link #GROUP_OWNER_BAND_AUTO},
|
|
* {@link #GROUP_OWNER_BAND_2GHZ},
|
|
* {@link #GROUP_OWNER_BAND_5GHZ}
|
|
*/
|
|
@GroupOperatingBandType
|
|
public int getGroupOwnerBand() {
|
|
return groupOwnerBand;
|
|
}
|
|
|
|
/** @hide */
|
|
@GroupOperatingBandType
|
|
public int groupOwnerBand = GROUP_OWNER_BAND_AUTO;
|
|
|
|
/** @hide */
|
|
@IntDef(flag = false, prefix = { "GROUP_OWNER_BAND_" }, value = {
|
|
GROUP_OWNER_BAND_AUTO,
|
|
GROUP_OWNER_BAND_2GHZ,
|
|
GROUP_OWNER_BAND_5GHZ
|
|
})
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
public @interface GroupOperatingBandType {}
|
|
|
|
/**
|
|
* IP provisioning via IPv4 DHCP, when joining a group as a group client.
|
|
*/
|
|
public static final int GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP = 0;
|
|
|
|
/**
|
|
* IP provisioning via IPv6 link-local, when joining a group as a group client.
|
|
*/
|
|
public static final int GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL = 1;
|
|
|
|
/**
|
|
* Allow the system to pick the operating frequency from all supported bands.
|
|
*/
|
|
public static final int GROUP_OWNER_BAND_AUTO = 0;
|
|
/**
|
|
* Allow the system to pick the operating frequency from the 2.4 GHz band.
|
|
*/
|
|
public static final int GROUP_OWNER_BAND_2GHZ = 1;
|
|
/**
|
|
* Allow the system to pick the operating frequency from the 5 GHz band.
|
|
*/
|
|
public static final int GROUP_OWNER_BAND_5GHZ = 2;
|
|
|
|
/**
|
|
* The least inclination to be a group owner, to be filled in the field
|
|
* {@link #groupOwnerIntent}.
|
|
*/
|
|
public static final int GROUP_OWNER_INTENT_MIN = 0;
|
|
|
|
/**
|
|
* The most inclination to be a group owner, to be filled in the field
|
|
* {@link #groupOwnerIntent}.
|
|
*/
|
|
public static final int GROUP_OWNER_INTENT_MAX = 15;
|
|
|
|
/**
|
|
* The system can choose an appropriate owner intent value, to be filled in the field
|
|
* {@link #groupOwnerIntent}.
|
|
*/
|
|
public static final int GROUP_OWNER_INTENT_AUTO = -1;
|
|
|
|
/**
|
|
* This is an integer value between {@link #GROUP_OWNER_INTENT_MIN} and
|
|
* {@link #GROUP_OWNER_INTENT_MAX} where
|
|
* {@link #GROUP_OWNER_INTENT_MIN} indicates the least inclination to be a group owner and
|
|
* {@link #GROUP_OWNER_INTENT_MAX} indicates the highest inclination to be a group owner.
|
|
*
|
|
* A value of {@link #GROUP_OWNER_INTENT_AUTO} indicates the system can choose an appropriate
|
|
* value.
|
|
*
|
|
* By default this field is set to {@link #GROUP_OWNER_INTENT_AUTO}.
|
|
*/
|
|
@IntRange(from = 0, to = 15)
|
|
public int groupOwnerIntent = GROUP_OWNER_INTENT_AUTO;
|
|
|
|
/** @hide */
|
|
@IntDef(prefix = { "GROUP_CLIENT_IP_PROVISIONING_MODE_" }, value = {
|
|
GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP,
|
|
GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL
|
|
})
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
public @interface GroupClientIpProvisioningMode {}
|
|
|
|
@GroupClientIpProvisioningMode
|
|
private int mGroupClientIpProvisioningMode = GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP;
|
|
|
|
/**
|
|
* Query whether or not join existing group is enabled/disabled.
|
|
* @see #setJoinExistingGroup(boolean)
|
|
*
|
|
* @return true if configured to trigger the join existing group logic. False otherwise.
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
public boolean isJoinExistingGroup() {
|
|
return mJoinExistingGroup;
|
|
}
|
|
|
|
/**
|
|
* Join an existing group as a client.
|
|
*/
|
|
private boolean mJoinExistingGroup = false;
|
|
|
|
/** @hide */
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public int netId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
|
|
|
|
/**
|
|
* Get the network ID of this P2P configuration.
|
|
* @return either a non-negative network ID, or one of
|
|
* {@link WifiP2pGroup#NETWORK_ID_PERSISTENT} or {@link WifiP2pGroup#NETWORK_ID_TEMPORARY}.
|
|
*/
|
|
public int getNetworkId() {
|
|
return netId;
|
|
}
|
|
|
|
/** List of {@link OuiKeyedData} providing vendor-specific configuration data. */
|
|
private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList();
|
|
|
|
/**
|
|
* Set additional vendor-provided configuration data.
|
|
*
|
|
* @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the
|
|
* vendor-provided configuration data. Note that multiple elements with
|
|
* the same OUI are allowed.
|
|
* @hide
|
|
*/
|
|
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
|
|
@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
|
|
@SystemApi
|
|
public void setVendorData(@NonNull List<OuiKeyedData> vendorData) {
|
|
if (!SdkLevel.isAtLeastV()) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
if (vendorData == null) {
|
|
throw new IllegalArgumentException("setVendorData received a null value");
|
|
}
|
|
mVendorData = new ArrayList<>(vendorData);
|
|
}
|
|
|
|
/**
|
|
* Return the vendor-provided configuration data, if it exists. See also {@link
|
|
* #setVendorData(List)}
|
|
*
|
|
* @return Vendor configuration data, or empty list if it does not exist.
|
|
* @hide
|
|
*/
|
|
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
|
|
@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
|
|
@SystemApi
|
|
@NonNull
|
|
public List<OuiKeyedData> getVendorData() {
|
|
if (!SdkLevel.isAtLeastV()) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
return mVendorData;
|
|
}
|
|
|
|
public WifiP2pConfig() {
|
|
//set defaults
|
|
wps = new WpsInfo();
|
|
wps.setup = WpsInfo.PBC;
|
|
}
|
|
|
|
/** @hide */
|
|
public void invalidate() {
|
|
deviceAddress = "";
|
|
}
|
|
|
|
/** P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 {@hide}*/
|
|
@UnsupportedAppUsage
|
|
public WifiP2pConfig(String supplicantEvent) throws IllegalArgumentException {
|
|
String[] tokens = supplicantEvent.split(" ");
|
|
|
|
if (tokens.length < 2 || !tokens[0].equals("P2P-GO-NEG-REQUEST")) {
|
|
throw new IllegalArgumentException("Malformed supplicant event");
|
|
}
|
|
|
|
deviceAddress = tokens[1];
|
|
wps = new WpsInfo();
|
|
|
|
if (tokens.length > 2) {
|
|
String[] nameVal = tokens[2].split("=");
|
|
int devPasswdId;
|
|
try {
|
|
devPasswdId = Integer.parseInt(nameVal[1]);
|
|
} catch (NumberFormatException e) {
|
|
devPasswdId = 0;
|
|
}
|
|
//Based on definitions in wps/wps_defs.h
|
|
switch (devPasswdId) {
|
|
//DEV_PW_USER_SPECIFIED = 0x0001,
|
|
case 0x01:
|
|
wps.setup = WpsInfo.DISPLAY;
|
|
break;
|
|
//DEV_PW_PUSHBUTTON = 0x0004,
|
|
case 0x04:
|
|
wps.setup = WpsInfo.PBC;
|
|
break;
|
|
//DEV_PW_REGISTRAR_SPECIFIED = 0x0005
|
|
case 0x05:
|
|
wps.setup = WpsInfo.KEYPAD;
|
|
break;
|
|
default:
|
|
wps.setup = WpsInfo.PBC;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the IP provisioning mode when joining a group as a group client.
|
|
* The result will be one of the following:
|
|
* {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP},
|
|
* {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL}
|
|
*/
|
|
@GroupClientIpProvisioningMode
|
|
public int getGroupClientIpProvisioningMode() {
|
|
return mGroupClientIpProvisioningMode;
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuffer sbuf = new StringBuffer();
|
|
sbuf.append("\n address: ").append(deviceAddress);
|
|
sbuf.append("\n wps: ").append(wps);
|
|
sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent);
|
|
sbuf.append("\n persist: ").append(netId);
|
|
sbuf.append("\n networkName: ").append(networkName);
|
|
sbuf.append("\n passphrase: ").append(
|
|
TextUtils.isEmpty(passphrase) ? "<empty>" : "<non-empty>");
|
|
sbuf.append("\n groupOwnerBand: ").append(groupOwnerBand);
|
|
sbuf.append("\n groupClientIpProvisioningMode: ").append(mGroupClientIpProvisioningMode);
|
|
sbuf.append("\n joinExistingGroup: ").append(mJoinExistingGroup);
|
|
sbuf.append("\n vendorData: ").append(mVendorData);
|
|
return sbuf.toString();
|
|
}
|
|
|
|
/** Implement the Parcelable interface */
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
/** copy constructor */
|
|
public WifiP2pConfig(WifiP2pConfig source) {
|
|
if (source != null) {
|
|
deviceAddress = source.deviceAddress;
|
|
wps = new WpsInfo(source.wps);
|
|
groupOwnerIntent = source.groupOwnerIntent;
|
|
netId = source.netId;
|
|
networkName = source.networkName;
|
|
passphrase = source.passphrase;
|
|
groupOwnerBand = source.groupOwnerBand;
|
|
mGroupClientIpProvisioningMode = source.mGroupClientIpProvisioningMode;
|
|
mJoinExistingGroup = source.mJoinExistingGroup;
|
|
mVendorData = new ArrayList<>(source.mVendorData);
|
|
}
|
|
}
|
|
|
|
/** Implement the Parcelable interface */
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
dest.writeString(deviceAddress);
|
|
dest.writeParcelable(wps, flags);
|
|
dest.writeInt(groupOwnerIntent);
|
|
dest.writeInt(netId);
|
|
dest.writeString(networkName);
|
|
dest.writeString(passphrase);
|
|
dest.writeInt(groupOwnerBand);
|
|
dest.writeInt(mGroupClientIpProvisioningMode);
|
|
dest.writeBoolean(mJoinExistingGroup);
|
|
dest.writeList(mVendorData);
|
|
}
|
|
|
|
/** Implement the Parcelable interface */
|
|
@NonNull
|
|
public static final Creator<WifiP2pConfig> CREATOR =
|
|
new Creator<WifiP2pConfig>() {
|
|
public WifiP2pConfig createFromParcel(Parcel in) {
|
|
WifiP2pConfig config = new WifiP2pConfig();
|
|
config.deviceAddress = in.readString();
|
|
config.wps = (WpsInfo) in.readParcelable(null);
|
|
config.groupOwnerIntent = in.readInt();
|
|
config.netId = in.readInt();
|
|
config.networkName = in.readString();
|
|
config.passphrase = in.readString();
|
|
config.groupOwnerBand = in.readInt();
|
|
config.mGroupClientIpProvisioningMode = in.readInt();
|
|
config.mJoinExistingGroup = in.readBoolean();
|
|
config.mVendorData = ParcelUtil.readOuiKeyedDataList(in);
|
|
return config;
|
|
}
|
|
|
|
public WifiP2pConfig[] newArray(int size) {
|
|
return new WifiP2pConfig[size];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Builder used to build {@link WifiP2pConfig} objects for
|
|
* creating or joining a group.
|
|
*
|
|
* The WifiP2pConfig can be constructed for two use-cases:
|
|
* <ul>
|
|
* <li>SSID + Passphrase are known: use {@link #setNetworkName(String)} and
|
|
* {@link #setPassphrase(String)}.</li>
|
|
* <li>SSID or Passphrase is unknown, in such a case the MAC address must be known and
|
|
* specified using {@link #setDeviceAddress(MacAddress)}.</li>
|
|
* </ul>
|
|
*/
|
|
public static final class Builder {
|
|
|
|
private static final MacAddress MAC_ANY_ADDRESS =
|
|
MacAddress.fromString("02:00:00:00:00:00");
|
|
/**
|
|
* Maximum number of bytes allowed for a SSID.
|
|
*/
|
|
private static final int MAX_SSID_BYTES = 32;
|
|
|
|
private MacAddress mDeviceAddress = MAC_ANY_ADDRESS;
|
|
private String mNetworkName = "";
|
|
private String mPassphrase = "";
|
|
private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
|
|
private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
|
|
private int mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
|
|
private int mGroupClientIpProvisioningMode = GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP;
|
|
private boolean mJoinExistingGroup = false;
|
|
|
|
/**
|
|
* Specify the peer's MAC address. If not set, the device will
|
|
* try to find a peer whose SSID matches the network name as
|
|
* specified by {@link #setNetworkName(String)}. Specifying null will
|
|
* reset the peer's MAC address to "02:00:00:00:00:00".
|
|
* <p>
|
|
* Optional. "02:00:00:00:00:00" by default.
|
|
*
|
|
* <p> If the network name is not set, the peer's MAC address is mandatory.
|
|
*
|
|
* @param deviceAddress the peer's MAC address.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
*/
|
|
@NonNull
|
|
public Builder setDeviceAddress(@Nullable MacAddress deviceAddress) {
|
|
if (deviceAddress == null) {
|
|
mDeviceAddress = MAC_ANY_ADDRESS;
|
|
} else {
|
|
mDeviceAddress = deviceAddress;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify the network name, a.k.a. group name,
|
|
* for creating or joining a group.
|
|
* <p>
|
|
* A network name shall begin with "DIRECT-xy". x and y are selected
|
|
* from the following character set: upper case letters, lower case
|
|
* letters and numbers. Any byte values allowed for an SSID according to
|
|
* IEEE802.11-2012 [1] may be included after the string "DIRECT-xy"
|
|
* (including none).
|
|
* <p>
|
|
* Must be called - an empty network name or an network name
|
|
* not conforming to the P2P Group ID naming rule is not valid.
|
|
*
|
|
* @param networkName network name of a group.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
*/
|
|
@NonNull
|
|
public Builder setNetworkName(@NonNull String networkName) {
|
|
if (TextUtils.isEmpty(networkName)) {
|
|
throw new IllegalArgumentException(
|
|
"network name must be non-empty.");
|
|
}
|
|
if (networkName.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
|
|
throw new IllegalArgumentException(
|
|
"network name exceeds " + MAX_SSID_BYTES + " bytes.");
|
|
}
|
|
try {
|
|
if (!networkName.matches("^DIRECT-[a-zA-Z0-9]{2}.*")) {
|
|
throw new IllegalArgumentException(
|
|
"network name must starts with the prefix DIRECT-xy.");
|
|
}
|
|
} catch (PatternSyntaxException e) {
|
|
// can never happen (fixed pattern)
|
|
}
|
|
mNetworkName = networkName;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify the passphrase for creating or joining a group.
|
|
* <p>
|
|
* The passphrase must be an ASCII string whose length is between 8
|
|
* and 63.
|
|
* <p>
|
|
* Must be called - an empty passphrase is not valid.
|
|
*
|
|
* @param passphrase the passphrase of a group.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
*/
|
|
@NonNull
|
|
public Builder setPassphrase(@NonNull String passphrase) {
|
|
if (TextUtils.isEmpty(passphrase)) {
|
|
throw new IllegalArgumentException(
|
|
"passphrase must be non-empty.");
|
|
}
|
|
if (passphrase.length() < 8 || passphrase.length() > 63) {
|
|
throw new IllegalArgumentException(
|
|
"The length of a passphrase must be between 8 and 63.");
|
|
}
|
|
mPassphrase = passphrase;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify the band to use for creating the group or joining the group. The band should
|
|
* be {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ} or
|
|
* {@link #GROUP_OWNER_BAND_AUTO}.
|
|
* <p>
|
|
* When creating a group as Group Owner using {@link
|
|
* WifiP2pManager#createGroup(WifiP2pManager.Channel,
|
|
* WifiP2pConfig, WifiP2pManager.ActionListener)},
|
|
* specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to pick the operating
|
|
* frequency from all supported bands.
|
|
* Specifying {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ}
|
|
* only allows the system to pick the operating frequency in the specified band.
|
|
* If the Group Owner cannot create a group in the specified band, the operation will fail.
|
|
* <p>
|
|
* When joining a group as Group Client using {@link
|
|
* WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
|
|
* WifiP2pManager.ActionListener)},
|
|
* specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to scan all supported
|
|
* frequencies to find the desired group. Specifying {@link #GROUP_OWNER_BAND_2GHZ} or
|
|
* {@link #GROUP_OWNER_BAND_5GHZ} only allows the system to scan the specified band.
|
|
* <p>
|
|
* {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
|
|
* mutually exclusive. Setting operating band and frequency both is invalid.
|
|
* <p>
|
|
* Optional. {@link #GROUP_OWNER_BAND_AUTO} by default.
|
|
*
|
|
* @param band the operating band of the group.
|
|
* This should be one of {@link #GROUP_OWNER_BAND_AUTO},
|
|
* {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
*/
|
|
@NonNull
|
|
public Builder setGroupOperatingBand(@GroupOperatingBandType int band) {
|
|
switch (band) {
|
|
case GROUP_OWNER_BAND_AUTO:
|
|
case GROUP_OWNER_BAND_2GHZ:
|
|
case GROUP_OWNER_BAND_5GHZ:
|
|
mGroupOperatingBand = band;
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Invalid constant for the group operating band!");
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify the frequency, in MHz, to use for creating the group or joining the group.
|
|
* <p>
|
|
* When creating a group as Group Owner using {@link WifiP2pManager#createGroup(
|
|
* WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
|
|
* specifying a frequency only allows the system to pick the specified frequency.
|
|
* If the Group Owner cannot create a group at the specified frequency,
|
|
* the operation will fail.
|
|
* When not specifying a frequency, it allows the system to pick operating frequency
|
|
* from all supported bands.
|
|
* <p>
|
|
* When joining a group as Group Client using {@link WifiP2pManager#connect(
|
|
* WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
|
|
* specifying a frequency only allows the system to scan the specified frequency.
|
|
* If the frequency is not supported or invalid, the operation will fail.
|
|
* When not specifying a frequency, it allows the system to scan all supported
|
|
* frequencies to find the desired group.
|
|
* <p>
|
|
* {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
|
|
* mutually exclusive. Setting operating band and frequency both is invalid.
|
|
* <p>
|
|
* Optional. 0 by default.
|
|
*
|
|
* @param frequency the operating frequency of the group.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
*/
|
|
@NonNull
|
|
public Builder setGroupOperatingFrequency(int frequency) {
|
|
if (frequency < 0) {
|
|
throw new IllegalArgumentException(
|
|
"Invalid group operating frequency!");
|
|
}
|
|
mGroupOperatingFrequency = frequency;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify that the group configuration be persisted (i.e. saved).
|
|
* By default the group configuration will not be saved.
|
|
* <p>
|
|
* Optional. false by default.
|
|
*
|
|
* @param persistent is this group persistent group.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
*/
|
|
@NonNull
|
|
public Builder enablePersistentMode(boolean persistent) {
|
|
if (persistent) {
|
|
mNetId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
|
|
} else {
|
|
mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify the IP provisioning mode when joining a group as a group client. The IP
|
|
* provisioning mode should be {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP} or
|
|
* {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL}.
|
|
* <p>
|
|
* When joining a group as group client using {@link
|
|
* WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
|
|
* WifiP2pManager.ActionListener)},
|
|
* specifying {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP} directs the system to
|
|
* assign a IPv4 to the group client using DHCP. Specifying
|
|
* {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL} directs the system to assign
|
|
* a link-local IPv6 to the group client.
|
|
* <p>
|
|
* Optional. {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP} by default.
|
|
* <p>
|
|
*
|
|
* If {@link WifiP2pManager#isGroupOwnerIPv6LinkLocalAddressProvided()} is {@code true} and
|
|
* {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL} is used then the system will
|
|
* discover the group owner's IPv6 link-local address and broadcast it using the
|
|
* {@link WifiP2pManager#EXTRA_WIFI_P2P_INFO} extra of the
|
|
* {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} broadcast. Otherwise, if
|
|
* {@link WifiP2pManager#isGroupOwnerIPv6LinkLocalAddressProvided()} is
|
|
* {@code false} then the group owner's IPv6 link-local address is not discovered and it is
|
|
* the responsibility of the caller to obtain it in some other way, e.g. via out-of-band
|
|
* communication.
|
|
*
|
|
* @param groupClientIpProvisioningMode the IP provisioning mode of the group client.
|
|
* This should be one of {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP},
|
|
* {@link #GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL}.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
* @see WifiP2pManager#isGroupOwnerIPv6LinkLocalAddressProvided()
|
|
*/
|
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
|
@NonNull
|
|
public Builder setGroupClientIpProvisioningMode(
|
|
@GroupClientIpProvisioningMode int groupClientIpProvisioningMode) {
|
|
// Since group client IP provisioning modes use NetworkStack functionalities introduced
|
|
// in T, hence we need at least T sdk for this to be supported.
|
|
if (!SdkLevel.isAtLeastT()) {
|
|
throw new UnsupportedOperationException(
|
|
"IPv6 link-local provisioning not supported");
|
|
}
|
|
switch (groupClientIpProvisioningMode) {
|
|
case GROUP_CLIENT_IP_PROVISIONING_MODE_IPV4_DHCP:
|
|
case GROUP_CLIENT_IP_PROVISIONING_MODE_IPV6_LINK_LOCAL:
|
|
mGroupClientIpProvisioningMode = groupClientIpProvisioningMode;
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Invalid constant for the group client IP provisioning mode!");
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Specify that the device wants to join an existing group as client.
|
|
* Usually group owner sets the group owner capability bit in beacons/probe responses. But
|
|
* there are deployed devices which don't set the group owner capability bit.
|
|
* This API is for applications which can get the peer group owner capability via OOB
|
|
* (out of band) mechanisms and forcefully trigger the join existing group logic.
|
|
* <p>
|
|
* Optional. false by default.
|
|
*
|
|
* @param join true to forcefully trigger the join existing group logic, false to let
|
|
* device decide whether to join a group or form a group.
|
|
* @return The builder to facilitate chaining
|
|
* {@code builder.setXXX(..).setXXX(..)}.
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
@NonNull
|
|
public Builder setJoinExistingGroup(boolean join) {
|
|
mJoinExistingGroup = join;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Build {@link WifiP2pConfig} given the current requests made on the builder.
|
|
* @return {@link WifiP2pConfig} constructed based on builder method calls.
|
|
*/
|
|
@NonNull
|
|
public WifiP2pConfig build() {
|
|
if ((TextUtils.isEmpty(mNetworkName) && !TextUtils.isEmpty(mPassphrase))
|
|
|| (!TextUtils.isEmpty(mNetworkName) && TextUtils.isEmpty(mPassphrase))) {
|
|
throw new IllegalStateException(
|
|
"network name and passphrase must be non-empty or empty both.");
|
|
}
|
|
if (TextUtils.isEmpty(mNetworkName)
|
|
&& mDeviceAddress.equals(MAC_ANY_ADDRESS)) {
|
|
throw new IllegalStateException(
|
|
"peer address must be set if network name and pasphrase are not set.");
|
|
}
|
|
|
|
if (mGroupOperatingFrequency > 0 && mGroupOperatingBand > 0) {
|
|
throw new IllegalStateException(
|
|
"Preferred frequency and band are mutually exclusive.");
|
|
}
|
|
|
|
WifiP2pConfig config = new WifiP2pConfig();
|
|
config.deviceAddress = mDeviceAddress.toString();
|
|
config.networkName = mNetworkName;
|
|
config.passphrase = mPassphrase;
|
|
config.groupOwnerBand = GROUP_OWNER_BAND_AUTO;
|
|
if (mGroupOperatingFrequency > 0) {
|
|
config.groupOwnerBand = mGroupOperatingFrequency;
|
|
} else if (mGroupOperatingBand > 0) {
|
|
config.groupOwnerBand = mGroupOperatingBand;
|
|
}
|
|
config.netId = mNetId;
|
|
config.mGroupClientIpProvisioningMode = mGroupClientIpProvisioningMode;
|
|
config.mJoinExistingGroup = mJoinExistingGroup;
|
|
return config;
|
|
}
|
|
}
|
|
}
|