OSDN Git Service

Fix NotificationListenerService fail to mirror work notification
[android-x86/frameworks-base.git] / core / java / android / net / NetworkTemplate.java
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
17 package android.net;
18
19 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
20 import static android.net.ConnectivityManager.TYPE_ETHERNET;
21 import static android.net.ConnectivityManager.TYPE_WIFI;
22 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
23 import static android.net.ConnectivityManager.TYPE_WIMAX;
24 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
25 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
26 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
27 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
28 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
29 import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
30 import static android.telephony.TelephonyManager.getNetworkClass;
31
32 import static com.android.internal.util.ArrayUtils.contains;
33
34 import android.content.res.Resources;
35 import android.os.Parcel;
36 import android.os.Parcelable;
37 import android.util.BackupUtils;
38
39 import com.android.internal.annotations.VisibleForTesting;
40 import com.android.internal.util.ArrayUtils;
41
42 import java.io.ByteArrayOutputStream;
43 import java.io.DataInputStream;
44 import java.io.DataOutputStream;
45 import java.io.IOException;
46 import java.util.Arrays;
47 import java.util.Objects;
48
49 /**
50  * Template definition used to generically match {@link NetworkIdentity},
51  * usually when collecting statistics.
52  *
53  * @hide
54  */
55 public class NetworkTemplate implements Parcelable {
56     /**
57      * Current Version of the Backup Serializer.
58      */
59     private static final int BACKUP_VERSION = 1;
60
61     public static final int MATCH_MOBILE_ALL = 1;
62     @Deprecated
63     public static final int MATCH_MOBILE_3G_LOWER = 2;
64     @Deprecated
65     public static final int MATCH_MOBILE_4G = 3;
66     public static final int MATCH_WIFI = 4;
67     public static final int MATCH_ETHERNET = 5;
68     public static final int MATCH_MOBILE_WILDCARD = 6;
69     public static final int MATCH_WIFI_WILDCARD = 7;
70     public static final int MATCH_BLUETOOTH = 8;
71
72     /**
73      * Set of {@link NetworkInfo#getType()} that reflect data usage.
74      */
75     private static final int[] DATA_USAGE_NETWORK_TYPES;
76
77     static {
78         DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray(
79                 com.android.internal.R.array.config_data_usage_network_types);
80     }
81
82     private static boolean sForceAllNetworkTypes = false;
83
84     @VisibleForTesting
85     public static void forceAllNetworkTypes() {
86         sForceAllNetworkTypes = true;
87     }
88
89     /**
90      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
91      * the given IMSI.
92      */
93     public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
94         return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null);
95     }
96
97     /**
98      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
99      * the given IMSI that roughly meet a "3G" definition, or lower.
100      */
101     @Deprecated
102     public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
103         return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null);
104     }
105
106     /**
107      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
108      * the given IMSI that roughly meet a "4G" definition.
109      */
110     @Deprecated
111     public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
112         return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null);
113     }
114
115     /**
116      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
117      * regardless of IMSI.
118      */
119     public static NetworkTemplate buildTemplateMobileWildcard() {
120         return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
121     }
122
123     /**
124      * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
125      * regardless of SSID.
126      */
127     public static NetworkTemplate buildTemplateWifiWildcard() {
128         return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
129     }
130
131     @Deprecated
132     public static NetworkTemplate buildTemplateWifi() {
133         return buildTemplateWifiWildcard();
134     }
135
136     /**
137      * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
138      * given SSID.
139      */
140     public static NetworkTemplate buildTemplateWifi(String networkId) {
141         return new NetworkTemplate(MATCH_WIFI, null, networkId);
142     }
143
144     /**
145      * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
146      * networks together.
147      */
148     public static NetworkTemplate buildTemplateEthernet() {
149         return new NetworkTemplate(MATCH_ETHERNET, null, null);
150     }
151
152     /**
153      * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
154      * networks together.
155      */
156     public static NetworkTemplate buildTemplateBluetooth() {
157         return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
158     }
159
160     private final int mMatchRule;
161     private final String mSubscriberId;
162
163     /**
164      * Ugh, templates are designed to target a single subscriber, but we might
165      * need to match several "merged" subscribers. These are the subscribers
166      * that should be considered to match this template.
167      * <p>
168      * Since the merge set is dynamic, it should <em>not</em> be persisted or
169      * used for determining equality.
170      */
171     private final String[] mMatchSubscriberIds;
172
173     private final String mNetworkId;
174
175     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
176         this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
177     }
178
179     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
180             String networkId) {
181         mMatchRule = matchRule;
182         mSubscriberId = subscriberId;
183         mMatchSubscriberIds = matchSubscriberIds;
184         mNetworkId = networkId;
185     }
186
187     private NetworkTemplate(Parcel in) {
188         mMatchRule = in.readInt();
189         mSubscriberId = in.readString();
190         mMatchSubscriberIds = in.createStringArray();
191         mNetworkId = in.readString();
192     }
193
194     @Override
195     public void writeToParcel(Parcel dest, int flags) {
196         dest.writeInt(mMatchRule);
197         dest.writeString(mSubscriberId);
198         dest.writeStringArray(mMatchSubscriberIds);
199         dest.writeString(mNetworkId);
200     }
201
202     @Override
203     public int describeContents() {
204         return 0;
205     }
206
207     @Override
208     public String toString() {
209         final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
210         builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
211         if (mSubscriberId != null) {
212             builder.append(", subscriberId=").append(
213                     NetworkIdentity.scrubSubscriberId(mSubscriberId));
214         }
215         if (mMatchSubscriberIds != null) {
216             builder.append(", matchSubscriberIds=").append(
217                     Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
218         }
219         if (mNetworkId != null) {
220             builder.append(", networkId=").append(mNetworkId);
221         }
222         return builder.toString();
223     }
224
225     @Override
226     public int hashCode() {
227         return Objects.hash(mMatchRule, mSubscriberId, mNetworkId);
228     }
229
230     @Override
231     public boolean equals(Object obj) {
232         if (obj instanceof NetworkTemplate) {
233             final NetworkTemplate other = (NetworkTemplate) obj;
234             return mMatchRule == other.mMatchRule
235                     && Objects.equals(mSubscriberId, other.mSubscriberId)
236                     && Objects.equals(mNetworkId, other.mNetworkId);
237         }
238         return false;
239     }
240
241     public boolean isMatchRuleMobile() {
242         switch (mMatchRule) {
243             case MATCH_MOBILE_3G_LOWER:
244             case MATCH_MOBILE_4G:
245             case MATCH_MOBILE_ALL:
246             case MATCH_MOBILE_WILDCARD:
247                 return true;
248             default:
249                 return false;
250         }
251     }
252
253     public int getMatchRule() {
254         return mMatchRule;
255     }
256
257     public String getSubscriberId() {
258         return mSubscriberId;
259     }
260
261     public String getNetworkId() {
262         return mNetworkId;
263     }
264
265     /**
266      * Test if given {@link NetworkIdentity} matches this template.
267      */
268     public boolean matches(NetworkIdentity ident) {
269         switch (mMatchRule) {
270             case MATCH_MOBILE_ALL:
271                 return matchesMobile(ident);
272             case MATCH_MOBILE_3G_LOWER:
273                 return matchesMobile3gLower(ident);
274             case MATCH_MOBILE_4G:
275                 return matchesMobile4g(ident);
276             case MATCH_WIFI:
277                 return matchesWifi(ident);
278             case MATCH_ETHERNET:
279                 return matchesEthernet(ident);
280             case MATCH_MOBILE_WILDCARD:
281                 return matchesMobileWildcard(ident);
282             case MATCH_WIFI_WILDCARD:
283                 return matchesWifiWildcard(ident);
284             case MATCH_BLUETOOTH:
285                 return matchesBluetooth(ident);
286             default:
287                 throw new IllegalArgumentException("unknown network template");
288         }
289     }
290
291     /**
292      * Check if mobile network with matching IMSI.
293      */
294     private boolean matchesMobile(NetworkIdentity ident) {
295         if (ident.mType == TYPE_WIMAX) {
296             // TODO: consider matching against WiMAX subscriber identity
297             return true;
298         } else {
299             final boolean matchesType = (sForceAllNetworkTypes
300                     || contains(DATA_USAGE_NETWORK_TYPES, ident.mType));
301             return matchesType && !ArrayUtils.isEmpty(mMatchSubscriberIds)
302                     && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
303         }
304     }
305
306     /**
307      * Check if mobile network classified 3G or lower with matching IMSI.
308      */
309     @Deprecated
310     private boolean matchesMobile3gLower(NetworkIdentity ident) {
311         ensureSubtypeAvailable();
312         if (ident.mType == TYPE_WIMAX) {
313             return false;
314         } else if (matchesMobile(ident)) {
315             switch (getNetworkClass(ident.mSubType)) {
316                 case NETWORK_CLASS_UNKNOWN:
317                 case NETWORK_CLASS_2_G:
318                 case NETWORK_CLASS_3_G:
319                     return true;
320             }
321         }
322         return false;
323     }
324
325     /**
326      * Check if mobile network classified 4G with matching IMSI.
327      */
328     @Deprecated
329     private boolean matchesMobile4g(NetworkIdentity ident) {
330         ensureSubtypeAvailable();
331         if (ident.mType == TYPE_WIMAX) {
332             // TODO: consider matching against WiMAX subscriber identity
333             return true;
334         } else if (matchesMobile(ident)) {
335             switch (getNetworkClass(ident.mSubType)) {
336                 case NETWORK_CLASS_4_G:
337                     return true;
338             }
339         }
340         return false;
341     }
342
343     /**
344      * Check if matches Wi-Fi network template.
345      */
346     private boolean matchesWifi(NetworkIdentity ident) {
347         switch (ident.mType) {
348             case TYPE_WIFI:
349                 return Objects.equals(
350                         removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId));
351             default:
352                 return false;
353         }
354     }
355
356     /**
357      * Check if matches Ethernet network template.
358      */
359     private boolean matchesEthernet(NetworkIdentity ident) {
360         if (ident.mType == TYPE_ETHERNET) {
361             return true;
362         }
363         return false;
364     }
365
366     private boolean matchesMobileWildcard(NetworkIdentity ident) {
367         if (ident.mType == TYPE_WIMAX) {
368             return true;
369         } else {
370             return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
371         }
372     }
373
374     private boolean matchesWifiWildcard(NetworkIdentity ident) {
375         switch (ident.mType) {
376             case TYPE_WIFI:
377             case TYPE_WIFI_P2P:
378                 return true;
379             default:
380                 return false;
381         }
382     }
383
384     /**
385      * Check if matches Bluetooth network template.
386      */
387     private boolean matchesBluetooth(NetworkIdentity ident) {
388         if (ident.mType == TYPE_BLUETOOTH) {
389             return true;
390         }
391         return false;
392     }
393
394     private static String getMatchRuleName(int matchRule) {
395         switch (matchRule) {
396             case MATCH_MOBILE_3G_LOWER:
397                 return "MOBILE_3G_LOWER";
398             case MATCH_MOBILE_4G:
399                 return "MOBILE_4G";
400             case MATCH_MOBILE_ALL:
401                 return "MOBILE_ALL";
402             case MATCH_WIFI:
403                 return "WIFI";
404             case MATCH_ETHERNET:
405                 return "ETHERNET";
406             case MATCH_MOBILE_WILDCARD:
407                 return "MOBILE_WILDCARD";
408             case MATCH_WIFI_WILDCARD:
409                 return "WIFI_WILDCARD";
410             case MATCH_BLUETOOTH:
411                 return "BLUETOOTH";
412             default:
413                 return "UNKNOWN";
414         }
415     }
416
417     private static void ensureSubtypeAvailable() {
418         if (COMBINE_SUBTYPE_ENABLED) {
419             throw new IllegalArgumentException(
420                     "Unable to enforce 3G_LOWER template on combined data.");
421         }
422     }
423
424     /**
425      * Examine the given template and normalize if it refers to a "merged"
426      * mobile subscriber. We pick the "lowest" merged subscriber as the primary
427      * for key purposes, and expand the template to match all other merged
428      * subscribers.
429      * <p>
430      * For example, given an incoming template matching B, and the currently
431      * active merge set [A,B], we'd return a new template that primarily matches
432      * A, but also matches B.
433      */
434     public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
435         if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
436             // Requested template subscriber is part of the merge group; return
437             // a template that matches all merged subscribers.
438             return new NetworkTemplate(template.mMatchRule, merged[0], merged,
439                     template.mNetworkId);
440         } else {
441             return template;
442         }
443     }
444
445     public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
446         @Override
447         public NetworkTemplate createFromParcel(Parcel in) {
448             return new NetworkTemplate(in);
449         }
450
451         @Override
452         public NetworkTemplate[] newArray(int size) {
453             return new NetworkTemplate[size];
454         }
455     };
456
457     public byte[] getBytesForBackup() throws IOException {
458         ByteArrayOutputStream baos = new ByteArrayOutputStream();
459         DataOutputStream out = new DataOutputStream(baos);
460
461         out.writeInt(BACKUP_VERSION);
462
463         out.writeInt(mMatchRule);
464         BackupUtils.writeString(out, mSubscriberId);
465         BackupUtils.writeString(out, mNetworkId);
466
467         return baos.toByteArray();
468     }
469
470     public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
471             throws IOException, BackupUtils.BadVersionException {
472         int version = in.readInt();
473         if (version < 1 || version > BACKUP_VERSION) {
474             throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
475         }
476
477         int matchRule = in.readInt();
478         String subscriberId = BackupUtils.readString(in);
479         String networkId = BackupUtils.readString(in);
480
481         return new NetworkTemplate(matchRule, subscriberId, networkId);
482     }
483 }