The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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 android.net; |
| 18 | |
| 19 | import android.content.BroadcastReceiver; |
| 20 | import android.content.Context; |
| 21 | import android.content.Intent; |
| 22 | import android.content.IntentFilter; |
| 23 | import android.os.RemoteException; |
| 24 | import android.os.Handler; |
| 25 | import android.os.ServiceManager; |
| 26 | import android.os.SystemProperties; |
| 27 | import com.android.internal.telephony.ITelephony; |
| 28 | import com.android.internal.telephony.Phone; |
| 29 | import com.android.internal.telephony.TelephonyIntents; |
| 30 | import android.net.NetworkInfo.DetailedState; |
| 31 | import android.telephony.TelephonyManager; |
| 32 | import android.util.Log; |
| 33 | import android.text.TextUtils; |
| 34 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 35 | /** |
| 36 | * Track the state of mobile data connectivity. This is done by |
| 37 | * receiving broadcast intents from the Phone process whenever |
| 38 | * the state of data connectivity changes. |
| 39 | * |
| 40 | * {@hide} |
| 41 | */ |
| 42 | public class MobileDataStateTracker extends NetworkStateTracker { |
| 43 | |
| 44 | private static final String TAG = "MobileDataStateTracker"; |
Robert Greenwalt | d8df149 | 2009-10-06 14:12:53 -0700 | [diff] [blame] | 45 | private static final boolean DBG = true; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 46 | |
| 47 | private Phone.DataState mMobileDataState; |
| 48 | private ITelephony mPhoneService; |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 49 | |
| 50 | private String mApnType; |
Mike Lockwood | 03d2467 | 2009-10-08 15:45:03 -0400 | [diff] [blame] | 51 | private String mApnName; |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 52 | private boolean mEnabled; |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 53 | private BroadcastReceiver mStateReceiver; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 54 | |
| 55 | /** |
| 56 | * Create a new MobileDataStateTracker |
| 57 | * @param context the application context of the caller |
| 58 | * @param target a message handler for getting callbacks about state changes |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 59 | * @param netType the ConnectivityManager network type |
| 60 | * @param apnType the Phone apnType |
| 61 | * @param tag the name of this network |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 62 | */ |
Robert Greenwalt | 5154ae76 | 2009-10-30 14:17:42 -0700 | [diff] [blame^] | 63 | public MobileDataStateTracker(Context context, Handler target, int netType, String tag) { |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 64 | super(context, target, netType, |
| 65 | TelephonyManager.getDefault().getNetworkType(), tag, |
| 66 | TelephonyManager.getDefault().getNetworkTypeName()); |
Robert Greenwalt | 5154ae76 | 2009-10-30 14:17:42 -0700 | [diff] [blame^] | 67 | mApnType = networkTypeToApnType(netType); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 68 | mPhoneService = null; |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 69 | if(netType == ConnectivityManager.TYPE_MOBILE) { |
| 70 | mEnabled = true; |
| 71 | } else { |
| 72 | mEnabled = false; |
| 73 | } |
| 74 | |
| 75 | mDnsPropNames = new String[] { |
| 76 | "net.rmnet0.dns1", |
| 77 | "net.rmnet0.dns2", |
| 78 | "net.eth0.dns1", |
| 79 | "net.eth0.dns2", |
| 80 | "net.eth0.dns3", |
| 81 | "net.eth0.dns4", |
| 82 | "net.gprs.dns1", |
Robert Greenwalt | 25a5d3d | 2009-08-13 15:59:51 -0700 | [diff] [blame] | 83 | "net.gprs.dns2", |
| 84 | "net.ppp0.dns1", |
| 85 | "net.ppp0.dns2"}; |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 86 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | /** |
| 90 | * Begin monitoring mobile data connectivity. |
| 91 | */ |
| 92 | public void startMonitoring() { |
| 93 | IntentFilter filter = |
| 94 | new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); |
| 95 | filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); |
| 96 | filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); |
| 97 | |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 98 | mStateReceiver = new MobileDataStateReceiver(); |
| 99 | Intent intent = mContext.registerReceiver(mStateReceiver, filter); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 100 | if (intent != null) |
| 101 | mMobileDataState = getMobileDataState(intent); |
| 102 | else |
| 103 | mMobileDataState = Phone.DataState.DISCONNECTED; |
| 104 | } |
| 105 | |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 106 | private Phone.DataState getMobileDataState(Intent intent) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 107 | String str = intent.getStringExtra(Phone.STATE_KEY); |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 108 | if (str != null) { |
| 109 | String apnTypeList = |
| 110 | intent.getStringExtra(Phone.DATA_APN_TYPES_KEY); |
| 111 | if (isApnTypeIncluded(apnTypeList)) { |
| 112 | return Enum.valueOf(Phone.DataState.class, str); |
| 113 | } |
| 114 | } |
| 115 | return Phone.DataState.DISCONNECTED; |
| 116 | } |
| 117 | |
| 118 | private boolean isApnTypeIncluded(String typeList) { |
| 119 | /* comma seperated list - split and check */ |
| 120 | if (typeList == null) |
| 121 | return false; |
| 122 | |
| 123 | String[] list = typeList.split(","); |
| 124 | for(int i=0; i< list.length; i++) { |
| 125 | if (TextUtils.equals(list[i], mApnType) || |
| 126 | TextUtils.equals(list[i], Phone.APN_TYPE_ALL)) { |
| 127 | return true; |
| 128 | } |
| 129 | } |
| 130 | return false; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | private class MobileDataStateReceiver extends BroadcastReceiver { |
| 134 | public void onReceive(Context context, Intent intent) { |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 135 | synchronized(this) { |
| 136 | if (intent.getAction().equals(TelephonyIntents. |
| 137 | ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { |
| 138 | Phone.DataState state = getMobileDataState(intent); |
| 139 | String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); |
| 140 | String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); |
| 141 | String apnTypeList = intent.getStringExtra(Phone.DATA_APN_TYPES_KEY); |
Mike Lockwood | 03d2467 | 2009-10-08 15:45:03 -0400 | [diff] [blame] | 142 | mApnName = apnName; |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 143 | |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 144 | boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, |
| 145 | false); |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 146 | |
Robert Greenwalt | 8206ff3 | 2009-09-10 15:06:20 -0700 | [diff] [blame] | 147 | // set this regardless of the apnTypeList. It's all the same radio/network |
| 148 | // underneath |
| 149 | mNetworkInfo.setIsAvailable(!unavailable); |
Robert Greenwalt | 0badd0b | 2009-08-24 15:44:55 -0700 | [diff] [blame] | 150 | |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 151 | if (isApnTypeIncluded(apnTypeList)) { |
| 152 | if (mEnabled == false) { |
| 153 | // if we're not enabled but the APN Type is supported by this connection |
| 154 | // we should record the interface name if one's provided. If the user |
| 155 | // turns on this network we will need the interfacename but won't get |
Robert Greenwalt | d1aca6a | 2009-09-25 14:52:34 -0700 | [diff] [blame] | 156 | // a fresh connected message - TODO fix this when we get per-APN |
| 157 | // notifications |
Robert Greenwalt | a64bf83 | 2009-08-19 20:19:33 -0700 | [diff] [blame] | 158 | if (state == Phone.DataState.CONNECTED) { |
| 159 | if (DBG) Log.d(TAG, "replacing old mInterfaceName (" + |
| 160 | mInterfaceName + ") with " + |
| 161 | intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY) + |
| 162 | " for " + mApnType); |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 163 | mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 164 | } |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 165 | return; |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 166 | } |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 167 | } else { |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 168 | return; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 169 | } |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 170 | |
Robert Greenwalt | d8df149 | 2009-10-06 14:12:53 -0700 | [diff] [blame] | 171 | if (DBG) Log.d(TAG, mApnType + " Received state= " + state + ", old= " + |
| 172 | mMobileDataState + ", reason= " + |
| 173 | (reason == null ? "(unspecified)" : reason) + |
| 174 | ", apnTypeList= " + apnTypeList); |
| 175 | |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 176 | if (mMobileDataState != state) { |
| 177 | mMobileDataState = state; |
| 178 | switch (state) { |
| 179 | case DISCONNECTED: |
| 180 | if(isTeardownRequested()) { |
| 181 | mEnabled = false; |
| 182 | setTeardownRequested(false); |
| 183 | } |
| 184 | |
| 185 | setDetailedState(DetailedState.DISCONNECTED, reason, apnName); |
| 186 | if (mInterfaceName != null) { |
| 187 | NetworkUtils.resetConnections(mInterfaceName); |
| 188 | } |
Robert Greenwalt | d1aca6a | 2009-09-25 14:52:34 -0700 | [diff] [blame] | 189 | // can't do this here - ConnectivityService needs it to clear stuff |
| 190 | // it's ok though - just leave it to be refreshed next time |
| 191 | // we connect. |
| 192 | //if (DBG) Log.d(TAG, "clearing mInterfaceName for "+ mApnType + |
| 193 | // " as it DISCONNECTED"); |
| 194 | //mInterfaceName = null; |
| 195 | //mDefaultGatewayAddr = 0; |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 196 | break; |
| 197 | case CONNECTING: |
| 198 | setDetailedState(DetailedState.CONNECTING, reason, apnName); |
| 199 | break; |
| 200 | case SUSPENDED: |
| 201 | setDetailedState(DetailedState.SUSPENDED, reason, apnName); |
| 202 | break; |
| 203 | case CONNECTED: |
| 204 | mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); |
| 205 | if (mInterfaceName == null) { |
| 206 | Log.d(TAG, "CONNECTED event did not supply interface name."); |
| 207 | } |
| 208 | setDetailedState(DetailedState.CONNECTED, reason, apnName); |
| 209 | break; |
| 210 | } |
| 211 | } |
| 212 | } else if (intent.getAction(). |
| 213 | equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { |
| 214 | mEnabled = false; |
| 215 | String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY); |
| 216 | String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); |
| 217 | if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" + |
| 218 | reason == null ? "" : "(" + reason + ")"); |
| 219 | setDetailedState(DetailedState.FAILED, reason, apnName); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 220 | } |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 221 | TelephonyManager tm = TelephonyManager.getDefault(); |
| 222 | setRoamingStatus(tm.isNetworkRoaming()); |
| 223 | setSubtype(tm.getNetworkType(), tm.getNetworkTypeName()); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 224 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 228 | private void getPhoneService(boolean forceRefresh) { |
| 229 | if ((mPhoneService == null) || forceRefresh) { |
| 230 | mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | /** |
| 235 | * Report whether data connectivity is possible. |
| 236 | */ |
| 237 | public boolean isAvailable() { |
| 238 | getPhoneService(false); |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 239 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 240 | /* |
| 241 | * If the phone process has crashed in the past, we'll get a |
| 242 | * RemoteException and need to re-reference the service. |
| 243 | */ |
| 244 | for (int retry = 0; retry < 2; retry++) { |
| 245 | if (mPhoneService == null) break; |
| 246 | |
| 247 | try { |
| 248 | return mPhoneService.isDataConnectivityPossible(); |
| 249 | } catch (RemoteException e) { |
| 250 | // First-time failed, get the phone service again |
| 251 | if (retry == 0) getPhoneService(true); |
| 252 | } |
| 253 | } |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 254 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 255 | return false; |
| 256 | } |
| 257 | |
| 258 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 259 | * {@inheritDoc} |
| 260 | * The mobile data network subtype indicates what generation network technology is in effect, |
| 261 | * e.g., GPRS, EDGE, UMTS, etc. |
| 262 | */ |
| 263 | public int getNetworkSubtype() { |
| 264 | return TelephonyManager.getDefault().getNetworkType(); |
| 265 | } |
| 266 | |
| 267 | /** |
| 268 | * Return the system properties name associated with the tcp buffer sizes |
| 269 | * for this network. |
| 270 | */ |
| 271 | public String getTcpBufferSizesPropName() { |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 272 | String networkTypeStr = "unknown"; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 273 | TelephonyManager tm = new TelephonyManager(mContext); |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 274 | //TODO We have to edit the parameter for getNetworkType regarding CDMA |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 275 | switch(tm.getNetworkType()) { |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 276 | case TelephonyManager.NETWORK_TYPE_GPRS: |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 277 | networkTypeStr = "gprs"; |
| 278 | break; |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 279 | case TelephonyManager.NETWORK_TYPE_EDGE: |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 280 | networkTypeStr = "edge"; |
| 281 | break; |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 282 | case TelephonyManager.NETWORK_TYPE_UMTS: |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 283 | networkTypeStr = "umts"; |
| 284 | break; |
Li Zhe | ebe6634 | 2009-08-14 19:22:16 +0800 | [diff] [blame] | 285 | case TelephonyManager.NETWORK_TYPE_HSDPA: |
| 286 | networkTypeStr = "hsdpa"; |
| 287 | break; |
| 288 | case TelephonyManager.NETWORK_TYPE_HSUPA: |
| 289 | networkTypeStr = "hsupa"; |
| 290 | break; |
| 291 | case TelephonyManager.NETWORK_TYPE_HSPA: |
| 292 | networkTypeStr = "hspa"; |
| 293 | break; |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 294 | case TelephonyManager.NETWORK_TYPE_CDMA: |
| 295 | networkTypeStr = "cdma"; |
| 296 | break; |
Li Zhe | ebe6634 | 2009-08-14 19:22:16 +0800 | [diff] [blame] | 297 | case TelephonyManager.NETWORK_TYPE_1xRTT: |
| 298 | networkTypeStr = "1xrtt"; |
| 299 | break; |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 300 | case TelephonyManager.NETWORK_TYPE_EVDO_0: |
| 301 | networkTypeStr = "evdo"; |
| 302 | break; |
| 303 | case TelephonyManager.NETWORK_TYPE_EVDO_A: |
| 304 | networkTypeStr = "evdo"; |
| 305 | break; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 306 | } |
| 307 | return "net.tcp.buffersize." + networkTypeStr; |
| 308 | } |
| 309 | |
| 310 | /** |
| 311 | * Tear down mobile data connectivity, i.e., disable the ability to create |
| 312 | * mobile data connections. |
| 313 | */ |
| 314 | @Override |
| 315 | public boolean teardown() { |
Robert Greenwalt | d1aca6a | 2009-09-25 14:52:34 -0700 | [diff] [blame] | 316 | // since we won't get a notification currently (TODO - per APN notifications) |
| 317 | // we won't get a disconnect message until all APN's on the current connection's |
| 318 | // APN list are disabled. That means privateRoutes for DNS and such will remain on - |
| 319 | // not a problem since that's all shared with whatever other APN is still on, but |
| 320 | // ugly. |
Robert Greenwalt | 25a5d3d | 2009-08-13 15:59:51 -0700 | [diff] [blame] | 321 | setTeardownRequested(true); |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 322 | return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | /** |
| 326 | * Re-enable mobile data connectivity after a {@link #teardown()}. |
| 327 | */ |
| 328 | public boolean reconnect() { |
Robert Greenwalt | 25a5d3d | 2009-08-13 15:59:51 -0700 | [diff] [blame] | 329 | setTeardownRequested(false); |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 330 | switch (setEnableApn(mApnType, true)) { |
| 331 | case Phone.APN_ALREADY_ACTIVE: |
Robert Greenwalt | d1aca6a | 2009-09-25 14:52:34 -0700 | [diff] [blame] | 332 | // TODO - remove this when we get per-apn notifications |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 333 | mEnabled = true; |
Robert Greenwalt | a64bf83 | 2009-08-19 20:19:33 -0700 | [diff] [blame] | 334 | // need to set self to CONNECTING so the below message is handled. |
| 335 | mMobileDataState = Phone.DataState.CONNECTING; |
Robert Greenwalt | ec9fe46 | 2009-08-20 15:25:14 -0700 | [diff] [blame] | 336 | setDetailedState(DetailedState.CONNECTING, Phone.REASON_APN_CHANGED, null); |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 337 | //send out a connected message |
| 338 | Intent intent = new Intent(TelephonyIntents. |
| 339 | ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); |
| 340 | intent.putExtra(Phone.STATE_KEY, Phone.DataState.CONNECTED.toString()); |
| 341 | intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, Phone.REASON_APN_CHANGED); |
| 342 | intent.putExtra(Phone.DATA_APN_TYPES_KEY, mApnType); |
Mike Lockwood | 03d2467 | 2009-10-08 15:45:03 -0400 | [diff] [blame] | 343 | intent.putExtra(Phone.DATA_APN_KEY, mApnName); |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 344 | intent.putExtra(Phone.DATA_IFACE_NAME_KEY, mInterfaceName); |
| 345 | intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, false); |
| 346 | if (mStateReceiver != null) mStateReceiver.onReceive(mContext, intent); |
| 347 | break; |
| 348 | case Phone.APN_REQUEST_STARTED: |
| 349 | mEnabled = true; |
| 350 | // no need to do anything - we're already due some status update intents |
| 351 | break; |
| 352 | case Phone.APN_REQUEST_FAILED: |
Robert Greenwalt | 60a45af | 2009-08-19 11:45:32 -0700 | [diff] [blame] | 353 | if (mPhoneService == null && mApnType == Phone.APN_TYPE_DEFAULT) { |
| 354 | // on startup we may try to talk to the phone before it's ready |
| 355 | // just leave mEnabled as it is for the default apn. |
| 356 | return false; |
| 357 | } |
| 358 | // else fall through |
Robert Greenwalt | c85675d | 2009-08-17 19:27:14 -0700 | [diff] [blame] | 359 | case Phone.APN_TYPE_NOT_AVAILABLE: |
| 360 | mEnabled = false; |
| 361 | break; |
| 362 | default: |
| 363 | Log.e(TAG, "Error in reconnect - unexpected response."); |
| 364 | mEnabled = false; |
| 365 | break; |
| 366 | } |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 367 | return mEnabled; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 368 | } |
| 369 | |
| 370 | /** |
| 371 | * Turn on or off the mobile radio. No connectivity will be possible while the |
| 372 | * radio is off. The operation is a no-op if the radio is already in the desired state. |
| 373 | * @param turnOn {@code true} if the radio should be turned on, {@code false} if |
| 374 | */ |
| 375 | public boolean setRadio(boolean turnOn) { |
| 376 | getPhoneService(false); |
| 377 | /* |
| 378 | * If the phone process has crashed in the past, we'll get a |
| 379 | * RemoteException and need to re-reference the service. |
| 380 | */ |
| 381 | for (int retry = 0; retry < 2; retry++) { |
| 382 | if (mPhoneService == null) { |
| 383 | Log.w(TAG, |
| 384 | "Ignoring mobile radio request because could not acquire PhoneService"); |
| 385 | break; |
| 386 | } |
Wink Saville | 767a662 | 2009-04-02 01:37:02 -0700 | [diff] [blame] | 387 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 388 | try { |
| 389 | return mPhoneService.setRadio(turnOn); |
| 390 | } catch (RemoteException e) { |
| 391 | if (retry == 0) getPhoneService(true); |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | Log.w(TAG, "Could not set radio power to " + (turnOn ? "on" : "off")); |
| 396 | return false; |
| 397 | } |
| 398 | |
| 399 | /** |
| 400 | * Tells the phone sub-system that the caller wants to |
Mike Lockwood | 42ad56e | 2009-04-14 10:56:36 -0400 | [diff] [blame] | 401 | * begin using the named feature. The only supported features at |
| 402 | * this time are {@code Phone.FEATURE_ENABLE_MMS}, which allows an application |
| 403 | * to specify that it wants to send and/or receive MMS data, and |
| 404 | * {@code Phone.FEATURE_ENABLE_SUPL}, which is used for Assisted GPS. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 405 | * @param feature the name of the feature to be used |
| 406 | * @param callingPid the process ID of the process that is issuing this request |
| 407 | * @param callingUid the user ID of the process that is issuing this request |
| 408 | * @return an integer value representing the outcome of the request. |
| 409 | * The interpretation of this value is feature-specific. |
| 410 | * specific, except that the value {@code -1} |
| 411 | * always indicates failure. For {@code Phone.FEATURE_ENABLE_MMS}, |
| 412 | * the other possible return values are |
| 413 | * <ul> |
| 414 | * <li>{@code Phone.APN_ALREADY_ACTIVE}</li> |
| 415 | * <li>{@code Phone.APN_REQUEST_STARTED}</li> |
| 416 | * <li>{@code Phone.APN_TYPE_NOT_AVAILABLE}</li> |
| 417 | * <li>{@code Phone.APN_REQUEST_FAILED}</li> |
| 418 | * </ul> |
| 419 | */ |
| 420 | public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 421 | return -1; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 422 | } |
| 423 | |
| 424 | /** |
| 425 | * Tells the phone sub-system that the caller is finished |
| 426 | * using the named feature. The only supported feature at |
| 427 | * this time is {@code Phone.FEATURE_ENABLE_MMS}, which allows an application |
| 428 | * to specify that it wants to send and/or receive MMS data. |
| 429 | * @param feature the name of the feature that is no longer needed |
| 430 | * @param callingPid the process ID of the process that is issuing this request |
| 431 | * @param callingUid the user ID of the process that is issuing this request |
| 432 | * @return an integer value representing the outcome of the request. |
| 433 | * The interpretation of this value is feature-specific, except that |
| 434 | * the value {@code -1} always indicates failure. |
| 435 | */ |
| 436 | public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { |
Robert Greenwalt | 42acef3 | 2009-08-12 16:08:25 -0700 | [diff] [blame] | 437 | return -1; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 438 | } |
| 439 | |
| 440 | /** |
| 441 | * Ensure that a network route exists to deliver traffic to the specified |
| 442 | * host via the mobile data network. |
| 443 | * @param hostAddress the IP address of the host to which the route is desired, |
| 444 | * in network byte order. |
| 445 | * @return {@code true} on success, {@code false} on failure |
| 446 | */ |
| 447 | @Override |
| 448 | public boolean requestRouteToHost(int hostAddress) { |
Robert Greenwalt | a64bf83 | 2009-08-19 20:19:33 -0700 | [diff] [blame] | 449 | if (DBG) { |
| 450 | Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) + |
| 451 | " for " + mApnType + "(" + mInterfaceName + ")"); |
| 452 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 453 | if (mInterfaceName != null && hostAddress != -1) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 454 | return NetworkUtils.addHostRoute(mInterfaceName, hostAddress) == 0; |
| 455 | } else { |
| 456 | return false; |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | @Override |
| 461 | public String toString() { |
| 462 | StringBuffer sb = new StringBuffer("Mobile data state: "); |
| 463 | |
| 464 | sb.append(mMobileDataState); |
| 465 | return sb.toString(); |
| 466 | } |
| 467 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 468 | /** |
| 469 | * Internal method supporting the ENABLE_MMS feature. |
| 470 | * @param apnType the type of APN to be enabled or disabled (e.g., mms) |
| 471 | * @param enable {@code true} to enable the specified APN type, |
| 472 | * {@code false} to disable it. |
| 473 | * @return an integer value representing the outcome of the request. |
| 474 | */ |
| 475 | private int setEnableApn(String apnType, boolean enable) { |
| 476 | getPhoneService(false); |
| 477 | /* |
| 478 | * If the phone process has crashed in the past, we'll get a |
| 479 | * RemoteException and need to re-reference the service. |
| 480 | */ |
| 481 | for (int retry = 0; retry < 2; retry++) { |
| 482 | if (mPhoneService == null) { |
| 483 | Log.w(TAG, |
| 484 | "Ignoring feature request because could not acquire PhoneService"); |
| 485 | break; |
| 486 | } |
| 487 | |
| 488 | try { |
| 489 | if (enable) { |
| 490 | return mPhoneService.enableApnType(apnType); |
| 491 | } else { |
| 492 | return mPhoneService.disableApnType(apnType); |
| 493 | } |
| 494 | } catch (RemoteException e) { |
| 495 | if (retry == 0) getPhoneService(true); |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | Log.w(TAG, "Could not " + (enable ? "enable" : "disable") |
| 500 | + " APN type \"" + apnType + "\""); |
| 501 | return Phone.APN_REQUEST_FAILED; |
| 502 | } |
Robert Greenwalt | 5154ae76 | 2009-10-30 14:17:42 -0700 | [diff] [blame^] | 503 | |
| 504 | public static String networkTypeToApnType(int netType) { |
| 505 | switch(netType) { |
| 506 | case ConnectivityManager.TYPE_MOBILE: |
| 507 | return Phone.APN_TYPE_DEFAULT; // TODO - use just one of these |
| 508 | case ConnectivityManager.TYPE_MOBILE_MMS: |
| 509 | return Phone.APN_TYPE_MMS; |
| 510 | case ConnectivityManager.TYPE_MOBILE_SUPL: |
| 511 | return Phone.APN_TYPE_SUPL; |
| 512 | case ConnectivityManager.TYPE_MOBILE_DUN: |
| 513 | return Phone.APN_TYPE_DUN; |
| 514 | case ConnectivityManager.TYPE_MOBILE_HIPRI: |
| 515 | return Phone.APN_TYPE_HIPRI; |
| 516 | default: |
| 517 | Log.e(TAG, "Error mapping networkType " + netType + " to apnType."); |
| 518 | return null; |
| 519 | } |
| 520 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 521 | } |