1 /* 2 * Copyright (C) 2016 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.internal.telephony.dataconnection; 18 19 20 import static android.telephony.PhoneStateListener.LISTEN_CALL_STATE; 21 import static android.telephony.PhoneStateListener.LISTEN_NONE; 22 23 import android.annotation.IntDef; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.os.Handler; 27 import android.os.RegistrantList; 28 import android.os.SystemProperties; 29 import android.provider.Settings; 30 import android.sysprop.TelephonyProperties; 31 import android.telephony.Annotation.CallState; 32 import android.telephony.CarrierConfigManager; 33 import android.telephony.PhoneStateListener; 34 import android.telephony.SubscriptionInfo; 35 import android.telephony.SubscriptionManager; 36 import android.telephony.TelephonyManager; 37 import android.telephony.data.ApnSetting; 38 import android.util.LocalLog; 39 import android.util.Pair; 40 41 import com.android.internal.telephony.GlobalSettingsHelper; 42 import com.android.internal.telephony.MultiSimSettingController; 43 import com.android.internal.telephony.Phone; 44 import com.android.internal.telephony.SubscriptionController; 45 import com.android.internal.telephony.data.DataEnabledOverride; 46 import com.android.telephony.Rlog; 47 48 import java.io.FileDescriptor; 49 import java.io.PrintWriter; 50 import java.lang.annotation.Retention; 51 import java.lang.annotation.RetentionPolicy; 52 53 /** 54 * The class to hold different data enabled/disabled settings. Also it allows clients to register 55 * for overall data enabled setting changed event. 56 * @hide 57 */ 58 public class DataEnabledSettings { 59 60 private static final String LOG_TAG = "DataEnabledSettings"; 61 62 @Retention(RetentionPolicy.SOURCE) 63 @IntDef(prefix = {"REASON_"}, 64 value = { 65 REASON_REGISTERED, 66 REASON_INTERNAL_DATA_ENABLED, 67 REASON_USER_DATA_ENABLED, 68 REASON_POLICY_DATA_ENABLED, 69 REASON_DATA_ENABLED_BY_CARRIER, 70 REASON_PROVISIONED_CHANGED, 71 REASON_PROVISIONING_DATA_ENABLED_CHANGED, 72 REASON_OVERRIDE_RULE_CHANGED, 73 REASON_OVERRIDE_CONDITION_CHANGED, 74 REASON_THERMAL_DATA_ENABLED 75 }) 76 public @interface DataEnabledChangedReason {} 77 78 public static final int REASON_REGISTERED = 0; 79 80 public static final int REASON_INTERNAL_DATA_ENABLED = 1; 81 82 public static final int REASON_USER_DATA_ENABLED = 2; 83 84 public static final int REASON_POLICY_DATA_ENABLED = 3; 85 86 public static final int REASON_DATA_ENABLED_BY_CARRIER = 4; 87 88 public static final int REASON_PROVISIONED_CHANGED = 5; 89 90 public static final int REASON_PROVISIONING_DATA_ENABLED_CHANGED = 6; 91 92 public static final int REASON_OVERRIDE_RULE_CHANGED = 7; 93 94 public static final int REASON_OVERRIDE_CONDITION_CHANGED = 8; 95 96 public static final int REASON_THERMAL_DATA_ENABLED = 9; 97 98 /** 99 * responds to the setInternalDataEnabled call - used internally to turn off data. 100 * For example during emergency calls 101 */ 102 private boolean mInternalDataEnabled = true; 103 104 /** 105 * Flag indicating data allowed by network policy manager or not. 106 */ 107 private boolean mPolicyDataEnabled = true; 108 109 /** 110 * Indicate if metered APNs are enabled by the carrier. set false to block all the metered APNs 111 * from continuously sending requests, which causes undesired network load. 112 */ 113 private boolean mCarrierDataEnabled = true; 114 115 /** 116 * Flag indicating data allowed by Thermal service or not. 117 */ 118 private boolean mThermalDataEnabled = true; 119 120 /** 121 * Flag indicating whether data is allowed or not for the device. It can be disabled by 122 * user, carrier, policy or thermal 123 */ 124 private boolean mIsDataEnabled = false; 125 126 private final Phone mPhone; 127 128 private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 129 130 private ContentResolver mResolver = null; 131 132 private final RegistrantList mOverallDataEnabledChangedRegistrants = new RegistrantList(); 133 134 // TODO: Merge this with mOverallDataEnabledChangedRegistrants. In the future, notifying data 135 // enabled changed with APN types bitmask 136 private final RegistrantList mOverallDataEnabledOverrideChangedRegistrants = 137 new RegistrantList(); 138 139 private final LocalLog mSettingChangeLocalLog = new LocalLog(32); 140 141 private DataEnabledOverride mDataEnabledOverride; 142 143 private TelephonyManager mTelephonyManager; 144 145 // for msim, user data enabled setting depends on subId. 146 private final SubscriptionManager.OnSubscriptionsChangedListener 147 mOnSubscriptionsChangeListener = 148 new SubscriptionManager.OnSubscriptionsChangedListener() { 149 @Override 150 public void onSubscriptionsChanged() { 151 synchronized (this) { 152 if (mSubId != mPhone.getSubId()) { 153 log("onSubscriptionsChanged subId: " + mSubId + " to: " 154 + mPhone.getSubId()); 155 mSubId = mPhone.getSubId(); 156 mDataEnabledOverride = getDataEnabledOverride(); 157 updatePhoneStateListener(); 158 updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); 159 mPhone.notifyUserMobileDataStateChanged(isUserDataEnabled()); 160 } 161 } 162 } 163 }; 164 updatePhoneStateListener()165 private void updatePhoneStateListener() { 166 mTelephonyManager.listen(mPhoneStateListener, LISTEN_NONE); 167 if (SubscriptionManager.isUsableSubscriptionId(mSubId)) { 168 mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); 169 } 170 mTelephonyManager.listen(mPhoneStateListener, LISTEN_CALL_STATE); 171 } 172 173 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 174 @Override 175 public void onCallStateChanged(@CallState int state, String phoneNumber) { 176 updateDataEnabledAndNotify(REASON_OVERRIDE_CONDITION_CHANGED); 177 } 178 }; 179 180 @Override toString()181 public String toString() { 182 return "[mInternalDataEnabled=" + mInternalDataEnabled 183 + ", isUserDataEnabled=" + isUserDataEnabled() 184 + ", isProvisioningDataEnabled=" + isProvisioningDataEnabled() 185 + ", mPolicyDataEnabled=" + mPolicyDataEnabled 186 + ", mCarrierDataEnabled=" + mCarrierDataEnabled 187 + ", mIsDataEnabled=" + mIsDataEnabled 188 + ", mThermalDataEnabled=" + mThermalDataEnabled 189 + ", " + mDataEnabledOverride 190 + "]"; 191 } 192 DataEnabledSettings(Phone phone)193 public DataEnabledSettings(Phone phone) { 194 mPhone = phone; 195 mResolver = mPhone.getContext().getContentResolver(); 196 SubscriptionManager subscriptionManager = (SubscriptionManager) mPhone.getContext() 197 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 198 subscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); 199 mTelephonyManager = (TelephonyManager) mPhone.getContext() 200 .getSystemService(Context.TELEPHONY_SERVICE); 201 mDataEnabledOverride = getDataEnabledOverride(); 202 updateDataEnabled(); 203 } 204 getDataEnabledOverride()205 private DataEnabledOverride getDataEnabledOverride() { 206 return new DataEnabledOverride(SubscriptionController.getInstance() 207 .getDataEnabledOverrideRules(mPhone.getSubId())); 208 } 209 setInternalDataEnabled(boolean enabled)210 public synchronized void setInternalDataEnabled(boolean enabled) { 211 if (mInternalDataEnabled != enabled) { 212 localLog("InternalDataEnabled", enabled); 213 mInternalDataEnabled = enabled; 214 updateDataEnabledAndNotify(REASON_INTERNAL_DATA_ENABLED); 215 } 216 } isInternalDataEnabled()217 public synchronized boolean isInternalDataEnabled() { 218 return mInternalDataEnabled; 219 } 220 setUserDataEnabled(boolean enabled)221 private synchronized void setUserDataEnabled(boolean enabled) { 222 // By default the change should propagate to the group. 223 setUserDataEnabled(enabled, true); 224 } 225 226 /** 227 * @param notifyMultiSimSettingController if setUserDataEnabled is already from propagating 228 * from MultiSimSettingController, don't notify MultiSimSettingController again. 229 * For example, if sub1 and sub2 are in the same group and user enables data for sub 230 * 1, sub 2 will also be enabled but with propagateToGroup = false. 231 */ setUserDataEnabled(boolean enabled, boolean notifyMultiSimSettingController)232 public synchronized void setUserDataEnabled(boolean enabled, 233 boolean notifyMultiSimSettingController) { 234 // Can't disable data for stand alone opportunistic subscription. 235 if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext()) && !enabled) return; 236 237 boolean changed = GlobalSettingsHelper.setInt(mPhone.getContext(), 238 Settings.Global.MOBILE_DATA, mPhone.getSubId(), (enabled ? 1 : 0)); 239 if (changed) { 240 localLog("UserDataEnabled", enabled); 241 mPhone.notifyUserMobileDataStateChanged(enabled); 242 updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); 243 if (notifyMultiSimSettingController) { 244 MultiSimSettingController.getInstance().notifyUserDataEnabled( 245 mPhone.getSubId(), enabled); 246 } 247 } 248 } 249 250 /** 251 * Policy control of data connection with reason 252 * @param reason the reason the data enable change is taking place 253 * @param enabled True if enabling the data, otherwise disabling. 254 */ setDataEnabled(@elephonyManager.DataEnabledReason int reason, boolean enabled)255 public synchronized void setDataEnabled(@TelephonyManager.DataEnabledReason int reason, 256 boolean enabled) { 257 switch (reason) { 258 case TelephonyManager.DATA_ENABLED_REASON_USER: 259 setUserDataEnabled(enabled); 260 break; 261 case TelephonyManager.DATA_ENABLED_REASON_CARRIER: 262 setCarrierDataEnabled(enabled); 263 break; 264 case TelephonyManager.DATA_ENABLED_REASON_POLICY: 265 setPolicyDataEnabled(enabled); 266 break; 267 case TelephonyManager.DATA_ENABLED_REASON_THERMAL: 268 setThermalDataEnabled(enabled); 269 break; 270 default: 271 log("Invalid data enable reason " + reason); 272 break; 273 } 274 } 275 isUserDataEnabled()276 public synchronized boolean isUserDataEnabled() { 277 // User data should always be true for opportunistic subscription. 278 if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext())) return true; 279 280 boolean defaultVal = TelephonyProperties.mobile_data().orElse(true); 281 282 return GlobalSettingsHelper.getBoolean(mPhone.getContext(), 283 Settings.Global.MOBILE_DATA, mPhone.getSubId(), defaultVal); 284 } 285 286 /** 287 * Set whether always allowing MMS data connection. 288 * 289 * @param alwaysAllow {@code true} if MMS data is always allowed. 290 * 291 * @return {@code false} if the setting is changed. 292 */ setAlwaysAllowMmsData(boolean alwaysAllow)293 public synchronized boolean setAlwaysAllowMmsData(boolean alwaysAllow) { 294 localLog("setAlwaysAllowMmsData", alwaysAllow); 295 mDataEnabledOverride.setAlwaysAllowMms(alwaysAllow); 296 boolean changed = SubscriptionController.getInstance() 297 .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); 298 if (changed) { 299 updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); 300 notifyDataEnabledOverrideChanged(); 301 } 302 303 return changed; 304 } 305 306 /** 307 * Set allowing mobile data during voice call. This is used for allowing data on the non-default 308 * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will 309 * not be able to use mobile data. By calling this API, data will be temporarily enabled on the 310 * non-default data SIM during the life cycle of the voice call. 311 * 312 * @param allow {@code true} if allowing using data during voice call, {@code false} if 313 * disallowed 314 * 315 * @return {@code true} if operation is successful. otherwise {@code false}. 316 */ setAllowDataDuringVoiceCall(boolean allow)317 public synchronized boolean setAllowDataDuringVoiceCall(boolean allow) { 318 localLog("setAllowDataDuringVoiceCall", allow); 319 if (allow == isDataAllowedInVoiceCall()) { 320 return true; 321 } 322 mDataEnabledOverride.setDataAllowedInVoiceCall(allow); 323 324 boolean changed = SubscriptionController.getInstance() 325 .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); 326 if (changed) { 327 updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); 328 notifyDataEnabledOverrideChanged(); 329 } 330 331 return changed; 332 } 333 334 /** 335 * Check if data is allowed during voice call. 336 * 337 * @return {@code true} if data is allowed during voice call. 338 */ isDataAllowedInVoiceCall()339 public synchronized boolean isDataAllowedInVoiceCall() { 340 return mDataEnabledOverride.isDataAllowedInVoiceCall(); 341 } 342 isMmsAlwaysAllowed()343 public synchronized boolean isMmsAlwaysAllowed() { 344 return mDataEnabledOverride.isMmsAlwaysAllowed(); 345 } 346 setPolicyDataEnabled(boolean enabled)347 private synchronized void setPolicyDataEnabled(boolean enabled) { 348 if (mPolicyDataEnabled != enabled) { 349 localLog("PolicyDataEnabled", enabled); 350 mPolicyDataEnabled = enabled; 351 updateDataEnabledAndNotify(REASON_POLICY_DATA_ENABLED); 352 } 353 } 354 isPolicyDataEnabled()355 public synchronized boolean isPolicyDataEnabled() { 356 return mPolicyDataEnabled; 357 } 358 setCarrierDataEnabled(boolean enabled)359 private synchronized void setCarrierDataEnabled(boolean enabled) { 360 if (mCarrierDataEnabled != enabled) { 361 localLog("CarrierDataEnabled", enabled); 362 mCarrierDataEnabled = enabled; 363 updateDataEnabledAndNotify(REASON_DATA_ENABLED_BY_CARRIER); 364 } 365 } 366 isCarrierDataEnabled()367 public synchronized boolean isCarrierDataEnabled() { 368 return mCarrierDataEnabled; 369 } 370 setThermalDataEnabled(boolean enabled)371 private synchronized void setThermalDataEnabled(boolean enabled) { 372 if (mThermalDataEnabled != enabled) { 373 localLog("ThermalDataEnabled", enabled); 374 mThermalDataEnabled = enabled; 375 updateDataEnabledAndNotify(REASON_THERMAL_DATA_ENABLED); 376 } 377 } 378 isThermalDataEnabled()379 public synchronized boolean isThermalDataEnabled() { 380 return mThermalDataEnabled; 381 } 382 updateProvisionedChanged()383 public synchronized void updateProvisionedChanged() { 384 updateDataEnabledAndNotify(REASON_PROVISIONED_CHANGED); 385 } 386 updateProvisioningDataEnabled()387 public synchronized void updateProvisioningDataEnabled() { 388 updateDataEnabledAndNotify(REASON_PROVISIONING_DATA_ENABLED_CHANGED); 389 } 390 isDataEnabled()391 public synchronized boolean isDataEnabled() { 392 return mIsDataEnabled; 393 } 394 395 /** 396 * Check if data is enabled for a specific reason {@@TelephonyManager.DataEnabledReason} 397 * 398 * @return {@code true} if the overall data is enabled; {@code false} if not. 399 */ isDataEnabledForReason( @elephonyManager.DataEnabledReason int reason)400 public synchronized boolean isDataEnabledForReason( 401 @TelephonyManager.DataEnabledReason int reason) { 402 switch (reason) { 403 case TelephonyManager.DATA_ENABLED_REASON_USER: 404 return isUserDataEnabled(); 405 case TelephonyManager.DATA_ENABLED_REASON_CARRIER: 406 return isCarrierDataEnabled(); 407 case TelephonyManager.DATA_ENABLED_REASON_POLICY: 408 return isPolicyDataEnabled(); 409 case TelephonyManager.DATA_ENABLED_REASON_THERMAL: 410 return isThermalDataEnabled(); 411 default: 412 return false; 413 } 414 } 415 updateDataEnabledAndNotify(int reason)416 private synchronized void updateDataEnabledAndNotify(int reason) { 417 boolean prevDataEnabled = mIsDataEnabled; 418 419 updateDataEnabled(); 420 421 if (prevDataEnabled != mIsDataEnabled) { 422 notifyDataEnabledChanged(!prevDataEnabled, reason); 423 } 424 } 425 updateDataEnabled()426 private synchronized void updateDataEnabled() { 427 if (isProvisioning()) { 428 mIsDataEnabled = isProvisioningDataEnabled(); 429 } else { 430 mIsDataEnabled = mInternalDataEnabled && (isUserDataEnabled() || mDataEnabledOverride 431 .shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_ALL)) 432 && mPolicyDataEnabled && mCarrierDataEnabled && mThermalDataEnabled; 433 } 434 } 435 isProvisioning()436 public boolean isProvisioning() { 437 return Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0; 438 } 439 /** 440 * In provisioning, we might want to have enable mobile data during provisioning. It depends 441 * on value of Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED which is set by 442 * setupwizard. It only matters if it's in provisioning stage. 443 * @return whether we are enabling userData during provisioning stage. 444 */ isProvisioningDataEnabled()445 public boolean isProvisioningDataEnabled() { 446 final String prov_property = SystemProperties.get("ro.com.android.prov_mobiledata", 447 "false"); 448 boolean retVal = "true".equalsIgnoreCase(prov_property); 449 450 final int prov_mobile_data = Settings.Global.getInt(mResolver, 451 Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 452 retVal ? 1 : 0); 453 retVal = prov_mobile_data != 0; 454 log("getDataEnabled during provisioning retVal=" + retVal + " - (" + prov_property 455 + ", " + prov_mobile_data + ")"); 456 457 return retVal; 458 } 459 setDataRoamingEnabled(boolean enabled)460 public synchronized void setDataRoamingEnabled(boolean enabled) { 461 // will trigger handleDataOnRoamingChange() through observer 462 boolean changed = GlobalSettingsHelper.setBoolean(mPhone.getContext(), 463 Settings.Global.DATA_ROAMING, mPhone.getSubId(), enabled); 464 465 if (changed) { 466 localLog("setDataRoamingEnabled", enabled); 467 MultiSimSettingController.getInstance().notifyRoamingDataEnabled(mPhone.getSubId(), 468 enabled); 469 } 470 } 471 472 /** 473 * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. 474 */ getDataRoamingEnabled()475 public synchronized boolean getDataRoamingEnabled() { 476 return GlobalSettingsHelper.getBoolean(mPhone.getContext(), 477 Settings.Global.DATA_ROAMING, mPhone.getSubId(), getDefaultDataRoamingEnabled()); 478 } 479 480 /** 481 * get default values for {@link Settings.Global#DATA_ROAMING} 482 * return {@code true} if either 483 * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} or 484 * system property ro.com.android.dataroaming is set to true. otherwise return {@code false} 485 */ getDefaultDataRoamingEnabled()486 public synchronized boolean getDefaultDataRoamingEnabled() { 487 final CarrierConfigManager configMgr = (CarrierConfigManager) 488 mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 489 boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get( 490 "ro.com.android.dataroaming", "false")); 491 isDataRoamingEnabled |= configMgr.getConfigForSubId(mPhone.getSubId()).getBoolean( 492 CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL); 493 return isDataRoamingEnabled; 494 } 495 notifyDataEnabledChanged(boolean enabled, int reason)496 private void notifyDataEnabledChanged(boolean enabled, int reason) { 497 mOverallDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason)); 498 mPhone.notifyDataEnabled(enabled, reason); 499 } 500 registerForDataEnabledChanged(Handler h, int what, Object obj)501 public void registerForDataEnabledChanged(Handler h, int what, Object obj) { 502 mOverallDataEnabledChangedRegistrants.addUnique(h, what, obj); 503 notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED); 504 } 505 unregisterForDataEnabledChanged(Handler h)506 public void unregisterForDataEnabledChanged(Handler h) { 507 mOverallDataEnabledChangedRegistrants.remove(h); 508 } 509 notifyDataEnabledOverrideChanged()510 private void notifyDataEnabledOverrideChanged() { 511 mOverallDataEnabledOverrideChangedRegistrants.notifyRegistrants(); 512 } 513 514 /** 515 * Register for data enabled override changed event. 516 * 517 * @param h The handler 518 * @param what The event 519 */ registerForDataEnabledOverrideChanged(Handler h, int what)520 public void registerForDataEnabledOverrideChanged(Handler h, int what) { 521 mOverallDataEnabledOverrideChangedRegistrants.addUnique(h, what, null); 522 notifyDataEnabledOverrideChanged(); 523 } 524 525 /** 526 * Unregistered for data enabled override changed event. 527 * 528 * @param h The handler 529 */ unregisterForDataEnabledOverrideChanged(Handler h)530 public void unregisterForDataEnabledOverrideChanged(Handler h) { 531 mOverallDataEnabledOverrideChangedRegistrants.remove(h); 532 } 533 isStandAloneOpportunistic(int subId, Context context)534 private static boolean isStandAloneOpportunistic(int subId, Context context) { 535 SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo( 536 subId, context.getOpPackageName(), context.getAttributionTag()); 537 return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null; 538 } 539 isDataEnabled(int apnType)540 public synchronized boolean isDataEnabled(int apnType) { 541 if (isProvisioning()) { 542 return isProvisioningDataEnabled(); 543 } else { 544 boolean userDataEnabled = isUserDataEnabled(); 545 // Check if we should temporarily enable data in certain conditions. 546 boolean isDataEnabledOverridden = mDataEnabledOverride 547 .shouldOverrideDataEnabledSettings(mPhone, apnType); 548 549 return (mInternalDataEnabled && mPolicyDataEnabled && mCarrierDataEnabled 550 && mThermalDataEnabled && (userDataEnabled || isDataEnabledOverridden)); 551 } 552 } 553 log(String s)554 private void log(String s) { 555 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 556 } 557 localLog(String name, boolean value)558 private void localLog(String name, boolean value) { 559 mSettingChangeLocalLog.log(name + " change to " + value); 560 } 561 dump(FileDescriptor fd, PrintWriter pw, String[] args)562 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 563 pw.println(" DataEnabledSettings="); 564 mSettingChangeLocalLog.dump(fd, pw, args); 565 } 566 } 567