1 /* 2 * Copyright (C) 2019 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 android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.util.Objects; 29 30 /** 31 * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt. 32 * @hide 33 */ 34 @SystemApi 35 public final class CaptivePortalData implements Parcelable { 36 private final long mRefreshTimeMillis; 37 @Nullable 38 private final Uri mUserPortalUrl; 39 @Nullable 40 private final Uri mVenueInfoUrl; 41 private final boolean mIsSessionExtendable; 42 private final long mByteLimit; 43 private final long mExpiryTimeMillis; 44 private final boolean mCaptive; 45 private final String mVenueFriendlyName; 46 private final int mVenueInfoUrlSource; 47 private final int mUserPortalUrlSource; 48 49 /** @hide */ 50 @Retention(RetentionPolicy.SOURCE) 51 @IntDef(prefix = {"CAPTIVE_PORTAL_DATA_SOURCE_"}, value = { 52 CAPTIVE_PORTAL_DATA_SOURCE_OTHER, 53 CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT}) 54 public @interface CaptivePortalDataSource {} 55 56 /** 57 * Source of information: Other (default) 58 */ 59 public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; 60 61 /** 62 * Source of information: Wi-Fi Passpoint 63 */ 64 public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; 65 CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive, CharSequence venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource)66 private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, 67 boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive, 68 CharSequence venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) { 69 mRefreshTimeMillis = refreshTimeMillis; 70 mUserPortalUrl = userPortalUrl; 71 mVenueInfoUrl = venueInfoUrl; 72 mIsSessionExtendable = isSessionExtendable; 73 mByteLimit = byteLimit; 74 mExpiryTimeMillis = expiryTimeMillis; 75 mCaptive = captive; 76 mVenueFriendlyName = venueFriendlyName == null ? null : venueFriendlyName.toString(); 77 mVenueInfoUrlSource = venueInfoUrlSource; 78 mUserPortalUrlSource = userPortalUrlSource; 79 } 80 CaptivePortalData(Parcel p)81 private CaptivePortalData(Parcel p) { 82 this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(), 83 p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(), 84 p.readInt()); 85 } 86 87 @Override describeContents()88 public int describeContents() { 89 return 0; 90 } 91 92 @Override writeToParcel(@onNull Parcel dest, int flags)93 public void writeToParcel(@NonNull Parcel dest, int flags) { 94 dest.writeLong(mRefreshTimeMillis); 95 dest.writeParcelable(mUserPortalUrl, 0); 96 dest.writeParcelable(mVenueInfoUrl, 0); 97 dest.writeBoolean(mIsSessionExtendable); 98 dest.writeLong(mByteLimit); 99 dest.writeLong(mExpiryTimeMillis); 100 dest.writeBoolean(mCaptive); 101 dest.writeString(mVenueFriendlyName); 102 dest.writeInt(mVenueInfoUrlSource); 103 dest.writeInt(mUserPortalUrlSource); 104 } 105 106 /** 107 * A builder to create new {@link CaptivePortalData}. 108 */ 109 public static class Builder { 110 private long mRefreshTime; 111 private Uri mUserPortalUrl; 112 private Uri mVenueInfoUrl; 113 private boolean mIsSessionExtendable; 114 private long mBytesRemaining = -1; 115 private long mExpiryTime = -1; 116 private boolean mCaptive; 117 private CharSequence mVenueFriendlyName; 118 private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER; 119 private @CaptivePortalDataSource int mUserPortalUrlSource = 120 CAPTIVE_PORTAL_DATA_SOURCE_OTHER; 121 122 /** 123 * Create an empty builder. 124 */ Builder()125 public Builder() {} 126 127 /** 128 * Create a builder copying all data from existing {@link CaptivePortalData}. 129 */ Builder(@ullable CaptivePortalData data)130 public Builder(@Nullable CaptivePortalData data) { 131 if (data == null) return; 132 setRefreshTime(data.mRefreshTimeMillis) 133 .setUserPortalUrl(data.mUserPortalUrl, data.mUserPortalUrlSource) 134 .setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource) 135 .setSessionExtendable(data.mIsSessionExtendable) 136 .setBytesRemaining(data.mByteLimit) 137 .setExpiryTime(data.mExpiryTimeMillis) 138 .setCaptive(data.mCaptive) 139 .setVenueFriendlyName(data.mVenueFriendlyName); 140 } 141 142 /** 143 * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. 144 */ 145 @NonNull setRefreshTime(long refreshTime)146 public Builder setRefreshTime(long refreshTime) { 147 mRefreshTime = refreshTime; 148 return this; 149 } 150 151 /** 152 * Set the URL to be used for users to login to the portal, if captive. 153 */ 154 @NonNull setUserPortalUrl(@ullable Uri userPortalUrl)155 public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) { 156 return setUserPortalUrl(userPortalUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER); 157 } 158 159 /** 160 * Set the URL to be used for users to login to the portal, if captive, and the source of 161 * the data, see {@link CaptivePortalDataSource} 162 */ 163 @NonNull setUserPortalUrl(@ullable Uri userPortalUrl, @CaptivePortalDataSource int source)164 public Builder setUserPortalUrl(@Nullable Uri userPortalUrl, 165 @CaptivePortalDataSource int source) { 166 mUserPortalUrl = userPortalUrl; 167 mUserPortalUrlSource = source; 168 return this; 169 } 170 171 /** 172 * Set the URL that can be used by users to view information about the network venue. 173 */ 174 @NonNull setVenueInfoUrl(@ullable Uri venueInfoUrl)175 public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) { 176 return setVenueInfoUrl(venueInfoUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER); 177 } 178 179 /** 180 * Set the URL that can be used by users to view information about the network venue, and 181 * the source of the data, see {@link CaptivePortalDataSource} 182 */ 183 @NonNull setVenueInfoUrl(@ullable Uri venueInfoUrl, @CaptivePortalDataSource int source)184 public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl, 185 @CaptivePortalDataSource int source) { 186 mVenueInfoUrl = venueInfoUrl; 187 mVenueInfoUrlSource = source; 188 return this; 189 } 190 191 /** 192 * Set whether the portal supports extending a user session on the portal URL page. 193 */ 194 @NonNull setSessionExtendable(boolean sessionExtendable)195 public Builder setSessionExtendable(boolean sessionExtendable) { 196 mIsSessionExtendable = sessionExtendable; 197 return this; 198 } 199 200 /** 201 * Set the number of bytes remaining on the network before the portal closes. 202 */ 203 @NonNull setBytesRemaining(long bytesRemaining)204 public Builder setBytesRemaining(long bytesRemaining) { 205 mBytesRemaining = bytesRemaining; 206 return this; 207 } 208 209 /** 210 * Set the time at the session will expire, as per {@link System#currentTimeMillis()}. 211 */ 212 @NonNull setExpiryTime(long expiryTime)213 public Builder setExpiryTime(long expiryTime) { 214 mExpiryTime = expiryTime; 215 return this; 216 } 217 218 /** 219 * Set whether the network is captive (portal closed). 220 */ 221 @NonNull setCaptive(boolean captive)222 public Builder setCaptive(boolean captive) { 223 mCaptive = captive; 224 return this; 225 } 226 227 /** 228 * Set the venue friendly name. 229 */ 230 @NonNull setVenueFriendlyName(@ullable CharSequence venueFriendlyName)231 public Builder setVenueFriendlyName(@Nullable CharSequence venueFriendlyName) { 232 mVenueFriendlyName = venueFriendlyName; 233 return this; 234 } 235 236 /** 237 * Create a new {@link CaptivePortalData}. 238 */ 239 @NonNull build()240 public CaptivePortalData build() { 241 return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl, 242 mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive, 243 mVenueFriendlyName, mVenueInfoUrlSource, 244 mUserPortalUrlSource); 245 } 246 } 247 248 /** 249 * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. 250 */ getRefreshTimeMillis()251 public long getRefreshTimeMillis() { 252 return mRefreshTimeMillis; 253 } 254 255 /** 256 * Get the URL to be used for users to login to the portal, or extend their session if 257 * {@link #isSessionExtendable()} is true. 258 */ 259 @Nullable getUserPortalUrl()260 public Uri getUserPortalUrl() { 261 return mUserPortalUrl; 262 } 263 264 /** 265 * Get the URL that can be used by users to view information about the network venue. 266 */ 267 @Nullable getVenueInfoUrl()268 public Uri getVenueInfoUrl() { 269 return mVenueInfoUrl; 270 } 271 272 /** 273 * Indicates whether the user portal URL can be used to extend sessions, when the user is logged 274 * in and the session has a time or byte limit. 275 */ isSessionExtendable()276 public boolean isSessionExtendable() { 277 return mIsSessionExtendable; 278 } 279 280 /** 281 * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData} 282 * was refreshed. This may be different from the limit currently enforced by the portal. 283 * @return The byte limit, or -1 if not set. 284 */ getByteLimit()285 public long getByteLimit() { 286 return mByteLimit; 287 } 288 289 /** 290 * Get the time at the session will expire, as per {@link System#currentTimeMillis()}. 291 * @return The expiry time, or -1 if unset. 292 */ getExpiryTimeMillis()293 public long getExpiryTimeMillis() { 294 return mExpiryTimeMillis; 295 } 296 297 /** 298 * Get whether the network is captive (portal closed). 299 */ isCaptive()300 public boolean isCaptive() { 301 return mCaptive; 302 } 303 304 /** 305 * Get the information source of the Venue URL 306 * @return The source that the Venue URL was obtained from 307 */ getVenueInfoUrlSource()308 public @CaptivePortalDataSource int getVenueInfoUrlSource() { 309 return mVenueInfoUrlSource; 310 } 311 312 /** 313 * Get the information source of the user portal URL 314 * @return The source that the user portal URL was obtained from 315 */ getUserPortalUrlSource()316 public @CaptivePortalDataSource int getUserPortalUrlSource() { 317 return mUserPortalUrlSource; 318 } 319 320 /** 321 * Get the venue friendly name 322 */ 323 @Nullable getVenueFriendlyName()324 public CharSequence getVenueFriendlyName() { 325 return mVenueFriendlyName; 326 } 327 328 @NonNull 329 public static final Creator<CaptivePortalData> CREATOR = new Creator<CaptivePortalData>() { 330 @Override 331 public CaptivePortalData createFromParcel(Parcel source) { 332 return new CaptivePortalData(source); 333 } 334 335 @Override 336 public CaptivePortalData[] newArray(int size) { 337 return new CaptivePortalData[size]; 338 } 339 }; 340 341 @Override hashCode()342 public int hashCode() { 343 return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl, 344 mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName, 345 mVenueInfoUrlSource, mUserPortalUrlSource); 346 } 347 348 @Override equals(@ullable Object obj)349 public boolean equals(@Nullable Object obj) { 350 if (!(obj instanceof CaptivePortalData)) return false; 351 final CaptivePortalData other = (CaptivePortalData) obj; 352 return mRefreshTimeMillis == other.mRefreshTimeMillis 353 && Objects.equals(mUserPortalUrl, other.mUserPortalUrl) 354 && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl) 355 && mIsSessionExtendable == other.mIsSessionExtendable 356 && mByteLimit == other.mByteLimit 357 && mExpiryTimeMillis == other.mExpiryTimeMillis 358 && mCaptive == other.mCaptive 359 && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName) 360 && mVenueInfoUrlSource == other.mVenueInfoUrlSource 361 && mUserPortalUrlSource == other.mUserPortalUrlSource; 362 } 363 364 @Override toString()365 public String toString() { 366 return "CaptivePortalData {" 367 + "refreshTime: " + mRefreshTimeMillis 368 + ", userPortalUrl: " + mUserPortalUrl 369 + ", venueInfoUrl: " + mVenueInfoUrl 370 + ", isSessionExtendable: " + mIsSessionExtendable 371 + ", byteLimit: " + mByteLimit 372 + ", expiryTime: " + mExpiryTimeMillis 373 + ", captive: " + mCaptive 374 + ", venueFriendlyName: " + mVenueFriendlyName 375 + ", venueInfoUrlSource: " + mVenueInfoUrlSource 376 + ", userPortalUrlSource: " + mUserPortalUrlSource 377 + "}"; 378 } 379 } 380