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.net.NetworkInfo.DetailedState; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.Messenger; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.telephony.TelephonyManager; 32 import android.text.TextUtils; 33 import android.util.Slog; 34 35 import com.android.internal.telephony.DctConstants; 36 import com.android.internal.telephony.ITelephony; 37 import com.android.internal.telephony.PhoneConstants; 38 import com.android.internal.telephony.TelephonyIntents; 39 import com.android.internal.util.AsyncChannel; 40 41 import java.io.CharArrayWriter; 42 import java.io.PrintWriter; 43 import java.util.concurrent.atomic.AtomicBoolean; 44 45 /** 46 * Track the state of mobile data connectivity. This is done by 47 * receiving broadcast intents from the Phone process whenever 48 * the state of data connectivity changes. 49 * 50 * {@hide} 51 */ 52 public class MobileDataStateTracker implements NetworkStateTracker { 53 54 private static final String TAG = "MobileDataStateTracker"; 55 private static final boolean DBG = true; 56 private static final boolean VDBG = false; 57 58 private PhoneConstants.DataState mMobileDataState; 59 private ITelephony mPhoneService; 60 61 private String mApnType; 62 private NetworkInfo mNetworkInfo; 63 private boolean mTeardownRequested = false; 64 private Handler mTarget; 65 private Context mContext; 66 private LinkProperties mLinkProperties; 67 private LinkCapabilities mLinkCapabilities; 68 private boolean mPrivateDnsRouteSet = false; 69 private boolean mDefaultRouteSet = false; 70 71 // NOTE: these are only kept for debugging output; actual values are 72 // maintained in DataConnectionTracker. 73 protected boolean mUserDataEnabled = true; 74 protected boolean mPolicyDataEnabled = true; 75 76 private Handler mHandler; 77 private AsyncChannel mDataConnectionTrackerAc; 78 79 private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false); 80 81 /** 82 * Create a new MobileDataStateTracker 83 * @param netType the ConnectivityManager network type 84 * @param tag the name of this network 85 */ 86 public MobileDataStateTracker(int netType, String tag) { 87 mNetworkInfo = new NetworkInfo(netType, 88 TelephonyManager.getDefault().getNetworkType(), tag, 89 TelephonyManager.getDefault().getNetworkTypeName()); 90 mApnType = networkTypeToApnType(netType); 91 } 92 93 /** 94 * Begin monitoring data connectivity. 95 * 96 * @param context is the current Android context 97 * @param target is the Hander to which to return the events. 98 */ 99 public void startMonitoring(Context context, Handler target) { 100 mTarget = target; 101 mContext = context; 102 103 mHandler = new MdstHandler(target.getLooper(), this); 104 105 IntentFilter filter = new IntentFilter(); 106 filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 107 filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN); 108 filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); 109 110 mContext.registerReceiver(new MobileDataStateReceiver(), filter); 111 mMobileDataState = PhoneConstants.DataState.DISCONNECTED; 112 } 113 114 static class MdstHandler extends Handler { 115 private MobileDataStateTracker mMdst; 116 117 MdstHandler(Looper looper, MobileDataStateTracker mdst) { 118 super(looper); 119 mMdst = mdst; 120 } 121 122 @Override 123 public void handleMessage(Message msg) { 124 switch (msg.what) { 125 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 126 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 127 if (VDBG) { 128 mMdst.log("MdstHandler connected"); 129 } 130 mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj; 131 } else { 132 if (VDBG) { 133 mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1); 134 } 135 } 136 break; 137 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 138 if (VDBG) mMdst.log("Disconnected from DataStateTracker"); 139 mMdst.mDataConnectionTrackerAc = null; 140 break; 141 default: { 142 if (VDBG) mMdst.log("Ignorning unknown message=" + msg); 143 break; 144 } 145 } 146 } 147 } 148 149 public boolean isPrivateDnsRouteSet() { 150 return mPrivateDnsRouteSet; 151 } 152 153 public void privateDnsRouteSet(boolean enabled) { 154 mPrivateDnsRouteSet = enabled; 155 } 156 157 public NetworkInfo getNetworkInfo() { 158 return mNetworkInfo; 159 } 160 161 public boolean isDefaultRouteSet() { 162 return mDefaultRouteSet; 163 } 164 165 public void defaultRouteSet(boolean enabled) { 166 mDefaultRouteSet = enabled; 167 } 168 169 /** 170 * This is not implemented. 171 */ 172 public void releaseWakeLock() { 173 } 174 175 private void updateLinkProperitesAndCapatilities(Intent intent) { 176 mLinkProperties = intent.getParcelableExtra( 177 PhoneConstants.DATA_LINK_PROPERTIES_KEY); 178 if (mLinkProperties == null) { 179 loge("CONNECTED event did not supply link properties."); 180 mLinkProperties = new LinkProperties(); 181 } 182 mLinkCapabilities = intent.getParcelableExtra( 183 PhoneConstants.DATA_LINK_CAPABILITIES_KEY); 184 if (mLinkCapabilities == null) { 185 loge("CONNECTED event did not supply link capabilities."); 186 mLinkCapabilities = new LinkCapabilities(); 187 } 188 } 189 190 private class MobileDataStateReceiver extends BroadcastReceiver { 191 @Override 192 public void onReceive(Context context, Intent intent) { 193 // Assume this isn't a provisioning network. 194 mNetworkInfo.setIsConnectedToProvisioningNetwork(false); 195 if (intent.getAction().equals(TelephonyIntents. 196 ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) { 197 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 198 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 199 if (!TextUtils.equals(mApnType, apnType)) { 200 return; 201 } 202 if (DBG) { 203 log("Broadcast received: " + intent.getAction() + " apnType=" + apnType 204 + " apnName=" + apnName); 205 } 206 207 // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING 208 mMobileDataState = PhoneConstants.DataState.CONNECTING; 209 updateLinkProperitesAndCapatilities(intent); 210 mNetworkInfo.setIsConnectedToProvisioningNetwork(true); 211 212 // Change state to SUSPENDED so setDetailedState 213 // sends EVENT_STATE_CHANGED to connectivityService 214 setDetailedState(DetailedState.SUSPENDED, "", apnName); 215 } else if (intent.getAction().equals(TelephonyIntents. 216 ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 217 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 218 if (!TextUtils.equals(apnType, mApnType)) { 219 return; 220 } 221 if (DBG) { 222 log("Broadcast received: " + intent.getAction() + " apnType=" + apnType); 223 } 224 225 int oldSubtype = mNetworkInfo.getSubtype(); 226 int newSubType = TelephonyManager.getDefault().getNetworkType(); 227 String subTypeName = TelephonyManager.getDefault().getNetworkTypeName(); 228 mNetworkInfo.setSubtype(newSubType, subTypeName); 229 if (newSubType != oldSubtype && mNetworkInfo.isConnected()) { 230 Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED, 231 oldSubtype, 0, mNetworkInfo); 232 msg.sendToTarget(); 233 } 234 235 PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class, 236 intent.getStringExtra(PhoneConstants.STATE_KEY)); 237 String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY); 238 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 239 mNetworkInfo.setRoaming(intent.getBooleanExtra( 240 PhoneConstants.DATA_NETWORK_ROAMING_KEY, false)); 241 if (DBG) { 242 log(mApnType + " setting isAvailable to " + 243 intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false)); 244 } 245 mNetworkInfo.setIsAvailable(!intent.getBooleanExtra( 246 PhoneConstants.NETWORK_UNAVAILABLE_KEY, false)); 247 248 if (DBG) { 249 log("Received state=" + state + ", old=" + mMobileDataState + 250 ", reason=" + (reason == null ? "(unspecified)" : reason)); 251 } 252 if (mMobileDataState != state) { 253 mMobileDataState = state; 254 switch (state) { 255 case DISCONNECTED: 256 if(isTeardownRequested()) { 257 setTeardownRequested(false); 258 } 259 260 setDetailedState(DetailedState.DISCONNECTED, reason, apnName); 261 // can't do this here - ConnectivityService needs it to clear stuff 262 // it's ok though - just leave it to be refreshed next time 263 // we connect. 264 //if (DBG) log("clearing mInterfaceName for "+ mApnType + 265 // " as it DISCONNECTED"); 266 //mInterfaceName = null; 267 break; 268 case CONNECTING: 269 setDetailedState(DetailedState.CONNECTING, reason, apnName); 270 break; 271 case SUSPENDED: 272 setDetailedState(DetailedState.SUSPENDED, reason, apnName); 273 break; 274 case CONNECTED: 275 updateLinkProperitesAndCapatilities(intent); 276 setDetailedState(DetailedState.CONNECTED, reason, apnName); 277 break; 278 } 279 } else { 280 // There was no state change. Check if LinkProperties has been updated. 281 if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { 282 mLinkProperties = intent.getParcelableExtra( 283 PhoneConstants.DATA_LINK_PROPERTIES_KEY); 284 if (mLinkProperties == null) { 285 loge("No link property in LINK_PROPERTIES change event."); 286 mLinkProperties = new LinkProperties(); 287 } 288 // Just update reason field in this NetworkInfo 289 mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason, 290 mNetworkInfo.getExtraInfo()); 291 Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, 292 mNetworkInfo); 293 msg.sendToTarget(); 294 } 295 } 296 } else if (intent.getAction(). 297 equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { 298 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 299 if (!TextUtils.equals(apnType, mApnType)) { 300 return; 301 } 302 String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY); 303 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 304 if (DBG) { 305 log("Broadcast received: " + intent.getAction() + 306 " reason=" + reason == null ? "null" : reason); 307 } 308 setDetailedState(DetailedState.FAILED, reason, apnName); 309 } else { 310 if (DBG) log("Broadcast received: ignore " + intent.getAction()); 311 } 312 } 313 } 314 315 private void getPhoneService(boolean forceRefresh) { 316 if ((mPhoneService == null) || forceRefresh) { 317 mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); 318 } 319 } 320 321 /** 322 * Report whether data connectivity is possible. 323 */ 324 public boolean isAvailable() { 325 return mNetworkInfo.isAvailable(); 326 } 327 328 /** 329 * Return the system properties name associated with the tcp buffer sizes 330 * for this network. 331 */ 332 public String getTcpBufferSizesPropName() { 333 String networkTypeStr = "unknown"; 334 TelephonyManager tm = new TelephonyManager(mContext); 335 //TODO We have to edit the parameter for getNetworkType regarding CDMA 336 switch(tm.getNetworkType()) { 337 case TelephonyManager.NETWORK_TYPE_GPRS: 338 networkTypeStr = "gprs"; 339 break; 340 case TelephonyManager.NETWORK_TYPE_EDGE: 341 networkTypeStr = "edge"; 342 break; 343 case TelephonyManager.NETWORK_TYPE_UMTS: 344 networkTypeStr = "umts"; 345 break; 346 case TelephonyManager.NETWORK_TYPE_HSDPA: 347 networkTypeStr = "hsdpa"; 348 break; 349 case TelephonyManager.NETWORK_TYPE_HSUPA: 350 networkTypeStr = "hsupa"; 351 break; 352 case TelephonyManager.NETWORK_TYPE_HSPA: 353 networkTypeStr = "hspa"; 354 break; 355 case TelephonyManager.NETWORK_TYPE_HSPAP: 356 networkTypeStr = "hspap"; 357 break; 358 case TelephonyManager.NETWORK_TYPE_CDMA: 359 networkTypeStr = "cdma"; 360 break; 361 case TelephonyManager.NETWORK_TYPE_1xRTT: 362 networkTypeStr = "1xrtt"; 363 break; 364 case TelephonyManager.NETWORK_TYPE_EVDO_0: 365 networkTypeStr = "evdo"; 366 break; 367 case TelephonyManager.NETWORK_TYPE_EVDO_A: 368 networkTypeStr = "evdo"; 369 break; 370 case TelephonyManager.NETWORK_TYPE_EVDO_B: 371 networkTypeStr = "evdo"; 372 break; 373 case TelephonyManager.NETWORK_TYPE_IDEN: 374 networkTypeStr = "iden"; 375 break; 376 case TelephonyManager.NETWORK_TYPE_LTE: 377 networkTypeStr = "lte"; 378 break; 379 case TelephonyManager.NETWORK_TYPE_EHRPD: 380 networkTypeStr = "ehrpd"; 381 break; 382 default: 383 loge("unknown network type: " + tm.getNetworkType()); 384 } 385 return "net.tcp.buffersize." + networkTypeStr; 386 } 387 388 /** 389 * Tear down mobile data connectivity, i.e., disable the ability to create 390 * mobile data connections. 391 * TODO - make async and return nothing? 392 */ 393 public boolean teardown() { 394 setTeardownRequested(true); 395 return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED); 396 } 397 398 /** 399 * @return true if this is ready to operate 400 */ 401 public boolean isReady() { 402 return mDataConnectionTrackerAc != null; 403 } 404 405 @Override 406 public void captivePortalCheckComplete() { 407 // not implemented 408 } 409 410 @Override 411 public void captivePortalCheckCompleted(boolean isCaptivePortal) { 412 if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { 413 // Captive portal change enable/disable failing fast 414 setEnableFailFastMobileData( 415 isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); 416 } 417 } 418 419 /** 420 * Record the detailed state of a network, and if it is a 421 * change from the previous state, send a notification to 422 * any listeners. 423 * @param state the new {@code DetailedState} 424 * @param reason a {@code String} indicating a reason for the state change, 425 * if one was supplied. May be {@code null}. 426 * @param extraInfo optional {@code String} providing extra information about the state change 427 */ 428 private void setDetailedState(NetworkInfo.DetailedState state, String reason, 429 String extraInfo) { 430 if (DBG) log("setDetailed state, old =" 431 + mNetworkInfo.getDetailedState() + " and new state=" + state); 432 if (state != mNetworkInfo.getDetailedState()) { 433 boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); 434 String lastReason = mNetworkInfo.getReason(); 435 /* 436 * If a reason was supplied when the CONNECTING state was entered, and no 437 * reason was supplied for entering the CONNECTED state, then retain the 438 * reason that was supplied when going to CONNECTING. 439 */ 440 if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null 441 && lastReason != null) 442 reason = lastReason; 443 mNetworkInfo.setDetailedState(state, reason, extraInfo); 444 Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)); 445 msg.sendToTarget(); 446 } 447 } 448 449 public void setTeardownRequested(boolean isRequested) { 450 mTeardownRequested = isRequested; 451 } 452 453 public boolean isTeardownRequested() { 454 return mTeardownRequested; 455 } 456 457 /** 458 * Re-enable mobile data connectivity after a {@link #teardown()}. 459 * TODO - make async and always get a notification? 460 */ 461 public boolean reconnect() { 462 boolean retValue = false; //connected or expect to be? 463 setTeardownRequested(false); 464 switch (setEnableApn(mApnType, true)) { 465 case PhoneConstants.APN_ALREADY_ACTIVE: 466 // need to set self to CONNECTING so the below message is handled. 467 retValue = true; 468 break; 469 case PhoneConstants.APN_REQUEST_STARTED: 470 // set IDLE here , avoid the following second FAILED not sent out 471 mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); 472 retValue = true; 473 break; 474 case PhoneConstants.APN_REQUEST_FAILED: 475 case PhoneConstants.APN_TYPE_NOT_AVAILABLE: 476 break; 477 default: 478 loge("Error in reconnect - unexpected response."); 479 break; 480 } 481 return retValue; 482 } 483 484 /** 485 * Turn on or off the mobile radio. No connectivity will be possible while the 486 * radio is off. The operation is a no-op if the radio is already in the desired state. 487 * @param turnOn {@code true} if the radio should be turned on, {@code false} if 488 */ 489 public boolean setRadio(boolean turnOn) { 490 getPhoneService(false); 491 /* 492 * If the phone process has crashed in the past, we'll get a 493 * RemoteException and need to re-reference the service. 494 */ 495 for (int retry = 0; retry < 2; retry++) { 496 if (mPhoneService == null) { 497 loge("Ignoring mobile radio request because could not acquire PhoneService"); 498 break; 499 } 500 501 try { 502 return mPhoneService.setRadio(turnOn); 503 } catch (RemoteException e) { 504 if (retry == 0) getPhoneService(true); 505 } 506 } 507 508 loge("Could not set radio power to " + (turnOn ? "on" : "off")); 509 return false; 510 } 511 512 @Override 513 public void setUserDataEnable(boolean enabled) { 514 if (DBG) log("setUserDataEnable: E enabled=" + enabled); 515 final AsyncChannel channel = mDataConnectionTrackerAc; 516 if (channel != null) { 517 channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE, 518 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 519 mUserDataEnabled = enabled; 520 } 521 if (VDBG) log("setUserDataEnable: X enabled=" + enabled); 522 } 523 524 @Override 525 public void setPolicyDataEnable(boolean enabled) { 526 if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")"); 527 final AsyncChannel channel = mDataConnectionTrackerAc; 528 if (channel != null) { 529 channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE, 530 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 531 mPolicyDataEnabled = enabled; 532 } 533 } 534 535 /** 536 * Eanble/disable FailFast 537 * 538 * @param enabled is DctConstants.ENABLED/DISABLED 539 */ 540 public void setEnableFailFastMobileData(int enabled) { 541 if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")"); 542 final AsyncChannel channel = mDataConnectionTrackerAc; 543 if (channel != null) { 544 channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled); 545 } 546 } 547 548 /** 549 * carrier dependency is met/unmet 550 * @param met 551 */ 552 public void setDependencyMet(boolean met) { 553 Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType); 554 try { 555 if (DBG) log("setDependencyMet: E met=" + met); 556 Message msg = Message.obtain(); 557 msg.what = DctConstants.CMD_SET_DEPENDENCY_MET; 558 msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED); 559 msg.setData(bundle); 560 mDataConnectionTrackerAc.sendMessage(msg); 561 if (VDBG) log("setDependencyMet: X met=" + met); 562 } catch (NullPointerException e) { 563 loge("setDependencyMet: X mAc was null" + e); 564 } 565 } 566 567 /** 568 * Inform DCT mobile provisioning has started, it ends when provisioning completes. 569 */ 570 public void enableMobileProvisioning(String url) { 571 if (DBG) log("enableMobileProvisioning(url=" + url + ")"); 572 final AsyncChannel channel = mDataConnectionTrackerAc; 573 if (channel != null) { 574 Message msg = Message.obtain(); 575 msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING; 576 msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url)); 577 channel.sendMessage(msg); 578 } 579 } 580 581 /** 582 * Return if this network is the provisioning network. Valid only if connected. 583 * @param met 584 */ 585 public boolean isProvisioningNetwork() { 586 boolean retVal; 587 try { 588 Message msg = Message.obtain(); 589 msg.what = DctConstants.CMD_IS_PROVISIONING_APN; 590 msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType)); 591 Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg); 592 retVal = result.arg1 == DctConstants.ENABLED; 593 } catch (NullPointerException e) { 594 loge("isProvisioningNetwork: X " + e); 595 retVal = false; 596 } 597 if (DBG) log("isProvisioningNetwork: retVal=" + retVal); 598 return retVal; 599 } 600 601 @Override 602 public void addStackedLink(LinkProperties link) { 603 mLinkProperties.addStackedLink(link); 604 } 605 606 @Override 607 public void removeStackedLink(LinkProperties link) { 608 mLinkProperties.removeStackedLink(link); 609 } 610 611 @Override 612 public String toString() { 613 final CharArrayWriter writer = new CharArrayWriter(); 614 final PrintWriter pw = new PrintWriter(writer); 615 pw.print("Mobile data state: "); pw.println(mMobileDataState); 616 pw.print("Data enabled: user="); pw.print(mUserDataEnabled); 617 pw.print(", policy="); pw.println(mPolicyDataEnabled); 618 return writer.toString(); 619 } 620 621 /** 622 * Internal method supporting the ENABLE_MMS feature. 623 * @param apnType the type of APN to be enabled or disabled (e.g., mms) 624 * @param enable {@code true} to enable the specified APN type, 625 * {@code false} to disable it. 626 * @return an integer value representing the outcome of the request. 627 */ 628 private int setEnableApn(String apnType, boolean enable) { 629 getPhoneService(false); 630 /* 631 * If the phone process has crashed in the past, we'll get a 632 * RemoteException and need to re-reference the service. 633 */ 634 for (int retry = 0; retry < 2; retry++) { 635 if (mPhoneService == null) { 636 loge("Ignoring feature request because could not acquire PhoneService"); 637 break; 638 } 639 640 try { 641 if (enable) { 642 return mPhoneService.enableApnType(apnType); 643 } else { 644 return mPhoneService.disableApnType(apnType); 645 } 646 } catch (RemoteException e) { 647 if (retry == 0) getPhoneService(true); 648 } 649 } 650 651 loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); 652 return PhoneConstants.APN_REQUEST_FAILED; 653 } 654 655 public static String networkTypeToApnType(int netType) { 656 switch(netType) { 657 case ConnectivityManager.TYPE_MOBILE: 658 return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these 659 case ConnectivityManager.TYPE_MOBILE_MMS: 660 return PhoneConstants.APN_TYPE_MMS; 661 case ConnectivityManager.TYPE_MOBILE_SUPL: 662 return PhoneConstants.APN_TYPE_SUPL; 663 case ConnectivityManager.TYPE_MOBILE_DUN: 664 return PhoneConstants.APN_TYPE_DUN; 665 case ConnectivityManager.TYPE_MOBILE_HIPRI: 666 return PhoneConstants.APN_TYPE_HIPRI; 667 case ConnectivityManager.TYPE_MOBILE_FOTA: 668 return PhoneConstants.APN_TYPE_FOTA; 669 case ConnectivityManager.TYPE_MOBILE_IMS: 670 return PhoneConstants.APN_TYPE_IMS; 671 case ConnectivityManager.TYPE_MOBILE_CBS: 672 return PhoneConstants.APN_TYPE_CBS; 673 default: 674 sloge("Error mapping networkType " + netType + " to apnType."); 675 return null; 676 } 677 } 678 679 /** 680 * @see android.net.NetworkStateTracker#getLinkProperties() 681 */ 682 public LinkProperties getLinkProperties() { 683 return new LinkProperties(mLinkProperties); 684 } 685 686 /** 687 * @see android.net.NetworkStateTracker#getLinkCapabilities() 688 */ 689 public LinkCapabilities getLinkCapabilities() { 690 return new LinkCapabilities(mLinkCapabilities); 691 } 692 693 public void supplyMessenger(Messenger messenger) { 694 if (VDBG) log(mApnType + " got supplyMessenger"); 695 AsyncChannel ac = new AsyncChannel(); 696 ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger); 697 } 698 699 private void log(String s) { 700 Slog.d(TAG, mApnType + ": " + s); 701 } 702 703 private void loge(String s) { 704 Slog.e(TAG, mApnType + ": " + s); 705 } 706 707 static private void sloge(String s) { 708 Slog.e(TAG, s); 709 } 710 } 711