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