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 com.android.server.net;
18
19import android.net.NetworkIdentity;
20
21import java.io.DataInputStream;
22import java.io.DataOutputStream;
23import java.io.IOException;
24import java.util.HashSet;
25
26import static android.net.ConnectivityManager.TYPE_MOBILE;
27
28/**
29 * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity}
30 * active on that interface.
31 *
32 * @hide
33 */
34public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
35        Comparable<NetworkIdentitySet> {
36    private static final int VERSION_INIT = 1;
37    private static final int VERSION_ADD_ROAMING = 2;
38    private static final int VERSION_ADD_NETWORK_ID = 3;
39    private static final int VERSION_ADD_METERED = 4;
40
41    public NetworkIdentitySet() {
42    }
43
44    public NetworkIdentitySet(DataInputStream in) throws IOException {
45        final int version = in.readInt();
46        final int size = in.readInt();
47        for (int i = 0; i < size; i++) {
48            if (version <= VERSION_INIT) {
49                final int ignored = in.readInt();
50            }
51            final int type = in.readInt();
52            final int subType = in.readInt();
53            final String subscriberId = readOptionalString(in);
54            final String networkId;
55            if (version >= VERSION_ADD_NETWORK_ID) {
56                networkId = readOptionalString(in);
57            } else {
58                networkId = null;
59            }
60            final boolean roaming;
61            if (version >= VERSION_ADD_ROAMING) {
62                roaming = in.readBoolean();
63            } else {
64                roaming = false;
65            }
66
67            final boolean metered;
68            if (version >= VERSION_ADD_METERED) {
69                metered = in.readBoolean();
70            } else {
71                // If this is the old data and the type is mobile, treat it as metered. (Note that
72                // if this is a mobile network, TYPE_MOBILE is the only possible type that could be
73                // used.)
74                metered = (type == TYPE_MOBILE);
75            }
76
77            add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered));
78        }
79    }
80
81    public void writeToStream(DataOutputStream out) throws IOException {
82        out.writeInt(VERSION_ADD_METERED);
83        out.writeInt(size());
84        for (NetworkIdentity ident : this) {
85            out.writeInt(ident.getType());
86            out.writeInt(ident.getSubType());
87            writeOptionalString(out, ident.getSubscriberId());
88            writeOptionalString(out, ident.getNetworkId());
89            out.writeBoolean(ident.getRoaming());
90            out.writeBoolean(ident.getMetered());
91        }
92    }
93
94    /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */
95    public boolean isAnyMemberRoaming() {
96        if (isEmpty()) {
97            return false;
98        }
99        for (NetworkIdentity ident : this) {
100            if (ident.getRoaming()) {
101                return true;
102            }
103        }
104        return false;
105    }
106
107    private static void writeOptionalString(DataOutputStream out, String value) throws IOException {
108        if (value != null) {
109            out.writeByte(1);
110            out.writeUTF(value);
111        } else {
112            out.writeByte(0);
113        }
114    }
115
116    private static String readOptionalString(DataInputStream in) throws IOException {
117        if (in.readByte() != 0) {
118            return in.readUTF();
119        } else {
120            return null;
121        }
122    }
123
124    @Override
125    public int compareTo(NetworkIdentitySet another) {
126        if (isEmpty()) return -1;
127        if (another.isEmpty()) return 1;
128
129        final NetworkIdentity ident = iterator().next();
130        final NetworkIdentity anotherIdent = another.iterator().next();
131        return ident.compareTo(anotherIdent);
132    }
133}
134