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_WIFI;
20import static android.net.ConnectivityManager.getNetworkTypeName;
21import static android.net.ConnectivityManager.isNetworkTypeMobile;
22
23import android.content.Context;
24import android.net.wifi.WifiInfo;
25import android.net.wifi.WifiManager;
26import android.os.Build;
27import android.telephony.TelephonyManager;
28
29import com.android.internal.util.Objects;
30
31/**
32 * Network definition that includes strong identity. Analogous to combining
33 * {@link NetworkInfo} and an IMSI.
34 *
35 * @hide
36 */
37public class NetworkIdentity {
38    /**
39     * When enabled, combine all {@link #mSubType} together under
40     * {@link #SUBTYPE_COMBINED}.
41     */
42    public static final boolean COMBINE_SUBTYPE_ENABLED = true;
43
44    public static final int SUBTYPE_COMBINED = -1;
45
46    final int mType;
47    final int mSubType;
48    final String mSubscriberId;
49    final String mNetworkId;
50    final boolean mRoaming;
51
52    public NetworkIdentity(
53            int type, int subType, String subscriberId, String networkId, boolean roaming) {
54        mType = type;
55        mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType;
56        mSubscriberId = subscriberId;
57        mNetworkId = networkId;
58        mRoaming = roaming;
59    }
60
61    @Override
62    public int hashCode() {
63        return Objects.hashCode(mType, mSubType, mSubscriberId, mNetworkId, mRoaming);
64    }
65
66    @Override
67    public boolean equals(Object obj) {
68        if (obj instanceof NetworkIdentity) {
69            final NetworkIdentity ident = (NetworkIdentity) obj;
70            return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
71                    && Objects.equal(mSubscriberId, ident.mSubscriberId)
72                    && Objects.equal(mNetworkId, ident.mNetworkId);
73        }
74        return false;
75    }
76
77    @Override
78    public String toString() {
79        final StringBuilder builder = new StringBuilder("[");
80        builder.append("type=").append(getNetworkTypeName(mType));
81        builder.append(", subType=");
82        if (COMBINE_SUBTYPE_ENABLED) {
83            builder.append("COMBINED");
84        } else if (ConnectivityManager.isNetworkTypeMobile(mType)) {
85            builder.append(TelephonyManager.getNetworkTypeName(mSubType));
86        } else {
87            builder.append(mSubType);
88        }
89        if (mSubscriberId != null) {
90            builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
91        }
92        if (mNetworkId != null) {
93            builder.append(", networkId=").append(mNetworkId);
94        }
95        if (mRoaming) {
96            builder.append(", ROAMING");
97        }
98        return builder.append("]").toString();
99    }
100
101    public int getType() {
102        return mType;
103    }
104
105    public int getSubType() {
106        return mSubType;
107    }
108
109    public String getSubscriberId() {
110        return mSubscriberId;
111    }
112
113    public String getNetworkId() {
114        return mNetworkId;
115    }
116
117    public boolean getRoaming() {
118        return mRoaming;
119    }
120
121    /**
122     * Scrub given IMSI on production builds.
123     */
124    public static String scrubSubscriberId(String subscriberId) {
125        if ("eng".equals(Build.TYPE)) {
126            return subscriberId;
127        } else if (subscriberId != null) {
128            // TODO: parse this as MCC+MNC instead of hard-coding
129            return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "...";
130        } else {
131            return "null";
132        }
133    }
134
135    /**
136     * Build a {@link NetworkIdentity} from the given {@link NetworkState},
137     * assuming that any mobile networks are using the current IMSI.
138     */
139    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) {
140        final int type = state.networkInfo.getType();
141        final int subType = state.networkInfo.getSubtype();
142
143        // TODO: consider moving subscriberId over to LinkCapabilities, so it
144        // comes from an authoritative source.
145
146        String subscriberId = null;
147        String networkId = null;
148        boolean roaming = false;
149
150        if (isNetworkTypeMobile(type)) {
151            final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
152                    Context.TELEPHONY_SERVICE);
153            roaming = telephony.isNetworkRoaming();
154            if (state.subscriberId != null) {
155                subscriberId = state.subscriberId;
156            } else {
157                subscriberId = telephony.getSubscriberId();
158            }
159
160        } else if (type == TYPE_WIFI) {
161            if (state.networkId != null) {
162                networkId = state.networkId;
163            } else {
164                final WifiManager wifi = (WifiManager) context.getSystemService(
165                        Context.WIFI_SERVICE);
166                final WifiInfo info = wifi.getConnectionInfo();
167                networkId = info != null ? info.getSSID() : null;
168            }
169        }
170
171        return new NetworkIdentity(type, subType, subscriberId, networkId, roaming);
172    }
173}
174