Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright (C) 2014 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 com.android.mms.service;
     18 
     19 import android.content.Context;
     20 import android.database.Cursor;
     21 import android.database.sqlite.SqliteWrapper;
     22 import android.net.NetworkUtils;
     23 import android.net.Uri;
     24 import android.provider.Telephony;
     25 import android.text.TextUtils;
     26 
     27 import com.android.internal.telephony.PhoneConstants;
     28 import com.android.mms.service.exception.ApnException;
     29 
     30 import java.net.URI;
     31 import java.net.URISyntaxException;
     32 
     33 /**
     34  * APN settings used for MMS transactions
     35  */
     36 public class ApnSettings {
     37     // MMSC URL
     38     private final String mServiceCenter;
     39     // MMSC proxy address
     40     private final String mProxyAddress;
     41     // MMSC proxy port
     42     private final int mProxyPort;
     43     // Debug text for this APN: a concatenation of interesting columns of this APN
     44     private final String mDebugText;
     45 
     46     private static final String[] APN_PROJECTION = {
     47             Telephony.Carriers.TYPE,
     48             Telephony.Carriers.MMSC,
     49             Telephony.Carriers.MMSPROXY,
     50             Telephony.Carriers.MMSPORT,
     51             Telephony.Carriers.NAME,
     52             Telephony.Carriers.APN,
     53             Telephony.Carriers.BEARER_BITMASK,
     54             Telephony.Carriers.PROTOCOL,
     55             Telephony.Carriers.ROAMING_PROTOCOL,
     56             Telephony.Carriers.AUTH_TYPE,
     57             Telephony.Carriers.MVNO_TYPE,
     58             Telephony.Carriers.MVNO_MATCH_DATA,
     59             Telephony.Carriers.PROXY,
     60             Telephony.Carriers.PORT,
     61             Telephony.Carriers.SERVER,
     62             Telephony.Carriers.USER,
     63             Telephony.Carriers.PASSWORD,
     64     };
     65     private static final int COLUMN_TYPE         = 0;
     66     private static final int COLUMN_MMSC         = 1;
     67     private static final int COLUMN_MMSPROXY     = 2;
     68     private static final int COLUMN_MMSPORT      = 3;
     69     private static final int COLUMN_NAME         = 4;
     70     private static final int COLUMN_APN          = 5;
     71     private static final int COLUMN_BEARER       = 6;
     72     private static final int COLUMN_PROTOCOL     = 7;
     73     private static final int COLUMN_ROAMING_PROTOCOL = 8;
     74     private static final int COLUMN_AUTH_TYPE    = 9;
     75     private static final int COLUMN_MVNO_TYPE    = 10;
     76     private static final int COLUMN_MVNO_MATCH_DATA = 11;
     77     private static final int COLUMN_PROXY        = 12;
     78     private static final int COLUMN_PORT         = 13;
     79     private static final int COLUMN_SERVER       = 14;
     80     private static final int COLUMN_USER         = 15;
     81     private static final int COLUMN_PASSWORD     = 16;
     82 
     83 
     84     /**
     85      * Load APN settings from system
     86      *  @param context
     87      * @param apnName the optional APN name to match
     88      * @param requestId the request ID for logging
     89      */
     90     public static ApnSettings load(Context context, String apnName, int subId, String requestId)
     91             throws ApnException {
     92         LogUtil.i(requestId, "Loading APN using name " + apnName);
     93         // TODO: CURRENT semantics is currently broken in telephony. Revive this when it is fixed.
     94         //String selection = Telephony.Carriers.CURRENT + " IS NOT NULL";
     95         String selection = null;
     96         String[] selectionArgs = null;
     97         apnName = apnName != null ? apnName.trim() : null;
     98         if (!TextUtils.isEmpty(apnName)) {
     99             //selection += " AND " + Telephony.Carriers.APN + "=?";
    100             selection = Telephony.Carriers.APN + "=?";
    101             selectionArgs = new String[]{ apnName };
    102         }
    103         Cursor cursor = null;
    104         try {
    105             cursor = SqliteWrapper.query(
    106                     context,
    107                     context.getContentResolver(),
    108                     Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "/subId/" + subId),
    109                     APN_PROJECTION,
    110                     selection,
    111                     selectionArgs,
    112                     null/*sortOrder*/);
    113             if (cursor != null) {
    114                 String mmscUrl = null;
    115                 String proxyAddress = null;
    116                 // Default proxy port to 80
    117                 int proxyPort = 80;
    118                 while (cursor.moveToNext()) {
    119                     // Read values from APN settings
    120                     if (isValidApnType(
    121                             cursor.getString(COLUMN_TYPE), PhoneConstants.APN_TYPE_MMS)) {
    122                         mmscUrl = trimWithNullCheck(cursor.getString(COLUMN_MMSC));
    123                         if (TextUtils.isEmpty(mmscUrl)) {
    124                             continue;
    125                         }
    126                         mmscUrl = NetworkUtils.trimV4AddrZeros(mmscUrl);
    127                         try {
    128                             new URI(mmscUrl);
    129                         } catch (URISyntaxException e) {
    130                             throw new ApnException("Invalid MMSC url " + mmscUrl);
    131                         }
    132                         proxyAddress = trimWithNullCheck(cursor.getString(COLUMN_MMSPROXY));
    133                         if (!TextUtils.isEmpty(proxyAddress)) {
    134                             proxyAddress = NetworkUtils.trimV4AddrZeros(proxyAddress);
    135                             final String portString =
    136                                     trimWithNullCheck(cursor.getString(COLUMN_MMSPORT));
    137                             if (!TextUtils.isEmpty(portString)) {
    138                                 try {
    139                                     proxyPort = Integer.parseInt(portString);
    140                                 } catch (NumberFormatException e) {
    141                                     LogUtil.e(requestId, "Invalid port " + portString + ", use 80");
    142                                 }
    143                             }
    144                         }
    145                         return new ApnSettings(
    146                                 mmscUrl, proxyAddress, proxyPort, getDebugText(cursor));
    147                     }
    148                 }
    149 
    150             }
    151         } finally {
    152             if (cursor != null) {
    153                 cursor.close();
    154             }
    155         }
    156         throw new ApnException("Can not find valid APN");
    157     }
    158 
    159     private static String getDebugText(Cursor cursor) {
    160         final StringBuilder sb = new StringBuilder();
    161         sb.append("APN [");
    162         for (int i = 0; i < cursor.getColumnCount(); i++) {
    163             final String name = cursor.getColumnName(i);
    164             final String value = cursor.getString(i);
    165             if (TextUtils.isEmpty(value)) {
    166                 continue;
    167             }
    168             if (i > 0) {
    169                 sb.append(' ');
    170             }
    171             sb.append(name).append('=').append(value);
    172         }
    173         sb.append("]");
    174         return sb.toString();
    175     }
    176 
    177     private static String trimWithNullCheck(String value) {
    178         return value != null ? value.trim() : null;
    179     }
    180 
    181     public ApnSettings(String mmscUrl, String proxyAddr, int proxyPort, String debugText) {
    182         mServiceCenter = mmscUrl;
    183         mProxyAddress = proxyAddr;
    184         mProxyPort = proxyPort;
    185         mDebugText = debugText;
    186    }
    187 
    188     public String getMmscUrl() {
    189         return mServiceCenter;
    190     }
    191 
    192     public String getProxyAddress() {
    193         return mProxyAddress;
    194     }
    195 
    196     public int getProxyPort() {
    197         return mProxyPort;
    198     }
    199 
    200     public boolean isProxySet() {
    201         return !TextUtils.isEmpty(mProxyAddress);
    202     }
    203 
    204     private static boolean isValidApnType(String types, String requestType) {
    205         // If APN type is unspecified, assume APN_TYPE_ALL.
    206         if (TextUtils.isEmpty(types)) {
    207             return true;
    208         }
    209         for (String type : types.split(",")) {
    210             type = type.trim();
    211             if (type.equals(requestType) || type.equals(PhoneConstants.APN_TYPE_ALL)) {
    212                 return true;
    213             }
    214         }
    215         return false;
    216     }
    217 
    218     public String toString() {
    219         return mDebugText;
    220     }
    221 }
    222