/* * Copyright (C) 2012 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.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Locale; /** * A class representing Wifi Display information for a device. * * See Wifi Display technical specification v1.0.0, section 5.1.2. * See Wifi Display technical specification v2.0.0, section 5.1.12 for Wifi Display R2. */ public final class WifiP2pWfdInfo implements Parcelable { private boolean mEnabled; /** Device information bitmap */ private int mDeviceInfo; /** R2 Device information bitmap */ private int mR2DeviceInfo = -1; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "DEVICE_TYPE_" }, value = { DEVICE_TYPE_WFD_SOURCE, DEVICE_TYPE_PRIMARY_SINK, DEVICE_TYPE_SECONDARY_SINK, DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK}) public @interface DeviceType {} /** The device is a Wifi Display Source. */ public static final int DEVICE_TYPE_WFD_SOURCE = 0; /** The device is a primary sink. */ public static final int DEVICE_TYPE_PRIMARY_SINK = 1; /** The device is a secondary sink. This type is only supported by R1. */ public static final int DEVICE_TYPE_SECONDARY_SINK = 2; /** The device is dual-role capable i.e. either a WFD source or a primary sink. */ public static final int DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK = 3; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "PREFERRED_CONNECTIVITY_" }, value = { PREFERRED_CONNECTIVITY_P2P, PREFERRED_CONNECTIVITY_TDLS}) public @interface PreferredConnectivity {} /** Wifi Display (WFD) preferred connectivity is Wifi Direct (P2P). */ public static final int PREFERRED_CONNECTIVITY_P2P = 0; /** Wifi Display (WFD) preferred connectivity is TDLS. */ public static final int PREFERRED_CONNECTIVITY_TDLS = 1; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = {"DEVICE_INFO_"}, value = { DEVICE_INFO_DEVICE_TYPE_MASK, DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SOURCE, DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SINK, DEVICE_INFO_SESSION_AVAILABLE_MASK, DEVICE_INFO_WFD_SERVICE_DISCOVERY_SUPPORT, DEVICE_INFO_PREFERRED_CONNECTIVITY_MASK, DEVICE_INFO_CONTENT_PROTECTION_SUPPORT, DEVICE_INFO_TIME_SYNCHRONIZATION_SUPPORT, DEVICE_INFO_AUDIO_UNSUPPORTED_AT_PRIMARY_SINK, DEVICE_INFO_AUDIO_ONLY_SUPPORT_AT_SOURCE, DEVICE_INFO_TDLS_PERSISTENT_GROUP, DEVICE_INFO_TDLS_PERSISTENT_GROUP_REINVOKE}) public @interface DeviceInfoMask {} /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = {"DEVICE_INFO_"}, value = {DEVICE_INFO_DEVICE_TYPE_MASK}) public @interface R2DeviceInfoMask {} /** * {@link #getDeviceInfo()} & {@link #DEVICE_INFO_DEVICE_TYPE_MASK} is one of * {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK}, * {@link #DEVICE_TYPE_SECONDARY_SINK} or {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK}. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement and * 5.1.12 WFD R2 Device Information Subelement in Wifi Display Technical Specification. */ public static final int DEVICE_INFO_DEVICE_TYPE_MASK = 1 << 1 | 1 << 0; /** * Bit field for {@link #getDeviceInfo()}, indicates that coupled sink is supported at source. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SOURCE = 1 << 2; /** * Bit field for {@link #getDeviceInfo()}, indicates that coupled sink is supporeted at sink. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SINK = 1 << 3; private static final int SESSION_AVAILABLE_BIT1 = 1 << 4; private static final int SESSION_AVAILABLE_BIT2 = 1 << 5; /** * Bit field for {@link #getDeviceInfo()}, indicates that Wifi Display session is available. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_SESSION_AVAILABLE_MASK = SESSION_AVAILABLE_BIT2 | SESSION_AVAILABLE_BIT1; /** * Bit field for {@link #getDeviceInfo()}, indicates that Wifi Display discovery is supported. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_WFD_SERVICE_DISCOVERY_SUPPORT = 1 << 6; /** * Bit field for {@link #getDeviceInfo()}, indicate the preferred connectifity for Wifi Display. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. * The value is one of {@link #PREFERRED_CONNECTIVITY_P2P} or * {@link #PREFERRED_CONNECTIVITY_TDLS}. */ public static final int DEVICE_INFO_PREFERRED_CONNECTIVITY_MASK = 1 << 7; /** * Bit field for {@link #getDeviceInfo()}, indicate the support of Content Protection * using the HDCP system 2.0/2.1. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_CONTENT_PROTECTION_SUPPORT = 1 << 8; /** * Bit field for {@link #getDeviceInfo()}, indicate time synchronization * using 802.1AS is supported. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_TIME_SYNCHRONIZATION_SUPPORT = 1 << 9; /** * Bit field for {@link #getDeviceInfo()}, indicate audio is not supported at primary sink. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_AUDIO_UNSUPPORTED_AT_PRIMARY_SINK = 1 << 10; /** * Bit field for {@link #getDeviceInfo()}, indicate audo is only supported at source. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_AUDIO_ONLY_SUPPORT_AT_SOURCE = 1 << 11; /** Bit field for {@link #getDeviceInfo()}, indicate that TDLS persistent group is intended. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_TDLS_PERSISTENT_GROUP = 1 << 12; /** Bit field for {@link #getDeviceInfo()}, indicate that the request is for * re-invocation of TDLS persistent group. * * The bit definition is listed in 5.1.2 WFD Device Information Subelement in * Wifi Display Technical Specification. */ public static final int DEVICE_INFO_TDLS_PERSISTENT_GROUP_REINVOKE = 1 << 13; private int mCtrlPort; private int mMaxThroughput; /** Default constructor. */ public WifiP2pWfdInfo() {} /** @hide */ @UnsupportedAppUsage public WifiP2pWfdInfo(int devInfo, int ctrlPort, int maxTput) { mEnabled = true; mDeviceInfo = devInfo; mCtrlPort = ctrlPort; mMaxThroughput = maxTput; mR2DeviceInfo = -1; } /** * Return R1 raw device info, See * Wifi Display technical specification v1.0.0, section 5.1.2. * Access bit fields by DEVICE_INFO_* constants. */ @DeviceInfoMask public int getDeviceInfo() { return mDeviceInfo; } /** * Set Wifi Display R2 raw device info, see * Wifi Display technical specification v2.0.0, section 5.1.12. * Access bit fields by {@link #DEVICE_INFO_DEVICE_TYPE_MASK}. * * @param r2DeviceInfo the raw data of R2 device info. * @hide */ public void setR2DeviceInfo(int r2DeviceInfo) { mR2DeviceInfo = r2DeviceInfo; } /** * Return R2 raw device info, See * Wifi Display technical specification v2.0.0, section 5.1.12. * Access bit fields by {@link #DEVICE_INFO_DEVICE_TYPE_MASK}. */ @R2DeviceInfoMask public int getR2DeviceInfo() { return mR2DeviceInfo; } /** Returns true is Wifi Display is enabled, false otherwise. */ public boolean isEnabled() { return mEnabled; } /** Returns true is Wifi Display R2 is enabled, false otherwise. */ public boolean isR2Supported() { return mR2DeviceInfo >= 0; } /** * Sets whether Wifi Display should be enabled. * * @param enabled true to enable Wifi Display, false to disable */ public void setEnabled(boolean enabled) { mEnabled = enabled; } /** * Sets the type of the Wifi Display R2 device. * See Wifi Display technical specification v2.0.0, section 5.1.12 for Wifi Display R2. * Before calling this API, call {@link WifiManager#isWifiDisplayR2Supported() * to know whether Wifi Display R2 is supported or not. * If R2 info was filled without Wifi Display R2 support, * {@link WifiP2pManager#setWfdInfo(Channel, WifiP2pWfdInfo, ActionListener) * would fail. * * @param deviceType One of {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK}, * {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK} * @return true if the device type was successfully set, false otherwise */ @RequiresApi(Build.VERSION_CODES.S) public boolean setR2DeviceType(@DeviceType int deviceType) { if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } if (DEVICE_TYPE_WFD_SOURCE != deviceType && DEVICE_TYPE_PRIMARY_SINK != deviceType && DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK != deviceType) { return false; } if (!isR2Supported()) mR2DeviceInfo = 0; mR2DeviceInfo &= ~DEVICE_INFO_DEVICE_TYPE_MASK; mR2DeviceInfo |= deviceType; return true; } /** * Get the type of the device. * One of {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK}, * {@link #DEVICE_TYPE_SECONDARY_SINK}, {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK} */ @DeviceType public int getDeviceType() { return mDeviceInfo & DEVICE_INFO_DEVICE_TYPE_MASK; } /** * Get the type of the R2 device. * One of {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK}, * or {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK} */ @DeviceType public int getR2DeviceType() { return mR2DeviceInfo & DEVICE_INFO_DEVICE_TYPE_MASK; } /** * Sets the type of the device. * * @param deviceType One of {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK}, * {@link #DEVICE_TYPE_SECONDARY_SINK}, {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK} * @return true if the device type was successfully set, false otherwise */ public boolean setDeviceType(@DeviceType int deviceType) { if (DEVICE_TYPE_WFD_SOURCE <= deviceType && deviceType <= DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK) { mDeviceInfo &= ~DEVICE_INFO_DEVICE_TYPE_MASK; mDeviceInfo |= deviceType; return true; } return false; } /** Returns true if a session is available, false otherwise. */ public boolean isSessionAvailable() { return (mDeviceInfo & DEVICE_INFO_SESSION_AVAILABLE_MASK) != 0; } /** * Sets whether a session is available. * * @param enabled true to indicate that a session is available, false otherwise. */ public void setSessionAvailable(boolean enabled) { if (enabled) { mDeviceInfo |= SESSION_AVAILABLE_BIT1; mDeviceInfo &= ~SESSION_AVAILABLE_BIT2; } else { mDeviceInfo &= ~DEVICE_INFO_SESSION_AVAILABLE_MASK; } } /** * @return true if Content Protection using the HDCP system 2.0/2.1 is supported. */ public boolean isContentProtectionSupported() { return (mDeviceInfo & DEVICE_INFO_CONTENT_PROTECTION_SUPPORT) != 0; } /** * Sets whether Content Protection using the HDCP system 2.0/2.1 is supported. * * @param enabled true to indicate that Content Protection is supported, false otherwise. */ public void setContentProtectionSupported(boolean enabled) { if (enabled) { mDeviceInfo |= DEVICE_INFO_CONTENT_PROTECTION_SUPPORT; } else { mDeviceInfo &= ~DEVICE_INFO_CONTENT_PROTECTION_SUPPORT; } } /** * Returns true if Coupled Sink is supported by WFD Source. * See Wifi Display technical specification v1.0.0, section 4.9. */ public boolean isCoupledSinkSupportedAtSource() { return (mDeviceInfo & DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SOURCE) != 0; } /** * Sets whether Coupled Sink feature is supported by WFD Source. * See Wifi Display technical specification v1.0.0, section 4.9. * * @param enabled true to indicate support for coupled sink, false otherwise. */ public void setCoupledSinkSupportAtSource(boolean enabled) { if (enabled) { mDeviceInfo |= DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SOURCE; } else { mDeviceInfo &= ~DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SOURCE; } } /** * Returns true if Coupled Sink is supported by WFD Sink. * See Wifi Display technical specification v1.0.0, section 4.9. */ public boolean isCoupledSinkSupportedAtSink() { return (mDeviceInfo & DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SINK) != 0; } /** * Sets whether Coupled Sink feature is supported by WFD Sink. * See Wifi Display technical specification v1.0.0, section 4.9. * * @param enabled true to indicate support for coupled sink, false otherwise. */ public void setCoupledSinkSupportAtSink(boolean enabled) { if (enabled) { mDeviceInfo |= DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SINK; } else { mDeviceInfo &= ~DEVICE_INFO_COUPLED_SINK_SUPPORT_AT_SINK; } } /** Returns the TCP port at which the WFD Device listens for RTSP messages. */ public int getControlPort() { return mCtrlPort; } /** Sets the TCP port at which the WFD Device listens for RTSP messages. */ public void setControlPort(@IntRange(from = 0) int port) { mCtrlPort = port; } /** Sets the maximum average throughput capability of the WFD Device, in megabits/second. */ public void setMaxThroughput(@IntRange(from = 0) int maxThroughput) { mMaxThroughput = maxThroughput; } /** Returns the maximum average throughput capability of the WFD Device, in megabits/second. */ public int getMaxThroughput() { return mMaxThroughput; } /** @hide */ public String getDeviceInfoHex() { return String.format( Locale.US, "%04x%04x%04x", mDeviceInfo, mCtrlPort, mMaxThroughput); } /** @hide */ public String getR2DeviceInfoHex() { return String.format(Locale.US, "%04x%04x", 2, mR2DeviceInfo); } @Override public String toString() { StringBuffer sbuf = new StringBuffer(); sbuf.append("WFD enabled: ").append(mEnabled); sbuf.append("WFD DeviceInfo: ").append(mDeviceInfo); sbuf.append("\n WFD CtrlPort: ").append(mCtrlPort); sbuf.append("\n WFD MaxThroughput: ").append(mMaxThroughput); sbuf.append("\n WFD R2 DeviceInfo: ").append(mR2DeviceInfo); return sbuf.toString(); } /** Implement the Parcelable interface */ public int describeContents() { return 0; } /** Copy constructor. */ public WifiP2pWfdInfo(@Nullable WifiP2pWfdInfo source) { if (source != null) { mEnabled = source.mEnabled; mDeviceInfo = source.mDeviceInfo; mCtrlPort = source.mCtrlPort; mMaxThroughput = source.mMaxThroughput; mR2DeviceInfo = source.mR2DeviceInfo; } } /** Implement the Parcelable interface */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mEnabled ? 1 : 0); dest.writeInt(mDeviceInfo); dest.writeInt(mCtrlPort); dest.writeInt(mMaxThroughput); dest.writeInt(mR2DeviceInfo); } private void readFromParcel(Parcel in) { mEnabled = (in.readInt() == 1); mDeviceInfo = in.readInt(); mCtrlPort = in.readInt(); mMaxThroughput = in.readInt(); mR2DeviceInfo = in.readInt(); } /** Implement the Parcelable interface */ public static final @NonNull Creator CREATOR = new Creator() { public WifiP2pWfdInfo createFromParcel(Parcel in) { WifiP2pWfdInfo device = new WifiP2pWfdInfo(); device.readFromParcel(in); return device; } public WifiP2pWfdInfo[] newArray(int size) { return new WifiP2pWfdInfo[size]; } }; }