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 */ load(Context context, String apnName, int subId)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 getDebugText(Cursor cursor)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 trimWithNullCheck(String value)182 private static String trimWithNullCheck(String value) { 183 return value != null ? value.trim() : null; 184 } 185 ApnSettings(String mmscUrl, String proxyAddr, int proxyPort, String debugText)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 getMmscUrl()193 public String getMmscUrl() { 194 return mServiceCenter; 195 } 196 getProxyAddress()197 public String getProxyAddress() { 198 return mProxyAddress; 199 } 200 getProxyPort()201 public int getProxyPort() { 202 return mProxyPort; 203 } 204 isProxySet()205 public boolean isProxySet() { 206 return !TextUtils.isEmpty(mProxyAddress); 207 } 208 isValidApnType(String types, String requestType)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 toString()223 public String toString() { 224 return mDebugText; 225 } 226 } 227