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 android.net;
18 
19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Objects;
33 
34 /**
35  * Information on a tethered downstream client.
36  * @hide
37  */
38 @SystemApi
39 @SystemApi(client = MODULE_LIBRARIES)
40 @TestApi
41 public final class TetheredClient implements Parcelable {
42     @NonNull
43     private final MacAddress mMacAddress;
44     @NonNull
45     private final List<AddressInfo> mAddresses;
46     // TODO: use an @IntDef here
47     private final int mTetheringType;
48 
TetheredClient(@onNull MacAddress macAddress, @NonNull Collection<AddressInfo> addresses, int tetheringType)49     public TetheredClient(@NonNull MacAddress macAddress,
50             @NonNull Collection<AddressInfo> addresses, int tetheringType) {
51         mMacAddress = macAddress;
52         mAddresses = new ArrayList<>(addresses);
53         mTetheringType = tetheringType;
54     }
55 
TetheredClient(@onNull Parcel in)56     private TetheredClient(@NonNull Parcel in) {
57         this(in.readParcelable(null), in.createTypedArrayList(AddressInfo.CREATOR), in.readInt());
58     }
59 
60     @Override
writeToParcel(@onNull Parcel dest, int flags)61     public void writeToParcel(@NonNull Parcel dest, int flags) {
62         dest.writeParcelable(mMacAddress, flags);
63         dest.writeTypedList(mAddresses);
64         dest.writeInt(mTetheringType);
65     }
66 
67     /**
68      * Get the MAC address used to identify the client.
69      */
70     @NonNull
getMacAddress()71     public MacAddress getMacAddress() {
72         return mMacAddress;
73     }
74 
75     /**
76      * Get information on the list of addresses that are associated with the client.
77      */
78     @NonNull
getAddresses()79     public List<AddressInfo> getAddresses() {
80         return new ArrayList<>(mAddresses);
81     }
82 
83     /**
84      * Get the type of tethering used by the client.
85      * @return one of the {@code TetheringManager#TETHERING_*} constants.
86      */
getTetheringType()87     public int getTetheringType() {
88         return mTetheringType;
89     }
90 
91     /**
92      * Return a new {@link TetheredClient} that has all the attributes of this instance, plus the
93      * {@link AddressInfo} of the provided {@link TetheredClient}.
94      *
95      * <p>Duplicate addresses are removed.
96      * @hide
97      */
addAddresses(@onNull TetheredClient other)98     public TetheredClient addAddresses(@NonNull TetheredClient other) {
99         final LinkedHashSet<AddressInfo> newAddresses = new LinkedHashSet<>(
100                 mAddresses.size() + other.mAddresses.size());
101         newAddresses.addAll(mAddresses);
102         newAddresses.addAll(other.mAddresses);
103         return new TetheredClient(mMacAddress, newAddresses, mTetheringType);
104     }
105 
106     @Override
hashCode()107     public int hashCode() {
108         return Objects.hash(mMacAddress, mAddresses, mTetheringType);
109     }
110 
111     @Override
equals(@ullable Object obj)112     public boolean equals(@Nullable Object obj) {
113         if (!(obj instanceof TetheredClient)) return false;
114         final TetheredClient other = (TetheredClient) obj;
115         return mMacAddress.equals(other.mMacAddress)
116                 && mAddresses.equals(other.mAddresses)
117                 && mTetheringType == other.mTetheringType;
118     }
119 
120     /**
121      * Information on an lease assigned to a tethered client.
122      */
123     public static final class AddressInfo implements Parcelable {
124         @NonNull
125         private final LinkAddress mAddress;
126         @Nullable
127         private final String mHostname;
128 
129         /** @hide */
AddressInfo(@onNull LinkAddress address, @Nullable String hostname)130         public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) {
131             this.mAddress = address;
132             this.mHostname = hostname;
133         }
134 
AddressInfo(Parcel in)135         private AddressInfo(Parcel in) {
136             this(in.readParcelable(null),  in.readString());
137         }
138 
139         @Override
writeToParcel(@onNull Parcel dest, int flags)140         public void writeToParcel(@NonNull Parcel dest, int flags) {
141             dest.writeParcelable(mAddress, flags);
142             dest.writeString(mHostname);
143         }
144 
145         /**
146          * Get the link address (including prefix length and lifetime) used by the client.
147          *
148          * This may be an IPv4 or IPv6 address.
149          */
150         @NonNull
getAddress()151         public LinkAddress getAddress() {
152             return mAddress;
153         }
154 
155         /**
156          * Get the hostname that was advertised by the client when obtaining its address, if any.
157          */
158         @Nullable
getHostname()159         public String getHostname() {
160             return mHostname;
161         }
162 
163         /**
164          * Get the expiration time of the address assigned to the client.
165          * @hide
166          */
getExpirationTime()167         public long getExpirationTime() {
168             return mAddress.getExpirationTime();
169         }
170 
171         @Override
describeContents()172         public int describeContents() {
173             return 0;
174         }
175 
176         @Override
hashCode()177         public int hashCode() {
178             return Objects.hash(mAddress, mHostname);
179         }
180 
181         @Override
equals(@ullable Object obj)182         public boolean equals(@Nullable Object obj) {
183             if (!(obj instanceof AddressInfo)) return false;
184             final AddressInfo other = (AddressInfo) obj;
185             // Use .equals() for addresses as all changes, including address expiry changes,
186             // should be included.
187             return other.mAddress.equals(mAddress)
188                     && Objects.equals(mHostname, other.mHostname);
189         }
190 
191         @NonNull
192         public static final Creator<AddressInfo> CREATOR = new Creator<AddressInfo>() {
193             @NonNull
194             @Override
195             public AddressInfo createFromParcel(@NonNull Parcel in) {
196                 return new AddressInfo(in);
197             }
198 
199             @NonNull
200             @Override
201             public AddressInfo[] newArray(int size) {
202                 return new AddressInfo[size];
203             }
204         };
205 
206         @NonNull
207         @Override
toString()208         public String toString() {
209             return "AddressInfo {"
210                     + mAddress
211                     + (mHostname != null ? ", hostname " + mHostname : "")
212                     + "}";
213         }
214     }
215 
216     @Override
describeContents()217     public int describeContents() {
218         return 0;
219     }
220 
221     @NonNull
222     public static final Creator<TetheredClient> CREATOR = new Creator<TetheredClient>() {
223         @NonNull
224         @Override
225         public TetheredClient createFromParcel(@NonNull Parcel in) {
226             return new TetheredClient(in);
227         }
228 
229         @NonNull
230         @Override
231         public TetheredClient[] newArray(int size) {
232             return new TetheredClient[size];
233         }
234     };
235 
236     @NonNull
237     @Override
toString()238     public String toString() {
239         return "TetheredClient {hwAddr " + mMacAddress
240                 + ", addresses " + mAddresses
241                 + ", tetheringType " + mTetheringType
242                 + "}";
243     }
244 }
245