1 /* 2 * Copyright 2019 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 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.telephony.Annotation.ApnType; 22 import android.telephony.SubscriptionManager; 23 import android.telephony.TelephonyManager; 24 import android.telephony.data.ApnSetting; 25 import android.text.TextUtils; 26 import android.util.ArrayMap; 27 import android.util.Log; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.telephony.Phone; 31 import com.android.internal.telephony.PhoneConstants; 32 import com.android.internal.telephony.PhoneFactory; 33 import com.android.internal.telephony.SubscriptionController; 34 import com.android.internal.telephony.dataconnection.DataEnabledOverride.OverrideConditions.Condition; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.util.ArrayList; 39 import java.util.HashSet; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.Objects; 43 import java.util.Set; 44 45 /** 46 * This class represents the rules for overriding data enabled settings in different conditions. 47 * When data is disabled by the user, data can still be turned on temporarily when conditions 48 * satisfy any rule here. 49 */ 50 public class DataEnabledOverride { 51 52 private final Set<OverrideRule> mRules = new HashSet<>(); 53 54 /** 55 * The rule for allowing data during voice call. 56 */ 57 private static final OverrideRule OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL = 58 new OverrideRule(ApnSetting.TYPE_ALL, OverrideConditions.CONDITION_IN_VOICE_CALL 59 | OverrideConditions.CONDITION_NON_DEFAULT 60 | OverrideConditions.CONDITION_DEFAULT_DATA_ENABLED 61 | OverrideConditions.CONDITION_DSDS_ENABLED); 62 63 /** 64 * The rule for always allowing mms. Without adding any condition to the rule, any condition can 65 * satisfy this rule for mms. 66 */ 67 private static final OverrideRule OVERRIDE_RULE_ALWAYS_ALLOW_MMS = 68 new OverrideRule(ApnSetting.TYPE_MMS, OverrideConditions.CONDITION_UNCONDITIONALLY); 69 70 /** 71 * Data enabled override rule 72 */ 73 private static class OverrideRule { 74 /** 75 * APN type of the rule. The rule is APN type specific. The override is applicable to the 76 * specified APN type as well. For now we only support one APN type per rule. Can be 77 * expanded to multiple APN types in the future. 78 */ 79 private final @ApnType int mApnType; 80 81 /** The required conditions for overriding */ 82 private final OverrideConditions mRequiredConditions; 83 84 /** 85 * Constructor 86 * 87 * @param rule The override rule string. For example, {@code mms=nonDefault} or 88 * {@code default=voiceCall & nonDefault} 89 */ OverrideRule(@onNull String rule)90 OverrideRule(@NonNull String rule) { 91 String[] tokens = rule.trim().split("\\s*=\\s*"); 92 if (tokens.length != 2) { 93 throw new IllegalArgumentException("Invalid data enabled override rule format: " 94 + rule); 95 } 96 97 if (TextUtils.isEmpty(tokens[0])) { 98 throw new IllegalArgumentException("APN type can't be empty"); 99 } 100 101 mApnType = ApnSetting.getApnTypesBitmaskFromString(tokens[0]); 102 if (mApnType == ApnSetting.TYPE_NONE) { 103 throw new IllegalArgumentException("Invalid APN type. Rule=" + rule); 104 } 105 106 mRequiredConditions = new OverrideConditions(tokens[1]); 107 } 108 109 /** 110 * Constructor 111 * 112 * @param apnType APN type of the rule 113 * @param requiredConditions The required conditions for the rule 114 */ OverrideRule(int apnType, int requiredConditions)115 private OverrideRule(int apnType, int requiredConditions) { 116 mApnType = apnType; 117 mRequiredConditions = new OverrideConditions(requiredConditions); 118 } 119 120 /** 121 * Check if this rule can be satisfied by the given APN type and provided conditions. 122 * 123 * @param apnType APN type to check 124 * @param providedConditions The provided conditions to check 125 * @return {@code true} if satisfied 126 */ isSatisfiedByConditions(@pnType int apnType, @Condition int providedConditions)127 boolean isSatisfiedByConditions(@ApnType int apnType, @Condition int providedConditions) { 128 return (mApnType == apnType || mApnType == ApnSetting.TYPE_ALL) 129 && mRequiredConditions.allMet(providedConditions); 130 } 131 132 @Override toString()133 public String toString() { 134 return ApnSetting.getApnTypeString(mApnType) + "=" + mRequiredConditions; 135 } 136 137 @Override equals(Object o)138 public boolean equals(Object o) { 139 if (this == o) return true; 140 if (o == null || getClass() != o.getClass()) return false; 141 OverrideRule that = (OverrideRule) o; 142 return mApnType == that.mApnType 143 && Objects.equals(mRequiredConditions, that.mRequiredConditions); 144 } 145 146 @Override hashCode()147 public int hashCode() { 148 return Objects.hash(mApnType, mRequiredConditions); 149 } 150 } 151 152 /** 153 * Represent the conditions for overriding data enabled settings 154 */ 155 static class OverrideConditions { 156 // Possible values for data enabled override condition. Note these flags are bitmasks. 157 /** Unconditionally override enabled settings */ 158 static final int CONDITION_UNCONDITIONALLY = 0; 159 160 /** Enable data only on subscription that is not user selected default data subscription */ 161 static final int CONDITION_NON_DEFAULT = 1 << 0; 162 163 /** Enable data only when device has ongoing voice call */ 164 static final int CONDITION_IN_VOICE_CALL = 1 << 1; 165 166 /** Enable data only when default data is on */ 167 static final int CONDITION_DEFAULT_DATA_ENABLED = 1 << 2; 168 169 /** Enable data only when device is in DSDS mode */ 170 static final int CONDITION_DSDS_ENABLED = 1 << 3; 171 172 /** Enable data unconditionally in string format */ 173 static final String CONDITION_UNCONDITIONALLY_STRING = "unconditionally"; 174 175 /** Enable data only on subscription that is not default in string format */ 176 static final String CONDITION_NON_DEFAULT_STRING = "nonDefault"; 177 178 /** Enable data only when device has ongoing voice call in string format */ 179 static final String CONDITION_VOICE_CALL_STRING = "inVoiceCall"; 180 181 /** Enable data only when default data is on in string format */ 182 static final String CONDITION_DEFAULT_DATA_ENABLED_STRING = "DefaultDataOn"; 183 184 /** Enable data only when device is in DSDS mode in string format */ 185 static final String CONDITION_DSDS_ENABLED_STRING = "dsdsEnabled"; 186 187 /** @hide */ 188 @IntDef(flag = true, prefix = { "OVERRIDE_CONDITION_" }, value = { 189 CONDITION_NON_DEFAULT, 190 CONDITION_IN_VOICE_CALL, 191 CONDITION_DEFAULT_DATA_ENABLED, 192 CONDITION_DSDS_ENABLED 193 }) 194 @Retention(RetentionPolicy.SOURCE) 195 public @interface Condition {} 196 197 private static final Map<Integer, String> OVERRIDE_CONDITION_INT_MAP = new ArrayMap<>(); 198 private static final Map<String, Integer> OVERRIDE_CONDITION_STRING_MAP = new ArrayMap<>(); 199 200 static { OVERRIDE_CONDITION_INT_MAP.put(CONDITION_NON_DEFAULT, CONDITION_NON_DEFAULT_STRING)201 OVERRIDE_CONDITION_INT_MAP.put(CONDITION_NON_DEFAULT, 202 CONDITION_NON_DEFAULT_STRING); OVERRIDE_CONDITION_INT_MAP.put(CONDITION_IN_VOICE_CALL, CONDITION_VOICE_CALL_STRING)203 OVERRIDE_CONDITION_INT_MAP.put(CONDITION_IN_VOICE_CALL, 204 CONDITION_VOICE_CALL_STRING); OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DEFAULT_DATA_ENABLED, CONDITION_DEFAULT_DATA_ENABLED_STRING)205 OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DEFAULT_DATA_ENABLED, 206 CONDITION_DEFAULT_DATA_ENABLED_STRING); OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DSDS_ENABLED, CONDITION_DSDS_ENABLED_STRING)207 OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DSDS_ENABLED, 208 CONDITION_DSDS_ENABLED_STRING); 209 OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_UNCONDITIONALLY_STRING, CONDITION_UNCONDITIONALLY)210 OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_UNCONDITIONALLY_STRING, 211 CONDITION_UNCONDITIONALLY); OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_NON_DEFAULT_STRING, CONDITION_NON_DEFAULT)212 OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_NON_DEFAULT_STRING, 213 CONDITION_NON_DEFAULT); OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_VOICE_CALL_STRING, CONDITION_IN_VOICE_CALL)214 OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_VOICE_CALL_STRING, 215 CONDITION_IN_VOICE_CALL); OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DEFAULT_DATA_ENABLED_STRING, CONDITION_DEFAULT_DATA_ENABLED)216 OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DEFAULT_DATA_ENABLED_STRING, 217 CONDITION_DEFAULT_DATA_ENABLED); OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DSDS_ENABLED_STRING, CONDITION_DSDS_ENABLED)218 OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DSDS_ENABLED_STRING, 219 CONDITION_DSDS_ENABLED); 220 } 221 222 private final @Condition int mConditions; 223 224 /** 225 * Conditions for overriding data enabled setting 226 * 227 * @param conditions Conditions in string format 228 */ OverrideConditions(@onNull String conditions)229 OverrideConditions(@NonNull String conditions) { 230 mConditions = getBitmaskFromString(conditions); 231 } 232 233 /** 234 * Conditions for overriding data enabled setting 235 * 236 * @param conditions Conditions in bitmask 237 */ OverrideConditions(@ondition int conditions)238 OverrideConditions(@Condition int conditions) { 239 mConditions = conditions; 240 } 241 getStringFromBitmask(@ondition int conditions)242 private static String getStringFromBitmask(@Condition int conditions) { 243 if (conditions == CONDITION_UNCONDITIONALLY) { 244 return CONDITION_UNCONDITIONALLY_STRING; 245 } 246 List<String> conditionsStrings = new ArrayList<>(); 247 for (Integer condition : OVERRIDE_CONDITION_INT_MAP.keySet()) { 248 if ((conditions & condition) == condition) { 249 conditionsStrings.add(OVERRIDE_CONDITION_INT_MAP.get(condition)); 250 } 251 } 252 return TextUtils.join("&", conditionsStrings); 253 } 254 getBitmaskFromString(@onNull String str)255 private static @Condition int getBitmaskFromString(@NonNull String str) { 256 if (TextUtils.isEmpty(str)) { 257 throw new IllegalArgumentException("Empty rule string"); 258 } 259 260 String[] conditionStrings = str.trim().split("\\s*&\\s*"); 261 int bitmask = 0; 262 263 for (String conditionStr : conditionStrings) { 264 if (!TextUtils.isEmpty(conditionStr)) { 265 if (!OVERRIDE_CONDITION_STRING_MAP.containsKey(conditionStr)) { 266 throw new IllegalArgumentException("Invalid conditions: " + str); 267 } 268 bitmask |= OVERRIDE_CONDITION_STRING_MAP.get(conditionStr); 269 } 270 } 271 272 return bitmask; 273 } 274 275 /** 276 * Check if provided conditions can meet all conditions in the rule. 277 * 278 * @param providedConditions The provided conditions 279 * @return {@code true} if all conditions are met. 280 */ allMet(@ondition int providedConditions)281 boolean allMet(@Condition int providedConditions) { 282 return (providedConditions & mConditions) == mConditions; 283 } 284 285 @Override equals(Object o)286 public boolean equals(Object o) { 287 if (this == o) return true; 288 if (o == null || getClass() != o.getClass()) return false; 289 OverrideConditions that = (OverrideConditions) o; 290 return mConditions == that.mConditions; 291 } 292 293 @Override hashCode()294 public int hashCode() { 295 return Objects.hash(mConditions); 296 } 297 298 @Override toString()299 public String toString() { 300 return getStringFromBitmask(mConditions); 301 } 302 } 303 304 /** 305 * Constructor 306 * 307 * @param rules Data enabled override rules 308 */ DataEnabledOverride(@onNull String rules)309 public DataEnabledOverride(@NonNull String rules) { 310 updateRules(rules); 311 } 312 313 /** 314 * Update the data enabled override rules. 315 * 316 * @param newRules New override rules 317 */ 318 @VisibleForTesting updateRules(@onNull String newRules)319 public void updateRules(@NonNull String newRules) { 320 mRules.clear(); 321 String[] rulesString = newRules.trim().split("\\s*,\\s*"); 322 for (String rule : rulesString) { 323 if (!TextUtils.isEmpty(rule)) { 324 mRules.add(new OverrideRule(rule)); 325 } 326 } 327 } 328 329 /** 330 * Set always allowing MMS 331 * 332 * @param allow {@code true} if always allowing, otherwise {@code false}. 333 */ setAlwaysAllowMms(boolean allow)334 public void setAlwaysAllowMms(boolean allow) { 335 if (allow) { 336 mRules.add(OVERRIDE_RULE_ALWAYS_ALLOW_MMS); 337 } else { 338 mRules.remove(OVERRIDE_RULE_ALWAYS_ALLOW_MMS); 339 } 340 } 341 342 /** 343 * Set allowing mobile data during voice call. This is used for allowing data on the non-default 344 * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will 345 * not be able to use mobile data. By calling this API, data will be temporarily enabled on the 346 * non-default data SIM during the life cycle of the voice call. 347 * 348 * @param allow {@code true} if allowing using data during voice call, {@code false} if 349 * disallowed. 350 */ setDataAllowedInVoiceCall(boolean allow)351 public void setDataAllowedInVoiceCall(boolean allow) { 352 if (allow) { 353 mRules.add(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL); 354 } else { 355 mRules.remove(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL); 356 } 357 } 358 359 /** 360 * Check if data is allowed during voice call. 361 * 362 * @return {@code true} if data is allowed during voice call. 363 */ isDataAllowedInVoiceCall()364 public boolean isDataAllowedInVoiceCall() { 365 return mRules.contains(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL); 366 } 367 canSatisfyAnyRule(@pnType int apnType, @Condition int providedConditions)368 private boolean canSatisfyAnyRule(@ApnType int apnType, 369 @Condition int providedConditions) { 370 for (OverrideRule rule : mRules) { 371 if (rule.isSatisfiedByConditions(apnType, providedConditions)) { 372 return true; 373 } 374 } 375 return false; 376 } 377 getCurrentConditions(Phone phone)378 private @Condition int getCurrentConditions(Phone phone) { 379 int conditions = 0; 380 381 if (phone != null) { 382 // Check if the device is on voice call 383 if (phone.getState() != PhoneConstants.State.IDLE) { 384 conditions |= OverrideConditions.CONDITION_IN_VOICE_CALL; 385 } 386 387 int defaultDataSubId = SubscriptionController.getInstance().getDefaultDataSubId(); 388 389 if (phone.getSubId() != defaultDataSubId) { 390 conditions |= OverrideConditions.CONDITION_NON_DEFAULT; 391 } 392 393 if (defaultDataSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 394 int phoneId = SubscriptionController.getInstance().getPhoneId(defaultDataSubId); 395 try { 396 Phone defaultDataPhone = PhoneFactory.getPhone(phoneId); 397 if (defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) { 398 conditions |= OverrideConditions.CONDITION_DEFAULT_DATA_ENABLED; 399 } 400 } catch (IllegalStateException e) { 401 //ignore the exception and do not add the condition 402 Log.d("DataEnabledOverride", e.getMessage()); 403 } 404 } 405 406 if (TelephonyManager.from(phone.getContext()).isMultiSimEnabled()) { 407 conditions |= OverrideConditions.CONDITION_DSDS_ENABLED; 408 } 409 } 410 411 return conditions; 412 } 413 414 /** 415 * Check for given APN type if we should enable data. 416 * 417 * @param phone Phone object 418 * @param apnType APN type 419 * @return {@code true} if data should be enabled for the current condition. 420 */ shouldOverrideDataEnabledSettings(Phone phone, @ApnType int apnType)421 public boolean shouldOverrideDataEnabledSettings(Phone phone, @ApnType int apnType) { 422 return canSatisfyAnyRule(apnType, getCurrentConditions(phone)); 423 } 424 425 /** 426 * Get data enabled override rules. 427 * 428 * @return Get data enabled override rules in string format 429 */ 430 @NonNull getRules()431 public String getRules() { 432 List<String> ruleStrings = new ArrayList<>(); 433 for (OverrideRule rule : mRules) { 434 ruleStrings.add(rule.toString()); 435 } 436 return TextUtils.join(",", ruleStrings); 437 } 438 439 @Override equals(Object o)440 public boolean equals(Object o) { 441 if (this == o) return true; 442 if (o == null || getClass() != o.getClass()) return false; 443 DataEnabledOverride that = (DataEnabledOverride) o; 444 return mRules.equals(that.mRules); 445 } 446 447 @Override hashCode()448 public int hashCode() { 449 return Objects.hash(mRules); 450 } 451 452 @Override toString()453 public String toString() { 454 return "DataEnabledOverride: [rules=\"" + getRules() + "\"]"; 455 } 456 } 457