1/*
2 * Copyright (C) 2006 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.internal.telephony.dataconnection;
18
19import android.text.TextUtils;
20
21import com.android.internal.telephony.PhoneConstants;
22import com.android.internal.telephony.RILConstants;
23
24import java.util.ArrayList;
25import java.util.List;
26import java.util.Locale;
27
28/**
29 * This class represents a apn setting for create PDP link
30 */
31public class ApnSetting {
32
33    static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
34    static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*";
35
36    public final String carrier;
37    public final String apn;
38    public final String proxy;
39    public final String port;
40    public final String mmsc;
41    public final String mmsProxy;
42    public final String mmsPort;
43    public final String user;
44    public final String password;
45    public final int authType;
46    public final String[] types;
47    public final int id;
48    public final String numeric;
49    public final String protocol;
50    public final String roamingProtocol;
51    public final int mtu;
52
53    /**
54      * Current status of APN
55      * true : enabled APN, false : disabled APN.
56      */
57    public final boolean carrierEnabled;
58    /**
59      * Radio Access Technology info
60      * To check what values can hold, refer to ServiceState.java.
61      * This should be spread to other technologies,
62      * but currently only used for LTE(14) and EHRPD(13).
63      */
64    public final int bearer;
65
66    /* ID of the profile in the modem */
67    public final int profileId;
68    public final boolean modemCognitive;
69    public final int maxConns;
70    public final int waitTime;
71    public final int maxConnsTime;
72
73    /**
74      * MVNO match type. Possible values:
75      *   "spn": Service provider name.
76      *   "imsi": IMSI.
77      *   "gid": Group identifier level 1.
78      */
79    public final String mvnoType;
80    /**
81      * MVNO data. Examples:
82      *   "spn": A MOBILE, BEN NL
83      *   "imsi": 302720x94, 2060188
84      *   "gid": 4E, 33
85      */
86    public final String mvnoMatchData;
87
88    public ApnSetting(int id, String numeric, String carrier, String apn,
89            String proxy, String port,
90            String mmsc, String mmsProxy, String mmsPort,
91            String user, String password, int authType, String[] types,
92            String protocol, String roamingProtocol, boolean carrierEnabled, int bearer,
93            int profileId, boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime,
94            int mtu, String mvnoType, String mvnoMatchData) {
95        this.id = id;
96        this.numeric = numeric;
97        this.carrier = carrier;
98        this.apn = apn;
99        this.proxy = proxy;
100        this.port = port;
101        this.mmsc = mmsc;
102        this.mmsProxy = mmsProxy;
103        this.mmsPort = mmsPort;
104        this.user = user;
105        this.password = password;
106        this.authType = authType;
107        this.types = new String[types.length];
108        for (int i = 0; i < types.length; i++) {
109            this.types[i] = types[i].toLowerCase(Locale.ROOT);
110        }
111        this.protocol = protocol;
112        this.roamingProtocol = roamingProtocol;
113        this.carrierEnabled = carrierEnabled;
114        this.bearer = bearer;
115        this.profileId = profileId;
116        this.modemCognitive = modemCognitive;
117        this.maxConns = maxConns;
118        this.waitTime = waitTime;
119        this.maxConnsTime = maxConnsTime;
120        this.mtu = mtu;
121        this.mvnoType = mvnoType;
122        this.mvnoMatchData = mvnoMatchData;
123
124    }
125
126    /**
127     * Creates an ApnSetting object from a string.
128     *
129     * @param data the string to read.
130     *
131     * The string must be in one of two formats (newlines added for clarity,
132     * spaces are optional):
133     *
134     * v1 format:
135     *   <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
136     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
137     *   <type>[| <type>...],
138     *
139     * v2 format:
140     *   [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
141     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
142     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearer>,
143     *
144     * v3 format:
145     *   [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
146     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
147     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearer>,
148     *   <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
149     *   <mvnoType>, <mvnoMatchData>
150     *
151     * Note that the strings generated by toString() do not contain the username
152     * and password and thus cannot be read by this method.
153     */
154    public static ApnSetting fromString(String data) {
155        if (data == null) return null;
156
157        int version;
158        // matches() operates on the whole string, so append .* to the regex.
159        if (data.matches(V3_FORMAT_REGEX + ".*")) {
160            version = 3;
161            data = data.replaceFirst(V3_FORMAT_REGEX, "");
162        } else if (data.matches(V2_FORMAT_REGEX + ".*")) {
163            version = 2;
164            data = data.replaceFirst(V2_FORMAT_REGEX, "");
165        } else {
166            version = 1;
167        }
168
169        String[] a = data.split("\\s*,\\s*");
170        if (a.length < 14) {
171            return null;
172        }
173
174        int authType;
175        try {
176            authType = Integer.parseInt(a[12]);
177        } catch (NumberFormatException e) {
178            authType = 0;
179        }
180
181        String[] typeArray;
182        String protocol, roamingProtocol;
183        boolean carrierEnabled;
184        int bearer = 0;
185        int profileId = 0;
186        boolean modemCognitive = false;
187        int maxConns = 0;
188        int waitTime = 0;
189        int maxConnsTime = 0;
190        int mtu = PhoneConstants.UNSET_MTU;
191        String mvnoType = "";
192        String mvnoMatchData = "";
193        if (version == 1) {
194            typeArray = new String[a.length - 13];
195            System.arraycopy(a, 13, typeArray, 0, a.length - 13);
196            protocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
197            roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
198            carrierEnabled = true;
199            bearer = 0;
200        } else {
201            if (a.length < 18) {
202                return null;
203            }
204            typeArray = a[13].split("\\s*\\|\\s*");
205            protocol = a[14];
206            roamingProtocol = a[15];
207            carrierEnabled = Boolean.parseBoolean(a[16]);
208
209            try {
210                bearer = Integer.parseInt(a[17]);
211            } catch (NumberFormatException ex) {
212            }
213
214            if (a.length > 22) {
215                modemCognitive = Boolean.parseBoolean(a[19]);
216                try {
217                    profileId = Integer.parseInt(a[18]);
218                    maxConns = Integer.parseInt(a[20]);
219                    waitTime = Integer.parseInt(a[21]);
220                    maxConnsTime = Integer.parseInt(a[22]);
221                } catch (NumberFormatException e) {
222                }
223            }
224            if (a.length > 23) {
225                try {
226                    mtu = Integer.parseInt(a[23]);
227                } catch (NumberFormatException e) {
228                }
229            }
230            if (a.length > 25) {
231                mvnoType = a[24];
232                mvnoMatchData = a[25];
233            }
234        }
235
236        return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
237                a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol,carrierEnabled,bearer,
238                profileId, modemCognitive, maxConns, waitTime, maxConnsTime, mtu,
239                mvnoType, mvnoMatchData);
240    }
241
242    /**
243     * Creates an array of ApnSetting objects from a string.
244     *
245     * @param data the string to read.
246     *
247     * Builds on top of the same format used by fromString, but allows for multiple entries
248     * separated by "; ".
249     */
250    public static List<ApnSetting> arrayFromString(String data) {
251        List<ApnSetting> retVal = new ArrayList<ApnSetting>();
252        if (TextUtils.isEmpty(data)) {
253            return retVal;
254        }
255        String[] apnStrings = data.split("\\s*;\\s*");
256        for (String apnString : apnStrings) {
257            ApnSetting apn = fromString(apnString);
258            if (apn != null) {
259                retVal.add(apn);
260            }
261        }
262        return retVal;
263    }
264
265    @Override
266    public String toString() {
267        StringBuilder sb = new StringBuilder();
268        sb.append("[ApnSettingV3] ")
269        .append(carrier)
270        .append(", ").append(id)
271        .append(", ").append(numeric)
272        .append(", ").append(apn)
273        .append(", ").append(proxy)
274        .append(", ").append(mmsc)
275        .append(", ").append(mmsProxy)
276        .append(", ").append(mmsPort)
277        .append(", ").append(port)
278        .append(", ").append(authType).append(", ");
279        for (int i = 0; i < types.length; i++) {
280            sb.append(types[i]);
281            if (i < types.length - 1) {
282                sb.append(" | ");
283            }
284        }
285        sb.append(", ").append(protocol);
286        sb.append(", ").append(roamingProtocol);
287        sb.append(", ").append(carrierEnabled);
288        sb.append(", ").append(bearer);
289        sb.append(", ").append(profileId);
290        sb.append(", ").append(modemCognitive);
291        sb.append(", ").append(maxConns);
292        sb.append(", ").append(waitTime);
293        sb.append(", ").append(maxConnsTime);
294        sb.append(", ").append(mtu);
295        sb.append(", ").append(mvnoType);
296        sb.append(", ").append(mvnoMatchData);
297        return sb.toString();
298    }
299
300    /**
301     * Returns true if there are MVNO params specified.
302     */
303    public boolean hasMvnoParams() {
304        return !TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData);
305    }
306
307    public boolean canHandleType(String type) {
308        if (!carrierEnabled) return false;
309        for (String t : types) {
310            // DEFAULT handles all, and HIPRI is handled by DEFAULT
311            if (t.equalsIgnoreCase(type) ||
312                    t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL) ||
313                    (t.equalsIgnoreCase(PhoneConstants.APN_TYPE_DEFAULT) &&
314                    type.equalsIgnoreCase(PhoneConstants.APN_TYPE_HIPRI))) {
315                return true;
316            }
317        }
318        return false;
319    }
320
321    // TODO - if we have this function we should also have hashCode.
322    // Also should handle changes in type order and perhaps case-insensitivity
323    @Override
324    public boolean equals(Object o) {
325        if (o instanceof ApnSetting == false) return false;
326        return (toString().equals(o.toString()));
327    }
328}
329