NetworkTemplate.java revision 55a442e58262e253df965d652bd8219c8d1e72d3
1/*
2 * Copyright (C) 2011 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
17package android.net;
18
19import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
20import static android.net.ConnectivityManager.TYPE_ETHERNET;
21import static android.net.ConnectivityManager.TYPE_WIFI;
22import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
23import static android.net.ConnectivityManager.TYPE_WIMAX;
24import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
25import static android.net.NetworkIdentity.scrubSubscriberId;
26import static android.net.wifi.WifiInfo.removeDoubleQuotes;
27import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
28import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
29import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
30import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
31import static android.telephony.TelephonyManager.getNetworkClass;
32import static com.android.internal.util.ArrayUtils.contains;
33
34import android.content.res.Resources;
35import android.os.Parcel;
36import android.os.Parcelable;
37
38import com.android.internal.annotations.VisibleForTesting;
39
40import java.util.Objects;
41
42/**
43 * Template definition used to generically match {@link NetworkIdentity},
44 * usually when collecting statistics.
45 *
46 * @hide
47 */
48public class NetworkTemplate implements Parcelable {
49
50    public static final int MATCH_MOBILE_ALL = 1;
51    public static final int MATCH_MOBILE_3G_LOWER = 2;
52    public static final int MATCH_MOBILE_4G = 3;
53    public static final int MATCH_WIFI = 4;
54    public static final int MATCH_ETHERNET = 5;
55    public static final int MATCH_MOBILE_WILDCARD = 6;
56    public static final int MATCH_WIFI_WILDCARD = 7;
57    public static final int MATCH_BLUETOOTH = 8;
58
59    /**
60     * Set of {@link NetworkInfo#getType()} that reflect data usage.
61     */
62    private static final int[] DATA_USAGE_NETWORK_TYPES;
63
64    static {
65        DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray(
66                com.android.internal.R.array.config_data_usage_network_types);
67    }
68
69    private static boolean sForceAllNetworkTypes = false;
70
71    @VisibleForTesting
72    public static void forceAllNetworkTypes() {
73        sForceAllNetworkTypes = true;
74    }
75
76    /**
77     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
78     * the given IMSI.
79     */
80    public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
81        return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null);
82    }
83
84    /**
85     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
86     * the given IMSI that roughly meet a "3G" definition, or lower.
87     */
88    @Deprecated
89    public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
90        return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null);
91    }
92
93    /**
94     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
95     * the given IMSI that roughly meet a "4G" definition.
96     */
97    @Deprecated
98    public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
99        return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null);
100    }
101
102    /**
103     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
104     * regardless of IMSI.
105     */
106    public static NetworkTemplate buildTemplateMobileWildcard() {
107        return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
108    }
109
110    /**
111     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
112     * regardless of SSID.
113     */
114    public static NetworkTemplate buildTemplateWifiWildcard() {
115        return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
116    }
117
118    @Deprecated
119    public static NetworkTemplate buildTemplateWifi() {
120        return buildTemplateWifiWildcard();
121    }
122
123    /**
124     * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
125     * given SSID.
126     */
127    public static NetworkTemplate buildTemplateWifi(String networkId) {
128        return new NetworkTemplate(MATCH_WIFI, null, networkId);
129    }
130
131    /**
132     * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
133     * networks together.
134     */
135    public static NetworkTemplate buildTemplateEthernet() {
136        return new NetworkTemplate(MATCH_ETHERNET, null, null);
137    }
138
139    /**
140     * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
141     * networks together.
142     */
143    public static NetworkTemplate buildTemplateBluetooth() {
144        return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
145    }
146
147    private final int mMatchRule;
148    private final String mSubscriberId;
149    private final String mNetworkId;
150
151    public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
152        mMatchRule = matchRule;
153        mSubscriberId = subscriberId;
154        mNetworkId = networkId;
155    }
156
157    private NetworkTemplate(Parcel in) {
158        mMatchRule = in.readInt();
159        mSubscriberId = in.readString();
160        mNetworkId = in.readString();
161    }
162
163    @Override
164    public void writeToParcel(Parcel dest, int flags) {
165        dest.writeInt(mMatchRule);
166        dest.writeString(mSubscriberId);
167        dest.writeString(mNetworkId);
168    }
169
170    @Override
171    public int describeContents() {
172        return 0;
173    }
174
175    @Override
176    public String toString() {
177        final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
178        builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
179        if (mSubscriberId != null) {
180            builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
181        }
182        if (mNetworkId != null) {
183            builder.append(", networkId=").append(mNetworkId);
184        }
185        return builder.toString();
186    }
187
188    @Override
189    public int hashCode() {
190        return Objects.hash(mMatchRule, mSubscriberId, mNetworkId);
191    }
192
193    @Override
194    public boolean equals(Object obj) {
195        if (obj instanceof NetworkTemplate) {
196            final NetworkTemplate other = (NetworkTemplate) obj;
197            return mMatchRule == other.mMatchRule
198                    && Objects.equals(mSubscriberId, other.mSubscriberId)
199                    && Objects.equals(mNetworkId, other.mNetworkId);
200        }
201        return false;
202    }
203
204    public int getMatchRule() {
205        return mMatchRule;
206    }
207
208    public String getSubscriberId() {
209        return mSubscriberId;
210    }
211
212    public String getNetworkId() {
213        return mNetworkId;
214    }
215
216    /**
217     * Test if given {@link NetworkIdentity} matches this template.
218     */
219    public boolean matches(NetworkIdentity ident) {
220        switch (mMatchRule) {
221            case MATCH_MOBILE_ALL:
222                return matchesMobile(ident);
223            case MATCH_MOBILE_3G_LOWER:
224                return matchesMobile3gLower(ident);
225            case MATCH_MOBILE_4G:
226                return matchesMobile4g(ident);
227            case MATCH_WIFI:
228                return matchesWifi(ident);
229            case MATCH_ETHERNET:
230                return matchesEthernet(ident);
231            case MATCH_MOBILE_WILDCARD:
232                return matchesMobileWildcard(ident);
233            case MATCH_WIFI_WILDCARD:
234                return matchesWifiWildcard(ident);
235            case MATCH_BLUETOOTH:
236                return matchesBluetooth(ident);
237            default:
238                throw new IllegalArgumentException("unknown network template");
239        }
240    }
241
242    /**
243     * Check if mobile network with matching IMSI.
244     */
245    private boolean matchesMobile(NetworkIdentity ident) {
246        if (ident.mType == TYPE_WIMAX) {
247            // TODO: consider matching against WiMAX subscriber identity
248            return true;
249        } else {
250            return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType))
251                    && Objects.equals(mSubscriberId, ident.mSubscriberId));
252        }
253    }
254
255    /**
256     * Check if mobile network classified 3G or lower with matching IMSI.
257     */
258    private boolean matchesMobile3gLower(NetworkIdentity ident) {
259        ensureSubtypeAvailable();
260        if (ident.mType == TYPE_WIMAX) {
261            return false;
262        } else if (matchesMobile(ident)) {
263            switch (getNetworkClass(ident.mSubType)) {
264                case NETWORK_CLASS_UNKNOWN:
265                case NETWORK_CLASS_2_G:
266                case NETWORK_CLASS_3_G:
267                    return true;
268            }
269        }
270        return false;
271    }
272
273    /**
274     * Check if mobile network classified 4G with matching IMSI.
275     */
276    private boolean matchesMobile4g(NetworkIdentity ident) {
277        ensureSubtypeAvailable();
278        if (ident.mType == TYPE_WIMAX) {
279            // TODO: consider matching against WiMAX subscriber identity
280            return true;
281        } else if (matchesMobile(ident)) {
282            switch (getNetworkClass(ident.mSubType)) {
283                case NETWORK_CLASS_4_G:
284                    return true;
285            }
286        }
287        return false;
288    }
289
290    /**
291     * Check if matches Wi-Fi network template.
292     */
293    private boolean matchesWifi(NetworkIdentity ident) {
294        switch (ident.mType) {
295            case TYPE_WIFI:
296                return Objects.equals(
297                        removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId));
298            default:
299                return false;
300        }
301    }
302
303    /**
304     * Check if matches Ethernet network template.
305     */
306    private boolean matchesEthernet(NetworkIdentity ident) {
307        if (ident.mType == TYPE_ETHERNET) {
308            return true;
309        }
310        return false;
311    }
312
313    private boolean matchesMobileWildcard(NetworkIdentity ident) {
314        if (ident.mType == TYPE_WIMAX) {
315            return true;
316        } else {
317            return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
318        }
319    }
320
321    private boolean matchesWifiWildcard(NetworkIdentity ident) {
322        switch (ident.mType) {
323            case TYPE_WIFI:
324            case TYPE_WIFI_P2P:
325                return true;
326            default:
327                return false;
328        }
329    }
330
331    /**
332     * Check if matches Bluetooth network template.
333     */
334    private boolean matchesBluetooth(NetworkIdentity ident) {
335        if (ident.mType == TYPE_BLUETOOTH) {
336            return true;
337        }
338        return false;
339    }
340
341    private static String getMatchRuleName(int matchRule) {
342        switch (matchRule) {
343            case MATCH_MOBILE_3G_LOWER:
344                return "MOBILE_3G_LOWER";
345            case MATCH_MOBILE_4G:
346                return "MOBILE_4G";
347            case MATCH_MOBILE_ALL:
348                return "MOBILE_ALL";
349            case MATCH_WIFI:
350                return "WIFI";
351            case MATCH_ETHERNET:
352                return "ETHERNET";
353            case MATCH_MOBILE_WILDCARD:
354                return "MOBILE_WILDCARD";
355            case MATCH_WIFI_WILDCARD:
356                return "WIFI_WILDCARD";
357            case MATCH_BLUETOOTH:
358                return "BLUETOOTH";
359            default:
360                return "UNKNOWN";
361        }
362    }
363
364    private static void ensureSubtypeAvailable() {
365        if (COMBINE_SUBTYPE_ENABLED) {
366            throw new IllegalArgumentException(
367                    "Unable to enforce 3G_LOWER template on combined data.");
368        }
369    }
370
371    public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
372        @Override
373        public NetworkTemplate createFromParcel(Parcel in) {
374            return new NetworkTemplate(in);
375        }
376
377        @Override
378        public NetworkTemplate[] newArray(int size) {
379            return new NetworkTemplate[size];
380        }
381    };
382}
383