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.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.annotation.TestApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.util.Objects;
27 
28 /**
29  * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt.
30  * @hide
31  */
32 @SystemApi
33 @TestApi
34 public final class CaptivePortalData implements Parcelable {
35     private final long mRefreshTimeMillis;
36     @Nullable
37     private final Uri mUserPortalUrl;
38     @Nullable
39     private final Uri mVenueInfoUrl;
40     private final boolean mIsSessionExtendable;
41     private final long mByteLimit;
42     private final long mExpiryTimeMillis;
43     private final boolean mCaptive;
44 
CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive)45     private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
46             boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive) {
47         mRefreshTimeMillis = refreshTimeMillis;
48         mUserPortalUrl = userPortalUrl;
49         mVenueInfoUrl = venueInfoUrl;
50         mIsSessionExtendable = isSessionExtendable;
51         mByteLimit = byteLimit;
52         mExpiryTimeMillis = expiryTimeMillis;
53         mCaptive = captive;
54     }
55 
CaptivePortalData(Parcel p)56     private CaptivePortalData(Parcel p) {
57         this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
58                 p.readLong(), p.readLong(), p.readBoolean());
59     }
60 
61     @Override
describeContents()62     public int describeContents() {
63         return 0;
64     }
65 
66     @Override
writeToParcel(@onNull Parcel dest, int flags)67     public void writeToParcel(@NonNull Parcel dest, int flags) {
68         dest.writeLong(mRefreshTimeMillis);
69         dest.writeParcelable(mUserPortalUrl, 0);
70         dest.writeParcelable(mVenueInfoUrl, 0);
71         dest.writeBoolean(mIsSessionExtendable);
72         dest.writeLong(mByteLimit);
73         dest.writeLong(mExpiryTimeMillis);
74         dest.writeBoolean(mCaptive);
75     }
76 
77     /**
78      * A builder to create new {@link CaptivePortalData}.
79      */
80     public static class Builder {
81         private long mRefreshTime;
82         private Uri mUserPortalUrl;
83         private Uri mVenueInfoUrl;
84         private boolean mIsSessionExtendable;
85         private long mBytesRemaining = -1;
86         private long mExpiryTime = -1;
87         private boolean mCaptive;
88 
89         /**
90          * Create an empty builder.
91          */
Builder()92         public Builder() {}
93 
94         /**
95          * Create a builder copying all data from existing {@link CaptivePortalData}.
96          */
Builder(@ullable CaptivePortalData data)97         public Builder(@Nullable CaptivePortalData data) {
98             if (data == null) return;
99             setRefreshTime(data.mRefreshTimeMillis)
100                     .setUserPortalUrl(data.mUserPortalUrl)
101                     .setVenueInfoUrl(data.mVenueInfoUrl)
102                     .setSessionExtendable(data.mIsSessionExtendable)
103                     .setBytesRemaining(data.mByteLimit)
104                     .setExpiryTime(data.mExpiryTimeMillis)
105                     .setCaptive(data.mCaptive);
106         }
107 
108         /**
109          * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
110          */
111         @NonNull
setRefreshTime(long refreshTime)112         public Builder setRefreshTime(long refreshTime) {
113             mRefreshTime = refreshTime;
114             return this;
115         }
116 
117         /**
118          * Set the URL to be used for users to login to the portal, if captive.
119          */
120         @NonNull
setUserPortalUrl(@ullable Uri userPortalUrl)121         public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
122             mUserPortalUrl = userPortalUrl;
123             return this;
124         }
125 
126         /**
127          * Set the URL that can be used by users to view information about the network venue.
128          */
129         @NonNull
setVenueInfoUrl(@ullable Uri venueInfoUrl)130         public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
131             mVenueInfoUrl = venueInfoUrl;
132             return this;
133         }
134 
135         /**
136          * Set whether the portal supports extending a user session on the portal URL page.
137          */
138         @NonNull
setSessionExtendable(boolean sessionExtendable)139         public Builder setSessionExtendable(boolean sessionExtendable) {
140             mIsSessionExtendable = sessionExtendable;
141             return this;
142         }
143 
144         /**
145          * Set the number of bytes remaining on the network before the portal closes.
146          */
147         @NonNull
setBytesRemaining(long bytesRemaining)148         public Builder setBytesRemaining(long bytesRemaining) {
149             mBytesRemaining = bytesRemaining;
150             return this;
151         }
152 
153         /**
154          * Set the time at the session will expire, as per {@link System#currentTimeMillis()}.
155          */
156         @NonNull
setExpiryTime(long expiryTime)157         public Builder setExpiryTime(long expiryTime) {
158             mExpiryTime = expiryTime;
159             return this;
160         }
161 
162         /**
163          * Set whether the network is captive (portal closed).
164          */
165         @NonNull
setCaptive(boolean captive)166         public Builder setCaptive(boolean captive) {
167             mCaptive = captive;
168             return this;
169         }
170 
171         /**
172          * Create a new {@link CaptivePortalData}.
173          */
174         @NonNull
build()175         public CaptivePortalData build() {
176             return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
177                     mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive);
178         }
179     }
180 
181     /**
182      * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
183      */
getRefreshTimeMillis()184     public long getRefreshTimeMillis() {
185         return mRefreshTimeMillis;
186     }
187 
188     /**
189      * Get the URL to be used for users to login to the portal, or extend their session if
190      * {@link #isSessionExtendable()} is true.
191      */
192     @Nullable
getUserPortalUrl()193     public Uri getUserPortalUrl() {
194         return mUserPortalUrl;
195     }
196 
197     /**
198      * Get the URL that can be used by users to view information about the network venue.
199      */
200     @Nullable
getVenueInfoUrl()201     public Uri getVenueInfoUrl() {
202         return mVenueInfoUrl;
203     }
204 
205     /**
206      * Indicates whether the user portal URL can be used to extend sessions, when the user is logged
207      * in and the session has a time or byte limit.
208      */
isSessionExtendable()209     public boolean isSessionExtendable() {
210         return mIsSessionExtendable;
211     }
212 
213     /**
214      * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData}
215      * was refreshed. This may be different from the limit currently enforced by the portal.
216      * @return The byte limit, or -1 if not set.
217      */
getByteLimit()218     public long getByteLimit() {
219         return mByteLimit;
220     }
221 
222     /**
223      * Get the time at the session will expire, as per {@link System#currentTimeMillis()}.
224      * @return The expiry time, or -1 if unset.
225      */
getExpiryTimeMillis()226     public long getExpiryTimeMillis() {
227         return mExpiryTimeMillis;
228     }
229 
230     /**
231      * Get whether the network is captive (portal closed).
232      */
isCaptive()233     public boolean isCaptive() {
234         return mCaptive;
235     }
236 
237     @NonNull
238     public static final Creator<CaptivePortalData> CREATOR = new Creator<CaptivePortalData>() {
239         @Override
240         public CaptivePortalData createFromParcel(Parcel source) {
241             return new CaptivePortalData(source);
242         }
243 
244         @Override
245         public CaptivePortalData[] newArray(int size) {
246             return new CaptivePortalData[size];
247         }
248     };
249 
250     @Override
hashCode()251     public int hashCode() {
252         return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
253                 mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive);
254     }
255 
256     @Override
equals(Object obj)257     public boolean equals(Object obj) {
258         if (!(obj instanceof CaptivePortalData)) return false;
259         final CaptivePortalData other = (CaptivePortalData) obj;
260         return mRefreshTimeMillis == other.mRefreshTimeMillis
261                 && Objects.equals(mUserPortalUrl, other.mUserPortalUrl)
262                 && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl)
263                 && mIsSessionExtendable == other.mIsSessionExtendable
264                 && mByteLimit == other.mByteLimit
265                 && mExpiryTimeMillis == other.mExpiryTimeMillis
266                 && mCaptive == other.mCaptive;
267     }
268 
269     @Override
toString()270     public String toString() {
271         return "CaptivePortalData {"
272                 + "refreshTime: " + mRefreshTimeMillis
273                 + ", userPortalUrl: " + mUserPortalUrl
274                 + ", venueInfoUrl: " + mVenueInfoUrl
275                 + ", isSessionExtendable: " + mIsSessionExtendable
276                 + ", byteLimit: " + mByteLimit
277                 + ", expiryTime: " + mExpiryTimeMillis
278                 + ", captive: " + mCaptive
279                 + "}";
280     }
281 }
282