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 */ load(Context context, String apnName, int subId, String requestId)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 getDebugText(Cursor cursor)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 trimWithNullCheck(String value)177 private static String trimWithNullCheck(String value) { 178 return value != null ? value.trim() : null; 179 } 180 ApnSettings(String mmscUrl, String proxyAddr, int proxyPort, String debugText)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 getMmscUrl()188 public String getMmscUrl() { 189 return mServiceCenter; 190 } 191 getProxyAddress()192 public String getProxyAddress() { 193 return mProxyAddress; 194 } 195 getProxyPort()196 public int getProxyPort() { 197 return mProxyPort; 198 } 199 isProxySet()200 public boolean isProxySet() { 201 return !TextUtils.isEmpty(mProxyAddress); 202 } 203 isValidApnType(String types, String requestType)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 toString()218 public String toString() { 219 return mDebugText; 220 } 221 } 222