• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.os.Bundle;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.util.Objects;
27 import java.util.Set;
28 
29 /**
30  * A network identifier along with a score for the quality of that network.
31  *
32  * @deprecated as part of the {@link NetworkScoreManager} deprecation.
33  * @hide
34  */
35 @Deprecated
36 @SystemApi
37 public class ScoredNetwork implements Parcelable {
38 
39   /**
40      * Key used with the {@link #attributes} bundle to define the badging curve.
41      *
42      * <p>The badging curve is a {@link RssiCurve} used to map different RSSI values to {@link
43      * NetworkBadging.Badging} enums.
44      */
45     public static final String ATTRIBUTES_KEY_BADGING_CURVE =
46             "android.net.attributes.key.BADGING_CURVE";
47     /**
48      * Extra used with {@link #attributes} to specify whether the
49      * network is believed to have a captive portal.
50      * <p>
51      * This data may be used, for example, to display a visual indicator
52      * in a network selection list.
53      * <p>
54      * Note that the this extra conveys the possible presence of a
55      * captive portal, not its state or the user's ability to open
56      * the portal.
57      * <p>
58      * If no value is associated with this key then it's unknown.
59      */
60     public static final String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL =
61             "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
62 
63     /**
64      * Key used with the {@link #attributes} bundle to define the rankingScoreOffset int value.
65      *
66      * <p>The rankingScoreOffset is used when calculating the ranking score used to rank networks
67      * against one another. See {@link #calculateRankingScore} for more information.
68      */
69     public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET =
70             "android.net.attributes.key.RANKING_SCORE_OFFSET";
71 
72     /** A {@link NetworkKey} uniquely identifying this network. */
73     public final NetworkKey networkKey;
74 
75     /**
76      * The {@link RssiCurve} representing the scores for this network based on the RSSI.
77      *
78      * <p>This field is optional and may be set to null to indicate that no score is available for
79      * this network at this time. Such networks, along with networks for which the scorer has not
80      * responded, are always prioritized below scored networks, regardless of the score.
81      */
82     public final RssiCurve rssiCurve;
83 
84     /**
85      * A boolean value that indicates whether or not the network is believed to be metered.
86      *
87      * <p>A network can be classified as metered if the user would be
88      * sensitive to heavy data usage on that connection due to monetary costs,
89      * data limitations or battery/performance issues. A typical example would
90      * be a wifi connection where the user would be charged for usage.
91      */
92     public final boolean meteredHint;
93 
94     /**
95      * An additional collection of optional attributes set by
96      * the Network Recommendation Provider.
97      *
98      * @see #ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL
99      * @see #ATTRIBUTES_KEY_RANKING_SCORE_OFFSET
100      */
101     @Nullable
102     public final Bundle attributes;
103 
104     /**
105      * Construct a new {@link ScoredNetwork}.
106      *
107      * @param networkKey the {@link NetworkKey} uniquely identifying this network.
108      * @param rssiCurve the {@link RssiCurve} representing the scores for this network based on the
109      *     RSSI. This field is optional, and may be skipped to represent a network which the scorer
110      *     has opted not to score at this time. Passing a null value here is strongly preferred to
111      *     not returning any {@link ScoredNetwork} for a given {@link NetworkKey} because it
112      *     indicates to the system not to request scores for this network in the future, although
113      *     the scorer may choose to issue an out-of-band update at any time.
114      */
ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve)115     public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve) {
116         this(networkKey, rssiCurve, false /* meteredHint */);
117     }
118 
119     /**
120      * Construct a new {@link ScoredNetwork}.
121      *
122      * @param networkKey the {@link NetworkKey} uniquely identifying this network.
123      * @param rssiCurve the {@link RssiCurve} representing the scores for this network based on the
124      *     RSSI. This field is optional, and may be skipped to represent a network which the scorer
125      *     has opted not to score at this time. Passing a null value here is strongly preferred to
126      *     not returning any {@link ScoredNetwork} for a given {@link NetworkKey} because it
127      *     indicates to the system not to request scores for this network in the future, although
128      *     the scorer may choose to issue an out-of-band update at any time.
129      * @param meteredHint A boolean value indicating whether or not the network is believed to be
130      *     metered.
131      */
ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint)132     public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint) {
133         this(networkKey, rssiCurve, meteredHint, null /* attributes */);
134     }
135 
136     /**
137      * Construct a new {@link ScoredNetwork}.
138      *
139      * @param networkKey the {@link NetworkKey} uniquely identifying this network
140      * @param rssiCurve the {@link RssiCurve} representing the scores for this network based on the
141      *     RSSI. This field is optional, and may be skipped to represent a network which the scorer
142      *     has opted not to score at this time. Passing a null value here is strongly preferred to
143      *     not returning any {@link ScoredNetwork} for a given {@link NetworkKey} because it
144      *     indicates to the system not to request scores for this network in the future, although
145      *     the scorer may choose to issue an out-of-band update at any time.
146      * @param meteredHint a boolean value indicating whether or not the network is believed to be
147      *                    metered
148      * @param attributes optional provider specific attributes
149      */
ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint, @Nullable Bundle attributes)150     public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint,
151             @Nullable Bundle attributes) {
152         this.networkKey = networkKey;
153         this.rssiCurve = rssiCurve;
154         this.meteredHint = meteredHint;
155         this.attributes = attributes;
156     }
157 
ScoredNetwork(Parcel in)158     private ScoredNetwork(Parcel in) {
159         networkKey = NetworkKey.CREATOR.createFromParcel(in);
160         if (in.readByte() == 1) {
161             rssiCurve = RssiCurve.CREATOR.createFromParcel(in);
162         } else {
163             rssiCurve = null;
164         }
165         meteredHint = (in.readByte() == 1);
166         attributes = in.readBundle();
167     }
168 
169     @Override
describeContents()170     public int describeContents() {
171         return 0;
172     }
173 
174     @Override
writeToParcel(Parcel out, int flags)175     public void writeToParcel(Parcel out, int flags) {
176         networkKey.writeToParcel(out, flags);
177         if (rssiCurve != null) {
178             out.writeByte((byte) 1);
179             rssiCurve.writeToParcel(out, flags);
180         } else {
181             out.writeByte((byte) 0);
182         }
183         out.writeByte((byte) (meteredHint ? 1 : 0));
184         out.writeBundle(attributes);
185     }
186 
187     @Override
equals(@ullable Object o)188     public boolean equals(@Nullable Object o) {
189         if (this == o) return true;
190         if (o == null || getClass() != o.getClass()) return false;
191 
192         ScoredNetwork that = (ScoredNetwork) o;
193 
194         return Objects.equals(networkKey, that.networkKey)
195                 && Objects.equals(rssiCurve, that.rssiCurve)
196                 && Objects.equals(meteredHint, that.meteredHint)
197                 && bundleEquals(attributes, that.attributes);
198     }
199 
bundleEquals(Bundle bundle1, Bundle bundle2)200     private boolean bundleEquals(Bundle bundle1, Bundle bundle2) {
201         if (bundle1 == bundle2) {
202             return true;
203         }
204         if (bundle1 == null || bundle2 == null) {
205             return false;
206         }
207         if (bundle1.size() != bundle2.size()) {
208             return false;
209         }
210         Set<String> keys = bundle1.keySet();
211         for (String key : keys) {
212             Object value1 = bundle1.get(key);
213             Object value2 = bundle2.get(key);
214             if (!Objects.equals(value1, value2)) {
215                 return false;
216             }
217         }
218         return true;
219     }
220 
221     @Override
hashCode()222     public int hashCode() {
223         return Objects.hash(networkKey, rssiCurve, meteredHint, attributes);
224     }
225 
226     @NonNull
227     @Override
toString()228     public String toString() {
229         StringBuilder out = new StringBuilder(
230                 "ScoredNetwork{" +
231                 "networkKey=" + networkKey +
232                 ", rssiCurve=" + rssiCurve +
233                 ", meteredHint=" + meteredHint);
234         // calling isEmpty will unparcel the bundle so its contents can be converted to a string
235         if (attributes != null && !attributes.isEmpty()) {
236             out.append(", attributes=" + attributes);
237         }
238         out.append('}');
239         return out.toString();
240     }
241 
242     /**
243      * Returns true if a ranking score can be calculated for this network.
244      *
245      * @hide
246      */
hasRankingScore()247     public boolean hasRankingScore() {
248         return (rssiCurve != null)
249                 || (attributes != null
250                         && attributes.containsKey(ATTRIBUTES_KEY_RANKING_SCORE_OFFSET));
251     }
252 
253     /**
254      * Returns a ranking score for a given RSSI which can be used to comparatively
255      * rank networks.
256      *
257      * <p>The score obtained by the rssiCurve is bitshifted left by 8 bits to expand it to an
258      * integer and then the offset is added. If the addition operation overflows or underflows,
259      * Integer.MAX_VALUE and Integer.MIN_VALUE will be returned respectively.
260      *
261      * <p>{@link #hasRankingScore} should be called first to ensure this network is capable
262      * of returning a ranking score.
263      *
264      * @throws UnsupportedOperationException if there is no RssiCurve and no rankingScoreOffset
265      * for this network (hasRankingScore returns false).
266      *
267      * @hide
268      */
calculateRankingScore(int rssi)269     public int calculateRankingScore(int rssi) throws UnsupportedOperationException {
270         if (!hasRankingScore()) {
271             throw new UnsupportedOperationException(
272                     "Either rssiCurve or rankingScoreOffset is required to calculate the "
273                             + "ranking score");
274         }
275 
276         int offset = 0;
277         if (attributes != null) {
278              offset += attributes.getInt(ATTRIBUTES_KEY_RANKING_SCORE_OFFSET, 0 /* default */);
279         }
280 
281         int score = (rssiCurve == null) ? 0 : rssiCurve.lookupScore(rssi) << Byte.SIZE;
282 
283         try {
284             return Math.addExact(score, offset);
285         } catch (ArithmeticException e) {
286             return (score < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
287         }
288     }
289 
290     /**
291      * Return the {@link NetworkBadging.Badging} enum for this network for the given RSSI, derived from the
292      * badging curve.
293      *
294      * <p>If no badging curve is present, {@link #BADGE_NONE} will be returned.
295      *
296      * @param rssi The rssi level for which the badge should be calculated
297      */
298     @NetworkBadging.Badging
calculateBadge(int rssi)299     public int calculateBadge(int rssi) {
300         if (attributes != null && attributes.containsKey(ATTRIBUTES_KEY_BADGING_CURVE)) {
301             RssiCurve badgingCurve =
302                     attributes.getParcelable(ATTRIBUTES_KEY_BADGING_CURVE, android.net.RssiCurve.class);
303             return badgingCurve.lookupScore(rssi);
304         }
305 
306         return NetworkBadging.BADGING_NONE;
307     }
308 
309     public static final @android.annotation.NonNull Parcelable.Creator<ScoredNetwork> CREATOR =
310             new Parcelable.Creator<ScoredNetwork>() {
311                 @Override
312                 public ScoredNetwork createFromParcel(Parcel in) {
313                     return new ScoredNetwork(in);
314                 }
315 
316                 @Override
317                 public ScoredNetwork[] newArray(int size) {
318                     return new ScoredNetwork[size];
319                 }
320             };
321 }
322