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