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 com.android.internal.telephony.PhoneConstants; 20 import com.android.mms.service.exception.ApnException; 21 22 import android.content.Context; 23 import android.database.Cursor; 24 import android.database.sqlite.SqliteWrapper; 25 import android.net.NetworkUtils; 26 import android.net.Uri; 27 import android.provider.Telephony; 28 import android.text.TextUtils; 29 import android.util.Log; 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 47 private static final String[] APN_PROJECTION = { 48 Telephony.Carriers.TYPE, // 0 49 Telephony.Carriers.MMSC, // 1 50 Telephony.Carriers.MMSPROXY, // 2 51 Telephony.Carriers.MMSPORT // 3 52 }; 53 private static final int COLUMN_TYPE = 0; 54 private static final int COLUMN_MMSC = 1; 55 private static final int COLUMN_MMSPROXY = 2; 56 private static final int COLUMN_MMSPORT = 3; 57 58 59 /** 60 * Load APN settings from system 61 * 62 * @param context 63 * @param apnName the optional APN name to match 64 */ 65 public static ApnSettings load(Context context, String apnName, long subId) 66 throws ApnException { 67 if (Log.isLoggable(TAG, Log.VERBOSE)) { 68 Log.v(TAG, "ApnSettings: apnName " + apnName); 69 } 70 // TODO: CURRENT semantics is currently broken in telephony. Revive this when it is fixed. 71 //String selection = Telephony.Carriers.CURRENT + " IS NOT NULL"; 72 String selection = null; 73 String[] selectionArgs = null; 74 apnName = apnName != null ? apnName.trim() : null; 75 if (!TextUtils.isEmpty(apnName)) { 76 //selection += " AND " + Telephony.Carriers.APN + "=?"; 77 selection = Telephony.Carriers.APN + "=?"; 78 selectionArgs = new String[]{ apnName }; 79 } 80 Cursor cursor = null; 81 try { 82 cursor = SqliteWrapper.query( 83 context, 84 context.getContentResolver(), 85 Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "/subId/" + subId), 86 APN_PROJECTION, 87 selection, 88 selectionArgs, 89 null/*sortOrder*/); 90 if (cursor != null) { 91 String mmscUrl = null; 92 String proxyAddress = null; 93 int proxyPort = -1; 94 while (cursor.moveToNext()) { 95 // Read values from APN settings 96 if (isValidApnType( 97 cursor.getString(COLUMN_TYPE), PhoneConstants.APN_TYPE_MMS)) { 98 mmscUrl = trimWithNullCheck(cursor.getString(COLUMN_MMSC)); 99 if (TextUtils.isEmpty(mmscUrl)) { 100 continue; 101 } 102 mmscUrl = NetworkUtils.trimV4AddrZeros(mmscUrl); 103 try { 104 new URI(mmscUrl); 105 } catch (URISyntaxException e) { 106 throw new ApnException("Invalid MMSC url " + mmscUrl); 107 } 108 proxyAddress = trimWithNullCheck(cursor.getString(COLUMN_MMSPROXY)); 109 if (!TextUtils.isEmpty(proxyAddress)) { 110 proxyAddress = NetworkUtils.trimV4AddrZeros(proxyAddress); 111 final String portString = 112 trimWithNullCheck(cursor.getString(COLUMN_MMSPORT)); 113 if (portString != null) { 114 try { 115 proxyPort = Integer.parseInt(portString); 116 } catch (NumberFormatException e) { 117 Log.e(TAG, "Invalid port " + portString); 118 throw new ApnException("Invalid port " + portString); 119 } 120 } 121 } 122 return new ApnSettings(mmscUrl, proxyAddress, proxyPort); 123 } 124 } 125 126 } 127 } finally { 128 if (cursor != null) { 129 cursor.close(); 130 } 131 } 132 throw new ApnException("Can not find valid APN"); 133 } 134 135 private static String trimWithNullCheck(String value) { 136 return value != null ? value.trim() : null; 137 } 138 139 public ApnSettings(String mmscUrl, String proxyAddr, int proxyPort) { 140 mServiceCenter = mmscUrl; 141 mProxyAddress = proxyAddr; 142 mProxyPort = proxyPort; 143 } 144 145 public String getMmscUrl() { 146 return mServiceCenter; 147 } 148 149 public String getProxyAddress() { 150 return mProxyAddress; 151 } 152 153 public int getProxyPort() { 154 return mProxyPort; 155 } 156 157 public boolean isProxySet() { 158 return !TextUtils.isEmpty(mProxyAddress); 159 } 160 161 private static boolean isValidApnType(String types, String requestType) { 162 // If APN type is unspecified, assume APN_TYPE_ALL. 163 if (TextUtils.isEmpty(types)) { 164 return true; 165 } 166 for (String type : types.split(",")) { 167 type = type.trim(); 168 if (type.equals(requestType) || type.equals(PhoneConstants.APN_TYPE_ALL)) { 169 return true; 170 } 171 } 172 return false; 173 } 174 175 public String toString() { 176 final StringBuilder sb = new StringBuilder(); 177 sb.append("APN:"); 178 sb.append(" mmsc=").append(mServiceCenter); 179 sb.append(" proxy=").append(mProxyAddress); 180 sb.append(" port=").append(mProxyPort); 181 return sb.toString(); 182 } 183 } 184