Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 340c7076 authored by Ling Ma's avatar Ling Ma Committed by Jack Yu
Browse files

Move dataEnabled override rule check to phone switcher

Previously, whether an override rule applies to the current condition is
decided by each sub.

The motive for moving the check to phoneSwitcher is that as the future
override rule becomes increasingly dependent on the status of both SIM,
phoneSwitcher, which oversees both SIMs in order to route requests, is
more suitable.

Bug: 244064524
Test: atest + manual toggle dataDuringCall during voice call + toggle
always allow MMS for sending MMS.

Merged-In: I8ea07a1ed879afd52d960241b40e8a4897f899aa
Change-Id: I8ea07a1ed879afd52d960241b40e8a4897f899aa
(cherry picked from commit 4622c39d)
parent dd287d02
Loading
Loading
Loading
Loading
+14 −14
Original line number Diff line number Diff line
@@ -76,7 +76,6 @@ import android.util.Log;
import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.data.DataEnabledOverride;
import com.android.internal.telephony.data.PhoneSwitcher;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccUtils;
@@ -310,7 +309,7 @@ public class SubscriptionController extends ISub.Stub {
            SubscriptionManager.WFC_IMS_ROAMING_ENABLED,
            SubscriptionManager.DATA_ROAMING,
            SubscriptionManager.DISPLAY_NAME,
            SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES,
            SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES,
            SubscriptionManager.UICC_APPLICATIONS_ENABLED,
            SubscriptionManager.IMS_RCS_UCE_ENABLED,
            SubscriptionManager.CROSS_SIM_CALLING_ENABLED,
@@ -2342,7 +2341,7 @@ public class SubscriptionController extends ISub.Stub {
                values.put(propKey, cursor.getInt(columnIndex));
                break;
            case SubscriptionManager.DISPLAY_NAME:
            case SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES:
            case SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES:
                values.put(propKey, cursor.getString(columnIndex));
                break;
            default:
@@ -3373,7 +3372,7 @@ public class SubscriptionController extends ISub.Stub {
                        case SubscriptionManager.CROSS_SIM_CALLING_ENABLED:
                        case SubscriptionManager.IS_OPPORTUNISTIC:
                        case SubscriptionManager.GROUP_UUID:
                        case SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES:
                        case SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES:
                        case SubscriptionManager.ALLOWED_NETWORK_TYPES:
                        case SubscriptionManager.D2D_STATUS_SHARING:
                        case SubscriptionManager.VOIMS_OPT_IN_STATUS:
@@ -4558,19 +4557,19 @@ public class SubscriptionController extends ISub.Stub {
    }

    /**
     * Set allowing mobile data during voice call.
     * Set enabled mobile data policies.
     *
     * @param subId Subscription index
     * @param rules Data enabled override rules in string format. See {@link DataEnabledOverride}
     * for details.
     * @param policies Mobile data policies in string format.
     *                 See {@link TelephonyManager.MobileDataPolicy} for details.
     * @return {@code true} if settings changed, otherwise {@code false}.
     */
    public boolean setDataEnabledOverrideRules(int subId, @NonNull String rules) {
        if (DBG) logd("[setDataEnabledOverrideRules]+ rules:" + rules + " subId:" + subId);
    public boolean setEnabledMobileDataPolicies(int subId, @NonNull String policies) {
        if (DBG) logd("[setEnabledMobileDataPolicies]+ policies:" + policies + " subId:" + subId);

        validateSubId(subId);
        ContentValues value = new ContentValues(1);
        value.put(SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES, rules);
        value.put(SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES, policies);

        boolean result = updateDatabase(value, subId, true) > 0;

@@ -4584,15 +4583,16 @@ public class SubscriptionController extends ISub.Stub {
    }

    /**
     * Get data enabled override rules.
     * Get enabled mobile data policies.
     *
     * @param subId Subscription index
     * @return Data enabled override rules in string
     * @return Enabled mobile data policies joined by "," (ie. "1,2") or an empty string if no
     * policies are enabled.
     */
    @NonNull
    public String getDataEnabledOverrideRules(int subId) {
    public String getEnabledMobileDataPolicies(int subId) {
        return TelephonyUtils.emptyIfNull(getSubscriptionProperty(subId,
                SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES));
                SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES));
    }

    /**
+0 −460
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony.data;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.telephony.Annotation.ApnType;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.data.DataEnabledOverride.OverrideConditions.Condition;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * This class represents the rules for overriding data enabled settings in different conditions.
 * When data is disabled by the user, data can still be turned on temporarily when conditions
 * satisfy any rule here.
 */
public class DataEnabledOverride {

    private final Set<OverrideRule> mRules = new HashSet<>();

    /**
     * The rule for allowing data during voice call.
     */
    private static final OverrideRule OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL =
            new OverrideRule(ApnSetting.TYPE_ALL, OverrideConditions.CONDITION_IN_VOICE_CALL
                    | OverrideConditions.CONDITION_NON_DEFAULT
                    | OverrideConditions.CONDITION_DEFAULT_DATA_ENABLED
                    | OverrideConditions.CONDITION_DSDS_ENABLED);

    /**
     * The rule for always allowing mms. Without adding any condition to the rule, any condition can
     * satisfy this rule for mms.
     */
    private static final OverrideRule OVERRIDE_RULE_ALWAYS_ALLOW_MMS =
            new OverrideRule(ApnSetting.TYPE_MMS, OverrideConditions.CONDITION_UNCONDITIONALLY);

    /**
     * Data enabled override rule
     */
    private static class OverrideRule {
        /**
         * APN type of the rule. The rule is APN type specific. The override is applicable to the
         * specified APN type as well. For now we only support one APN type per rule. Can be
         * expanded to multiple APN types in the future.
         */
        private final @ApnType int mApnType;

        /** The required conditions for overriding */
        private final OverrideConditions mRequiredConditions;

        /**
         * Constructor
         *
         * @param rule The override rule string. For example, {@code mms=nonDefault} or
         * {@code default=voiceCall & nonDefault}
         */
        OverrideRule(@NonNull String rule) {
            String[] tokens = rule.trim().split("\\s*=\\s*");
            if (tokens.length != 2) {
                throw new IllegalArgumentException("Invalid data enabled override rule format: "
                        + rule);
            }

            if (TextUtils.isEmpty(tokens[0])) {
                throw new IllegalArgumentException("APN type can't be empty");
            }

            mApnType = ApnSetting.getApnTypesBitmaskFromString(tokens[0]);
            if (mApnType == ApnSetting.TYPE_NONE) {
                throw new IllegalArgumentException("Invalid APN type. Rule=" + rule);
            }

            mRequiredConditions = new OverrideConditions(tokens[1]);
        }

        /**
         * Constructor
         *
         * @param apnType APN type of the rule
         * @param requiredConditions The required conditions for the rule
         */
        private OverrideRule(int apnType, int requiredConditions) {
            mApnType = apnType;
            mRequiredConditions = new OverrideConditions(requiredConditions);
        }

        /**
         * Check if this rule can be satisfied by the given APN type and provided conditions.
         *
         * @param apnType APN type to check
         * @param providedConditions The provided conditions to check
         * @return {@code true} if satisfied
         */
        boolean isSatisfiedByConditions(@ApnType int apnType, @Condition int providedConditions) {
            return (mApnType == apnType || mApnType == ApnSetting.TYPE_ALL)
                    && mRequiredConditions.allMet(providedConditions);
        }

        @Override
        public String toString() {
            return ApnSetting.getApnTypeString(mApnType) + "=" + mRequiredConditions;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            OverrideRule that = (OverrideRule) o;
            return mApnType == that.mApnType
                    && Objects.equals(mRequiredConditions, that.mRequiredConditions);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mApnType, mRequiredConditions);
        }
    }

    /**
     * Represent the conditions for overriding data enabled settings
     */
    static class OverrideConditions {
        // Possible values for data enabled override condition. Note these flags are bitmasks.
        /** Unconditionally override enabled settings */
        static final int CONDITION_UNCONDITIONALLY = 0;

        /** Enable data only on subscription that is not user selected default data subscription */
        static final int CONDITION_NON_DEFAULT = 1 << 0;

        /** Enable data only when device has ongoing voice call */
        static final int CONDITION_IN_VOICE_CALL = 1 << 1;

        /** Enable data only when default data is on */
        static final int CONDITION_DEFAULT_DATA_ENABLED = 1 << 2;

        /** Enable data only when device is in DSDS mode */
        static final int CONDITION_DSDS_ENABLED = 1 << 3;

        /** Enable data unconditionally in string format */
        static final String CONDITION_UNCONDITIONALLY_STRING = "unconditionally";

        /** Enable data only on subscription that is not default in string format */
        static final String CONDITION_NON_DEFAULT_STRING = "nonDefault";

        /** Enable data only when device has ongoing voice call in string format */
        static final String CONDITION_VOICE_CALL_STRING = "inVoiceCall";

        /** Enable data only when default data is on in string format */
        static final String CONDITION_DEFAULT_DATA_ENABLED_STRING = "DefaultDataOn";

        /** Enable data only when device is in DSDS mode in string format */
        static final String CONDITION_DSDS_ENABLED_STRING = "dsdsEnabled";

        /** @hide */
        @IntDef(flag = true, prefix = { "OVERRIDE_CONDITION_" }, value = {
                CONDITION_NON_DEFAULT,
                CONDITION_IN_VOICE_CALL,
                CONDITION_DEFAULT_DATA_ENABLED,
                CONDITION_DSDS_ENABLED
        })
        @Retention(RetentionPolicy.SOURCE)
        public @interface Condition {}

        private static final Map<Integer, String> OVERRIDE_CONDITION_INT_MAP = new ArrayMap<>();
        private static final Map<String, Integer> OVERRIDE_CONDITION_STRING_MAP = new ArrayMap<>();

        static {
            OVERRIDE_CONDITION_INT_MAP.put(CONDITION_NON_DEFAULT,
                    CONDITION_NON_DEFAULT_STRING);
            OVERRIDE_CONDITION_INT_MAP.put(CONDITION_IN_VOICE_CALL,
                    CONDITION_VOICE_CALL_STRING);
            OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DEFAULT_DATA_ENABLED,
                    CONDITION_DEFAULT_DATA_ENABLED_STRING);
            OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DSDS_ENABLED,
                    CONDITION_DSDS_ENABLED_STRING);

            OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_UNCONDITIONALLY_STRING,
                    CONDITION_UNCONDITIONALLY);
            OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_NON_DEFAULT_STRING,
                    CONDITION_NON_DEFAULT);
            OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_VOICE_CALL_STRING,
                    CONDITION_IN_VOICE_CALL);
            OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DEFAULT_DATA_ENABLED_STRING,
                    CONDITION_DEFAULT_DATA_ENABLED);
            OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DSDS_ENABLED_STRING,
                    CONDITION_DSDS_ENABLED);
        }

        private final @Condition int mConditions;

        /**
         * Conditions for overriding data enabled setting
         *
         * @param conditions Conditions in string format
         */
        OverrideConditions(@NonNull String conditions) {
            mConditions = getBitmaskFromString(conditions);
        }

        /**
         * Conditions for overriding data enabled setting
         *
         * @param conditions Conditions in bitmask
         */
        OverrideConditions(@Condition int conditions) {
            mConditions = conditions;
        }

        private static String getStringFromBitmask(@Condition int conditions) {
            if (conditions == CONDITION_UNCONDITIONALLY) {
                return CONDITION_UNCONDITIONALLY_STRING;
            }
            List<String> conditionsStrings = new ArrayList<>();
            for (Integer condition : OVERRIDE_CONDITION_INT_MAP.keySet()) {
                if ((conditions & condition) == condition) {
                    conditionsStrings.add(OVERRIDE_CONDITION_INT_MAP.get(condition));
                }
            }
            return TextUtils.join("&", conditionsStrings);
        }

        private static @Condition int getBitmaskFromString(@NonNull String str) {
            if (TextUtils.isEmpty(str)) {
                throw new IllegalArgumentException("Empty rule string");
            }

            String[] conditionStrings = str.trim().split("\\s*&\\s*");
            int bitmask = 0;

            for (String conditionStr : conditionStrings) {
                if (!TextUtils.isEmpty(conditionStr)) {
                    if (!OVERRIDE_CONDITION_STRING_MAP.containsKey(conditionStr)) {
                        throw new IllegalArgumentException("Invalid conditions: " + str);
                    }
                    bitmask |= OVERRIDE_CONDITION_STRING_MAP.get(conditionStr);
                }
            }

            return bitmask;
        }

        /**
         * Check if provided conditions can meet all conditions in the rule.
         *
         * @param providedConditions The provided conditions
         * @return {@code true} if all conditions are met.
         */
        boolean allMet(@Condition int providedConditions) {
            return (providedConditions & mConditions) == mConditions;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            OverrideConditions that = (OverrideConditions) o;
            return mConditions == that.mConditions;
        }

        @Override
        public int hashCode() {
            return Objects.hash(mConditions);
        }

        @Override
        public String toString() {
            return getStringFromBitmask(mConditions);
        }
    }

    /**
     * Constructor
     *
     * @param rules Data enabled override rules
     */
    public DataEnabledOverride(@NonNull String rules) {
        updateRules(rules);
    }

    /**
     * Update the data enabled override rules.
     *
     * @param newRules New override rules
     */
    @VisibleForTesting
    public void updateRules(@NonNull String newRules) {
        mRules.clear();
        String[] rulesString = newRules.trim().split("\\s*,\\s*");
        for (String rule : rulesString) {
            if (!TextUtils.isEmpty(rule)) {
                mRules.add(new OverrideRule(rule));
            }
        }
    }

    /**
     * Set always allowing MMS
     *
     * @param allow {@code true} if always allowing, otherwise {@code false}.
     */
    public void setAlwaysAllowMms(boolean allow) {
        if (allow) {
            mRules.add(OVERRIDE_RULE_ALWAYS_ALLOW_MMS);
        } else {
            mRules.remove(OVERRIDE_RULE_ALWAYS_ALLOW_MMS);
        }
    }

    /**
     * Set allowing mobile data during voice call. This is used for allowing data on the non-default
     * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will
     * not be able to use mobile data. By calling this API, data will be temporarily enabled on the
     * non-default data SIM during the life cycle of the voice call.
     *
     * @param allow {@code true} if allowing using data during voice call, {@code false} if
     * disallowed.
     */
    public void setDataAllowedInVoiceCall(boolean allow) {
        if (allow) {
            mRules.add(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL);
        } else {
            mRules.remove(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL);
        }
    }

    /**
     * Check if data is allowed during voice call.
     *
     * @return {@code true} if data is allowed during voice call.
     */
    public boolean isDataAllowedInVoiceCall() {
        return mRules.contains(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL);
    }

    public boolean isMmsAlwaysAllowed() {
        return mRules.contains(OVERRIDE_RULE_ALWAYS_ALLOW_MMS);
    }

    private boolean canSatisfyAnyRule(@ApnType int apnType,
                                      @Condition int providedConditions) {
        for (OverrideRule rule : mRules) {
            if (rule.isSatisfiedByConditions(apnType, providedConditions)) {
                return true;
            }
        }
        return false;
    }

    private @Condition int getCurrentConditions(Phone phone) {
        int conditions = 0;

        if (phone != null) {
            // Check if the device is on voice call
            if (phone.getState() != PhoneConstants.State.IDLE) {
                conditions |= OverrideConditions.CONDITION_IN_VOICE_CALL;
            }

            int defaultDataSubId = SubscriptionController.getInstance().getDefaultDataSubId();

            if (phone.getSubId() != defaultDataSubId) {
                conditions |= OverrideConditions.CONDITION_NON_DEFAULT;
            }

            if (defaultDataSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                int phoneId = SubscriptionController.getInstance().getPhoneId(defaultDataSubId);
                try {
                    Phone defaultDataPhone = PhoneFactory.getPhone(phoneId);
                    if (defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) {
                        conditions |= OverrideConditions.CONDITION_DEFAULT_DATA_ENABLED;
                    }
                } catch (IllegalStateException e) {
                    //ignore the exception and do not add the condition
                    Log.d("DataEnabledOverride", e.getMessage());
                }
            }

            if (TelephonyManager.from(phone.getContext()).isMultiSimEnabled()) {
                conditions |= OverrideConditions.CONDITION_DSDS_ENABLED;
            }
        }

        return conditions;
    }

    /**
     * Check for given APN type if we should enable data.
     *
     * @param phone Phone object
     * @param apnType APN type
     * @return {@code true} if data should be enabled for the current condition.
     */
    public boolean shouldOverrideDataEnabledSettings(Phone phone, @ApnType int apnType) {
        return canSatisfyAnyRule(apnType, getCurrentConditions(phone));
    }

    /**
     * Get data enabled override rules.
     *
     * @return Get data enabled override rules in string format
     */
    @NonNull
    public String getRules() {
        List<String> ruleStrings = new ArrayList<>();
        for (OverrideRule rule : mRules) {
            ruleStrings.add(rule.toString());
        }
        return TextUtils.join(",", ruleStrings);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        DataEnabledOverride that = (DataEnabledOverride) o;
        return mRules.equals(that.mRules);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mRules);
    }

    @Override
    public String toString() {
        return "DataEnabledOverride: [rules=\"" + getRules() + "\"]";
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -1567,7 +1567,8 @@ public class DataNetworkController extends Handler {

            if (!mDataSettingsManager.isDataEnabled()
                    && networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
                    && mDataSettingsManager.isMmsAlwaysAllowed()) {
                    && mDataSettingsManager.isMobileDataPolicyEnabled(TelephonyManager
                    .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED)) {
                // We reach here when data is disabled, but MMS always-allowed is enabled.
                // (Note that isDataEnabled(ApnSetting.TYPE_MMS) returns true in this case, so it
                // would not generate any soft disallowed reason. We need to explicitly handle it.)
+126 −65

File changed.

Preview size limit exceeded, changes collapsed.

+36 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.telephony.Annotation.NetCapability;
import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.ValidationStatus;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.MobileDataPolicy;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
import android.telephony.data.DataCallResponse;
@@ -41,6 +42,7 @@ import android.telephony.ims.feature.ImsFeature;
import android.util.ArrayMap;

import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
import com.android.telephony.Rlog;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -61,6 +63,7 @@ public class DataUtils {
    /** The time format for converting time to readable string. */
    private static final SimpleDateFormat TIME_FORMAT =
            new SimpleDateFormat("HH:mm:ss.SSS", Locale.US);
    private static final String TAG = "DataUtils";

    /**
     * Get the network capability from the string.
@@ -164,6 +167,7 @@ public class DataUtils {
            case NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH:
                return "PRIORITIZE_BANDWIDTH";
            default:
                loge("Unknown network capability(" + netCap + ")");
                return "Unknown(" + netCap + ")";
        }
    }
@@ -209,7 +213,9 @@ public class DataUtils {
        switch (status) {
            case NetworkAgent.VALIDATION_STATUS_VALID: return "VALID";
            case NetworkAgent.VALIDATION_STATUS_NOT_VALID: return "INVALID";
            default: return "UNKNOWN(" + status + ")";
            default:
                loge("Unknown validation status(" + status + ")");
                return "UNKNOWN(" + status + ")";
        }
    }

@@ -366,6 +372,7 @@ public class DataUtils {
            case ImsFeature.FEATURE_MMTEL: return "MMTEL";
            case ImsFeature.FEATURE_RCS: return "RCS";
            default:
                loge("Unknown IMS feature(" + imsFeature + ")");
                return "Unknown(" + imsFeature + ")";
        }
    }
@@ -468,7 +475,9 @@ public class DataUtils {
            case DataCallResponse.LINK_STATUS_INACTIVE: return "INACTIVE";
            case DataCallResponse.LINK_STATUS_ACTIVE: return "ACTIVE";
            case DataCallResponse.LINK_STATUS_DORMANT: return "DORMANT";
            default: return "UNKNOWN(" + linkStatus + ")";
            default:
                loge("Unknown link status(" + linkStatus + ")");
                return "UNKNOWN(" + linkStatus + ")";
        }
    }

@@ -505,7 +514,31 @@ public class DataUtils {
            case TelephonyManager.DATA_ACTIVITY_OUT: return "OUT";
            case TelephonyManager.DATA_ACTIVITY_INOUT: return "INOUT";
            case TelephonyManager.DATA_ACTIVITY_DORMANT: return "DORMANT";
            default: return "UNKNOWN(" + dataActivity + ")";
            default:
                loge("Unknown data activity(" + dataActivity + ")");
                return "UNKNOWN(" + dataActivity + ")";
        }
    }

    /**
     * Convert mobile data policy to string.
     *
     * @param mobileDataPolicy The mobile data policy.
     * @return The mobile data policy in string format.
     */
    public static @NonNull String mobileDataPolicyToString(@MobileDataPolicy int mobileDataPolicy) {
        switch (mobileDataPolicy) {
            case TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL:
                return "DATA_ON_NON_DEFAULT_DURING_VOICE_CALL";
            case TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED:
                return "MMS_ALWAYS_ALLOWED";
            default:
                loge("Unknown mobile data policy(" + mobileDataPolicy + ")");
                return "UNKNOWN(" + mobileDataPolicy + ")";
        }
    }

    private static void loge(String msg) {
        Rlog.e(TAG, msg);
    }
}
Loading