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 if (intent.getAction().equals(TelephonyIntents. 194 ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) { 195 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 196 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 197 if (!TextUtils.equals(mApnType, apnType)) { 198 return; 199 } 200 if (DBG) { 201 log("Broadcast received: " + intent.getAction() + " apnType=" + apnType 202 + " apnName=" + apnName); 203 } 204 205 // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING 206 mMobileDataState = PhoneConstants.DataState.CONNECTING; 207 updateLinkProperitesAndCapatilities(intent); 208 mNetworkInfo.setIsConnectedToProvisioningNetwork(true); 209 210 // Change state to SUSPENDED so setDetailedState 211 // sends EVENT_STATE_CHANGED to connectivityService 212 setDetailedState(DetailedState.SUSPENDED, "", apnName); 213 } else if (intent.getAction().equals(TelephonyIntents. 214 ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 215 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 216 if (!TextUtils.equals(apnType, mApnType)) { 217 return; 218 } 219 // Assume this isn't a provisioning network. 220 mNetworkInfo.setIsConnectedToProvisioningNetwork(false); 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 // Assume this isn't a provisioning network. 303 mNetworkInfo.setIsConnectedToProvisioningNetwork(false); 304 String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY); 305 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); 306 if (DBG) { 307 log("Broadcast received: " + intent.getAction() + 308 " reason=" + reason == null ? "null" : reason); 309 } 310 setDetailedState(DetailedState.FAILED, reason, apnName); 311 } else { 312 if (DBG) log("Broadcast received: ignore " + intent.getAction()); 313 } 314 } 315 } 316 317 private void getPhoneService(boolean forceRefresh) { 318 if ((mPhoneService == null) || forceRefresh) { 319 mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); 320 } 321 } 322 323 /** 324 * Report whether data connectivity is possible. 325 */ 326 public boolean isAvailable() { 327 return mNetworkInfo.isAvailable(); 328 } 329 330 /** 331 * Return the system properties name associated with the tcp buffer sizes 332 * for this network. 333 */ 334 public String getTcpBufferSizesPropName() { 335 String networkTypeStr = "unknown"; 336 TelephonyManager tm = new TelephonyManager(mContext); 337 //TODO We have to edit the parameter for getNetworkType regarding CDMA 338 switch(tm.getNetworkType()) { 339 case TelephonyManager.NETWORK_TYPE_GPRS: 340 networkTypeStr = "gprs"; 341 break; 342 case TelephonyManager.NETWORK_TYPE_EDGE: 343 networkTypeStr = "edge"; 344 break; 345 case TelephonyManager.NETWORK_TYPE_UMTS: 346 networkTypeStr = "umts"; 347 break; 348 case TelephonyManager.NETWORK_TYPE_HSDPA: 349 networkTypeStr = "hsdpa"; 350 break; 351 case TelephonyManager.NETWORK_TYPE_HSUPA: 352 networkTypeStr = "hsupa"; 353 break; 354 case TelephonyManager.NETWORK_TYPE_HSPA: 355 networkTypeStr = "hspa"; 356 break; 357 case TelephonyManager.NETWORK_TYPE_HSPAP: 358 networkTypeStr = "hspap"; 359 break; 360 case TelephonyManager.NETWORK_TYPE_CDMA: 361 networkTypeStr = "cdma"; 362 break; 363 case TelephonyManager.NETWORK_TYPE_1xRTT: 364 networkTypeStr = "1xrtt"; 365 break; 366 case TelephonyManager.NETWORK_TYPE_EVDO_0: 367 networkTypeStr = "evdo"; 368 break; 369 case TelephonyManager.NETWORK_TYPE_EVDO_A: 370 networkTypeStr = "evdo"; 371 break; 372 case TelephonyManager.NETWORK_TYPE_EVDO_B: 373 networkTypeStr = "evdo"; 374 break; 375 case TelephonyManager.NETWORK_TYPE_IDEN: 376 networkTypeStr = "iden"; 377 break; 378 case TelephonyManager.NETWORK_TYPE_LTE: 379 networkTypeStr = "lte"; 380 break; 381 case TelephonyManager.NETWORK_TYPE_EHRPD: 382 networkTypeStr = "ehrpd"; 383 break; 384 default: 385 loge("unknown network type: " + tm.getNetworkType()); 386 } 387 return "net.tcp.buffersize." + networkTypeStr; 388 } 389 390 /** 391 * Tear down mobile data connectivity, i.e., disable the ability to create 392 * mobile data connections. 393 * TODO - make async and return nothing? 394 */ 395 public boolean teardown() { 396 setTeardownRequested(true); 397 return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED); 398 } 399 400 /** 401 * @return true if this is ready to operate 402 */ 403 public boolean isReady() { 404 return mDataConnectionTrackerAc != null; 405 } 406 407 @Override 408 public void captivePortalCheckComplete() { 409 // not implemented 410 } 411 412 @Override 413 public void captivePortalCheckCompleted(boolean isCaptivePortal) { 414 if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { 415 // Captive portal change enable/disable failing fast 416 setEnableFailFastMobileData( 417 isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); 418 } 419 } 420 421 /** 422 * Record the detailed state of a network, and if it is a 423 * change from the previous state, send a notification to 424 * any listeners. 425 * @param state the new {@code DetailedState} 426 * @param reason a {@code String} indicating a reason for the state change, 427 * if one was supplied. May be {@code null}. 428 * @param extraInfo optional {@code String} providing extra information about the state change 429 */ 430 private void setDetailedState(NetworkInfo.DetailedState state, String reason, 431 String extraInfo) { 432 if (DBG) log("setDetailed state, old =" 433 + mNetworkInfo.getDetailedState() + " and new state=" + state); 434 if (state != mNetworkInfo.getDetailedState()) { 435 boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); 436 String lastReason = mNetworkInfo.getReason(); 437 /* 438 * If a reason was supplied when the CONNECTING state was entered, and no 439 * reason was supplied for entering the CONNECTED state, then retain the 440 * reason that was supplied when going to CONNECTING. 441 */ 442 if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null 443 && lastReason != null) 444 reason = lastReason; 445 mNetworkInfo.setDetailedState(state, reason, extraInfo); 446 Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)); 447 msg.sendToTarget(); 448 } 449 } 450 451 public void setTeardownRequested(boolean isRequested) { 452 mTeardownRequested = isRequested; 453 } 454 455 public boolean isTeardownRequested() { 456 return mTeardownRequested; 457 } 458 459 /** 460 * Re-enable mobile data connectivity after a {@link #teardown()}. 461 * TODO - make async and always get a notification? 462 */ 463 public boolean reconnect() { 464 boolean retValue = false; //connected or expect to be? 465 setTeardownRequested(false); 466 switch (setEnableApn(mApnType, true)) { 467 case PhoneConstants.APN_ALREADY_ACTIVE: 468 // need to set self to CONNECTING so the below message is handled. 469 retValue = true; 470 break; 471 case PhoneConstants.APN_REQUEST_STARTED: 472 // set IDLE here , avoid the following second FAILED not sent out 473 mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); 474 retValue = true; 475 break; 476 case PhoneConstants.APN_REQUEST_FAILED: 477 case PhoneConstants.APN_TYPE_NOT_AVAILABLE: 478 break; 479 default: 480 loge("Error in reconnect - unexpected response."); 481 break; 482 } 483 return retValue; 484 } 485 486 /** 487 * Turn on or off the mobile radio. No connectivity will be possible while the 488 * radio is off. The operation is a no-op if the radio is already in the desired state. 489 * @param turnOn {@code true} if the radio should be turned on, {@code false} if 490 */ 491 public boolean setRadio(boolean turnOn) { 492 getPhoneService(false); 493 /* 494 * If the phone process has crashed in the past, we'll get a 495 * RemoteException and need to re-reference the service. 496 */ 497 for (int retry = 0; retry < 2; retry++) { 498 if (mPhoneService == null) { 499 loge("Ignoring mobile radio request because could not acquire PhoneService"); 500 break; 501 } 502 503 try { 504 return mPhoneService.setRadio(turnOn); 505 } catch (RemoteException e) { 506 if (retry == 0) getPhoneService(true); 507 } 508 } 509 510 loge("Could not set radio power to " + (turnOn ? "on" : "off")); 511 return false; 512 } 513 514 @Override 515 public void setUserDataEnable(boolean enabled) { 516 if (DBG) log("setUserDataEnable: E enabled=" + enabled); 517 final AsyncChannel channel = mDataConnectionTrackerAc; 518 if (channel != null) { 519 channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE, 520 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 521 mUserDataEnabled = enabled; 522 } 523 if (VDBG) log("setUserDataEnable: X enabled=" + enabled); 524 } 525 526 @Override 527 public void setPolicyDataEnable(boolean enabled) { 528 if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")"); 529 final AsyncChannel channel = mDataConnectionTrackerAc; 530 if (channel != null) { 531 channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE, 532 enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 533 mPolicyDataEnabled = enabled; 534 } 535 } 536 537 /** 538 * Eanble/disable FailFast 539 * 540 * @param enabled is DctConstants.ENABLED/DISABLED 541 */ 542 public void setEnableFailFastMobileData(int enabled) { 543 if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")"); 544 final AsyncChannel channel = mDataConnectionTrackerAc; 545 if (channel != null) { 546 channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled); 547 } 548 } 549 550 /** 551 * carrier dependency is met/unmet 552 * @param met 553 */ 554 public void setDependencyMet(boolean met) { 555 Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType); 556 try { 557 if (DBG) log("setDependencyMet: E met=" + met); 558 Message msg = Message.obtain(); 559 msg.what = DctConstants.CMD_SET_DEPENDENCY_MET; 560 msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED); 561 msg.setData(bundle); 562 mDataConnectionTrackerAc.sendMessage(msg); 563 if (VDBG) log("setDependencyMet: X met=" + met); 564 } catch (NullPointerException e) { 565 loge("setDependencyMet: X mAc was null" + e); 566 } 567 } 568 569 /** 570 * Inform DCT mobile provisioning has started, it ends when provisioning completes. 571 */ 572 public void enableMobileProvisioning(String url) { 573 if (DBG) log("enableMobileProvisioning(url=" + url + ")"); 574 final AsyncChannel channel = mDataConnectionTrackerAc; 575 if (channel != null) { 576 Message msg = Message.obtain(); 577 msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING; 578 msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url)); 579 channel.sendMessage(msg); 580 } 581 } 582 583 /** 584 * Return if this network is the provisioning network. Valid only if connected. 585 * @param met 586 */ 587 public boolean isProvisioningNetwork() { 588 boolean retVal; 589 try { 590 Message msg = Message.obtain(); 591 msg.what = DctConstants.CMD_IS_PROVISIONING_APN; 592 msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType)); 593 Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg); 594 retVal = result.arg1 == DctConstants.ENABLED; 595 } catch (NullPointerException e) { 596 loge("isProvisioningNetwork: X " + e); 597 retVal = false; 598 } 599 if (DBG) log("isProvisioningNetwork: retVal=" + retVal); 600 return retVal; 601 } 602 603 @Override 604 public void addStackedLink(LinkProperties link) { 605 mLinkProperties.addStackedLink(link); 606 } 607 608 @Override 609 public void removeStackedLink(LinkProperties link) { 610 mLinkProperties.removeStackedLink(link); 611 } 612 613 @Override 614 public String toString() { 615 final CharArrayWriter writer = new CharArrayWriter(); 616 final PrintWriter pw = new PrintWriter(writer); 617 pw.print("Mobile data state: "); pw.println(mMobileDataState); 618 pw.print("Data enabled: user="); pw.print(mUserDataEnabled); 619 pw.print(", policy="); pw.println(mPolicyDataEnabled); 620 return writer.toString(); 621 } 622 623 /** 624 * Internal method supporting the ENABLE_MMS feature. 625 * @param apnType the type of APN to be enabled or disabled (e.g., mms) 626 * @param enable {@code true} to enable the specified APN type, 627 * {@code false} to disable it. 628 * @return an integer value representing the outcome of the request. 629 */ 630 private int setEnableApn(String apnType, boolean enable) { 631 getPhoneService(false); 632 /* 633 * If the phone process has crashed in the past, we'll get a 634 * RemoteException and need to re-reference the service. 635 */ 636 for (int retry = 0; retry < 2; retry++) { 637 if (mPhoneService == null) { 638 loge("Ignoring feature request because could not acquire PhoneService"); 639 break; 640 } 641 642 try { 643 if (enable) { 644 return mPhoneService.enableApnType(apnType); 645 } else { 646 return mPhoneService.disableApnType(apnType); 647 } 648 } catch (RemoteException e) { 649 if (retry == 0) getPhoneService(true); 650 } 651 } 652 653 loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); 654 return PhoneConstants.APN_REQUEST_FAILED; 655 } 656 657 public static String networkTypeToApnType(int netType) { 658 switch(netType) { 659 case ConnectivityManager.TYPE_MOBILE: 660 return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these 661 case ConnectivityManager.TYPE_MOBILE_MMS: 662 return PhoneConstants.APN_TYPE_MMS; 663 case ConnectivityManager.TYPE_MOBILE_SUPL: 664 return PhoneConstants.APN_TYPE_SUPL; 665 case ConnectivityManager.TYPE_MOBILE_DUN: 666 return PhoneConstants.APN_TYPE_DUN; 667 case ConnectivityManager.TYPE_MOBILE_HIPRI: 668 return PhoneConstants.APN_TYPE_HIPRI; 669 case ConnectivityManager.TYPE_MOBILE_FOTA: 670 return PhoneConstants.APN_TYPE_FOTA; 671 case ConnectivityManager.TYPE_MOBILE_IMS: 672 return PhoneConstants.APN_TYPE_IMS; 673 case ConnectivityManager.TYPE_MOBILE_CBS: 674 return PhoneConstants.APN_TYPE_CBS; 675 default: 676 sloge("Error mapping networkType " + netType + " to apnType."); 677 return null; 678 } 679 } 680 681 /** 682 * @see android.net.NetworkStateTracker#getLinkProperties() 683 */ 684 public LinkProperties getLinkProperties() { 685 return new LinkProperties(mLinkProperties); 686 } 687 688 /** 689 * @see android.net.NetworkStateTracker#getLinkCapabilities() 690 */ 691 public LinkCapabilities getLinkCapabilities() { 692 return new LinkCapabilities(mLinkCapabilities); 693 } 694 695 public void supplyMessenger(Messenger messenger) { 696 if (VDBG) log(mApnType + " got supplyMessenger"); 697 AsyncChannel ac = new AsyncChannel(); 698 ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger); 699 } 700 701 private void log(String s) { 702 Slog.d(TAG, mApnType + ": " + s); 703 } 704 705 private void loge(String s) { 706 Slog.e(TAG, mApnType + ": " + s); 707 } 708 709 static private void sloge(String s) { 710 Slog.e(TAG, s); 711 } 712 } 713