1 /*
2  * Copyright (C) 2024 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 android.net.wifi;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.net.TetheringManager;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 
27 import com.android.modules.utils.build.SdkLevel;
28 import com.android.wifi.flags.Flags;
29 
30 import java.util.Objects;
31 
32 /**
33  * A class representing the current state of SoftAp.
34  * @see WifiManager.SoftApCallback#onStateChanged(SoftApState)
35  *
36  * @hide
37  */
38 @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
39 @SystemApi
40 public final class SoftApState implements Parcelable {
41 
42     @WifiManager.WifiApState
43     final int mState;
44     @WifiManager.SapStartFailure
45     final int mFailureReason;
46     @Nullable
47     final TetheringManager.TetheringRequest mTetheringRequest;
48     @Nullable
49     final String mIface;
50 
51     /**
52      * SoftApState constructor.
53      *
54      * @param state Current state of the Soft AP.
55      * @param failureReason Failure reason if the current state is
56      *                      {@link WifiManager#WIFI_AP_STATE_FAILED}.
57      * @param tetheringRequest TetheringRequest if one was specified when Soft AP was requested,
58      *                         else {@code null}.
59      * @param iface Interface name if an interface was created, else {@code null}.
60      * @hide
61      */
SoftApState(@ifiManager.WifiApState int state, @WifiManager.SapStartFailure int failureReason, @Nullable TetheringManager.TetheringRequest tetheringRequest, @Nullable String iface)62     public SoftApState(@WifiManager.WifiApState int state,
63             @WifiManager.SapStartFailure int failureReason,
64             @Nullable TetheringManager.TetheringRequest tetheringRequest,
65             @Nullable String iface) {
66         mState = state;
67         mFailureReason = failureReason;
68         mTetheringRequest = tetheringRequest;
69         mIface = iface;
70     }
71 
SoftApState(@onNull Parcel in)72     private SoftApState(@NonNull Parcel in) {
73         mState = in.readInt();
74         mFailureReason = in.readInt();
75         if (SdkLevel.isAtLeastV()) {
76             // TetheringRequest is parcelable starting in V.
77             mTetheringRequest = in.readParcelable(
78                     TetheringManager.TetheringRequest.class.getClassLoader());
79         } else {
80             mTetheringRequest = null;
81         }
82         mIface = in.readString();
83     }
84 
85     @Override
writeToParcel(@onNull Parcel dest, int flags)86     public void writeToParcel(@NonNull Parcel dest, int flags) {
87         dest.writeInt(mState);
88         dest.writeInt(mFailureReason);
89         if (SdkLevel.isAtLeastV()) {
90             // TetheringRequest is parcelable starting in V.
91             dest.writeParcelable(mTetheringRequest, flags);
92         }
93         dest.writeString(mIface);
94     }
95 
96     @Override
describeContents()97     public int describeContents() {
98         return 0;
99     }
100 
101     @NonNull
102     public static final Creator<SoftApState> CREATOR = new Creator<SoftApState>() {
103         @Override
104         @NonNull
105         public SoftApState createFromParcel(Parcel in) {
106             return new SoftApState(in);
107         }
108 
109         @Override
110         @NonNull
111         public SoftApState[] newArray(int size) {
112             return new SoftApState[size];
113         }
114     };
115 
116     /**
117      * Get the AP state.
118      *
119      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
120      *                {@link WifiManager#WIFI_AP_STATE_DISABLING},
121      *                {@link WifiManager#WIFI_AP_STATE_ENABLED},
122      *                {@link WifiManager#WIFI_AP_STATE_ENABLING},
123      *                {@link WifiManager#WIFI_AP_STATE_FAILED}
124      */
125     @WifiManager.WifiApState
getState()126     public int getState() {
127         return mState;
128     }
129 
130     /**
131      * Get the failure reason if the state is {@link WifiManager#WIFI_AP_STATE_FAILED}.
132      *
133      * @return One of {@link WifiManager#SAP_START_FAILURE_GENERAL},
134      *                {@link WifiManager#SAP_START_FAILURE_NO_CHANNEL},
135      *                {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION},
136      *                {@link WifiManager#SAP_START_FAILURE_USER_REJECTED}
137      * @throws IllegalStateException if the state is not {@link WifiManager#WIFI_AP_STATE_FAILED}.
138      */
139     @WifiManager.SapStartFailure
getFailureReason()140     public int getFailureReason() {
141         if (mState != WifiManager.WIFI_AP_STATE_FAILED) {
142             throw new IllegalStateException("Called getFailureReason() when state is not"
143                     + " WIFI_AP_STATE_FAILED. Actual state is " + mState);
144         }
145         return getFailureReasonInternal();
146     }
147 
148     /**
149      * @hide
150      */
151     @WifiManager.SapStartFailure
getFailureReasonInternal()152     public int getFailureReasonInternal() {
153         return mFailureReason;
154     }
155 
156     /**
157      * Gets the TetheringRequest of the Soft AP, if one was specified via
158      * {@link WifiManager#startTetheredHotspotRequest(TetheringManager.TetheringRequest)}.
159      * Otherwise, returns {@code null}.
160      */
161     @Nullable
getTetheringRequest()162     public TetheringManager.TetheringRequest getTetheringRequest() {
163         return mTetheringRequest;
164     }
165 
166     /**
167      * Gets the interface name of the Soft AP (e.g. "wlan0") once the Soft AP starts enabling, i.e.
168      * {@link #getState()} returns {@link WifiManager#WIFI_AP_STATE_ENABLING}). Returns {@code null}
169      * if the Soft AP hasn't started enabling yet, or if it failed with
170      * {@link WifiManager#WIFI_AP_STATE_FAILED} without starting enabling.
171      */
172     @Nullable
getIface()173     public String getIface() {
174         return mIface;
175     }
176 
177     @Override
toString()178     public String toString() {
179         return "SoftApState{"
180                 + "mState=" + mState
181                 + ", mFailureReason=" + mFailureReason
182                 + ", mTetheringRequest=" + mTetheringRequest
183                 + ", mIface='" + mIface + '\''
184                 + '}';
185     }
186 
187     @Override
equals(Object o)188     public boolean equals(Object o) {
189         if (this == o) return true;
190         if (!(o instanceof SoftApState stateInfo)) return false;
191         return mState == stateInfo.mState && mFailureReason == stateInfo.mFailureReason
192                 && Objects.equals(mTetheringRequest, stateInfo.mTetheringRequest)
193                 && Objects.equals(mIface, stateInfo.mIface);
194     }
195 
196     @Override
hashCode()197     public int hashCode() {
198         return Objects.hash(mState, mFailureReason, mTetheringRequest, mIface);
199     }
200 }
201