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

Commit 415ef1f1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Added unmetered use only data connection support" into oc-dev

parents 7611bfd8 120d52b8
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -104,14 +104,17 @@ public class DataConnection extends StateMachine {
        ApnContext mApnContext;
        int mProfileId;
        int mRilRat;
        final boolean mUnmeteredUseOnly;
        Message mOnCompletedMsg;
        final int mConnectionGeneration;

        ConnectionParams(ApnContext apnContext, int profileId,
                int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) {
        ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology,
                         boolean unmeteredUseOnly,  Message onCompletedMsg,
                         int connectionGeneration) {
            mApnContext = apnContext;
            mProfileId = profileId;
            mRilRat = rilRadioTechnology;
            mUnmeteredUseOnly = unmeteredUseOnly;
            mOnCompletedMsg = onCompletedMsg;
            mConnectionGeneration = connectionGeneration;
        }
@@ -121,6 +124,7 @@ public class DataConnection extends StateMachine {
            return "{mTag=" + mTag + " mApnContext=" + mApnContext
                    + " mProfileId=" + mProfileId
                    + " mRat=" + mRilRat
                    + " mUnmeteredUseOnly=" + mUnmeteredUseOnly
                    + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
        }
    }
@@ -854,7 +858,7 @@ public class DataConnection extends StateMachine {
        }

        // Is data disabled?
        mRestrictedNetworkOverride = (mDct.isDataEnabled(true) == false);
        mRestrictedNetworkOverride = !mDct.isDataEnabled();
    }

    NetworkCapabilities getNetworkCapabilities() {
@@ -863,6 +867,13 @@ public class DataConnection extends StateMachine {

        if (mApnSetting != null) {
            for (String type : mApnSetting.types) {
                if (!mRestrictedNetworkOverride
                        && mConnectionParams.mUnmeteredUseOnly && ApnSetting.isMeteredApnType(type,
                        mPhone.getContext(), mPhone.getSubId(),
                        mPhone.getServiceState().getDataRoaming())) {
                    log("Dropped the metered " + type + " for the unmetered data call.");
                    continue;
                }
                switch (type) {
                    case PhoneConstants.APN_TYPE_ALL: {
                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
@@ -917,9 +928,11 @@ public class DataConnection extends StateMachine {
                }
            }

            // If none of the APN types associated with this APN setting is metered,
            // then we apply NOT_METERED capability to the network.
            if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
            // Mark NOT_METERED in the following cases,
            // 1. All APNs in APN settings are unmetered.
            // 2. The non-restricted data and is intended for unmetered use only.
            if ((mConnectionParams.mUnmeteredUseOnly && !mRestrictedNetworkOverride)
                    || !mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
                    mPhone.getServiceState().getDataRoaming())) {
                result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
                mNetworkInfo.setMetered(false);
+12 −14
Original line number Diff line number Diff line
@@ -64,9 +64,9 @@ public class DataEnabledSettings {
    private final RegistrantList mDataEnabledChangedRegistrants = new RegistrantList();

    public synchronized void setInternalDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mInternalDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_INTERNAL_DATA_ENABLED);
        }
    }
@@ -75,9 +75,9 @@ public class DataEnabledSettings {
    }

    public synchronized void setUserDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mUserDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_USER_DATA_ENABLED);
        }
    }
@@ -86,9 +86,9 @@ public class DataEnabledSettings {
    }

    public synchronized void setPolicyDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mPolicyDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_POLICY_DATA_ENABLED);
        }
    }
@@ -97,9 +97,9 @@ public class DataEnabledSettings {
    }

    public synchronized void setCarrierDataEnabled(boolean enabled) {
        boolean prevDataEnabled = isDataEnabled(true);
        boolean prevDataEnabled = isDataEnabled();
        mCarrierDataEnabled = enabled;
        if (prevDataEnabled != isDataEnabled(true)) {
        if (prevDataEnabled != isDataEnabled()) {
            notifyDataEnabledChanged(!prevDataEnabled, REASON_DATA_ENABLED_BY_CARRIER);
        }
    }
@@ -107,11 +107,9 @@ public class DataEnabledSettings {
        return mCarrierDataEnabled;
    }

    public synchronized boolean isDataEnabled(boolean checkUserDataEnabled) {
        return (mInternalDataEnabled
                && (!checkUserDataEnabled || mUserDataEnabled)
                && (!checkUserDataEnabled || mPolicyDataEnabled)
                && (!checkUserDataEnabled || mCarrierDataEnabled));
    public synchronized boolean isDataEnabled() {
        return (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
                && mCarrierDataEnabled);
    }

    private void notifyDataEnabledChanged(boolean enabled, int reason) {
@@ -120,7 +118,7 @@ public class DataEnabledSettings {

    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
        mDataEnabledChangedRegistrants.addUnique(h, what, obj);
        notifyDataEnabledChanged(isDataEnabled(true), REASON_REGISTERED);
        notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED);
    }

    public void unregisterForDataEnabledChanged(Handler h) {
+15 −9
Original line number Diff line number Diff line
@@ -319,7 +319,7 @@ public class DcAsyncChannel extends AsyncChannel {
     * Evaluate RSP_GET_NETWORK_CAPABILITIES
     *
     * @param response
     * @return NetworkCapabilites, maybe null.
     * @return NetworkCapabilities, maybe null.
     */
    public NetworkCapabilities rspNetworkCapabilities(Message response) {
        NetworkCapabilities retVal = (NetworkCapabilities) response.obj;
@@ -357,23 +357,29 @@ public class DcAsyncChannel extends AsyncChannel {

    /**
     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
     * Used for cellular networks that use Acesss Point Names (APN) such
     * Used for cellular networks that use Access Point Names (APN) such
     * as GSM networks.
     *
     * @param apnContext is the Access Point Name to bring up a connection to
     * @param profileId for the conneciton
     * @param profileId for the connection
     * @param rilRadioTechnology Radio technology for the data connection
     * @param unmeteredUseOnly Indicates the data connection can only used for unmetered purposes
     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
     *                       With AsyncResult.userObj set to the original msg.obj,
     *                       AsyncResult.result = FailCause and AsyncResult.exception = Exception().
     * @param connectionGeneration used to track a single connection request so disconnects can get
     *                             ignored if obsolete.
     */
    public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology,
                        Message onCompletedMsg, int connectionGeneration) {
                        boolean unmeteredUseOnly, Message onCompletedMsg,
                        int connectionGeneration) {
        if (DBG) {
            log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg);
            log("bringUp: apnContext=" + apnContext + "unmeteredUseOnly=" + unmeteredUseOnly
                    + " onCompletedMsg=" + onCompletedMsg);
        }
        sendMessage(DataConnection.EVENT_CONNECT,
                new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg,
                        connectionGeneration));
                new ConnectionParams(apnContext, profileId, rilRadioTechnology, unmeteredUseOnly,
                        onCompletedMsg, connectionGeneration));
    }

    /**
+101 −61
Original line number Diff line number Diff line
@@ -920,7 +920,7 @@ public class DcTracker extends Handler {
                // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
                // handle the rest from there.
                if (enabled) {
                    teardownRestrictedMeteredConnections();
                    reevaluateDataConnections();
                    onTrySetupData(Phone.REASON_DATA_ENABLED);
                } else {
                    onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
@@ -930,42 +930,58 @@ public class DcTracker extends Handler {
    }

    /**
     * Handle reverting restricted networks back to unrestricted.
     * If we're changing user data to enabled and this makes data
     * truely enabled (not disabled by other factors) we need to
     * tear down any metered apn type that was enabled anyway by
     * a privileged request.  This allows us to reconnect
     * to it in an unrestricted way.
     * Reevaluate existing data connections when conditions change.
     *
     * For example, handle reverting restricted networks back to unrestricted. If we're changing
     * user data to enabled and this makes data truly enabled (not disabled by other factors) we
     * need to tear down any metered apn type that was enabled anyway by a privileged request.
     * This allows us to reconnect to it in an unrestricted way.
     *
     * Or when we brought up a unmetered data connection while data is off, we only limit this
     * data connection for unmetered use only. When data is turned back on, we need to tear that
     * down so a full capable data connection can be re-established.
     */
    private void teardownRestrictedMeteredConnections() {
        if (mDataEnabledSettings.isDataEnabled(true)) {
    private void reevaluateDataConnections() {
        if (mDataEnabledSettings.isDataEnabled()) {
            for (ApnContext apnContext : mApnContexts.values()) {
                if (apnContext.isConnectedOrConnecting() &&
                        apnContext.getApnSetting().isMetered(mPhone.getContext(),
                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {

                    final DcAsyncChannel dataConnectionAc = apnContext.getDcAc();
                    if (dataConnectionAc != null) {
                        final NetworkCapabilities nc =
                                dataConnectionAc.getNetworkCapabilitiesSync();
                        if (nc != null && nc.hasCapability(NetworkCapabilities.
                              NET_CAPABILITY_NOT_RESTRICTED)) {
                            if (DBG) log("not tearing down unrestricted metered net:" + apnContext);
                            continue;
                if (apnContext.isConnectedOrConnecting()) {
                    final DcAsyncChannel dcac = apnContext.getDcAc();
                    if (dcac != null) {
                        final NetworkCapabilities netCaps = dcac.getNetworkCapabilitiesSync();
                        if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities
                                .NET_CAPABILITY_NOT_RESTRICTED)) {
                            if (DBG) {
                                log("Tearing down restricted net:" + apnContext);
                            }
                            // Tearing down the restricted data call (metered or unmetered) when
                            // conditions change. This will allow reestablishing a new unrestricted
                            // data connection.
                            apnContext.setReason(Phone.REASON_DATA_ENABLED);
                            cleanUpConnection(true, apnContext);
                        } else if (apnContext.getApnSetting().isMetered(mPhone.getContext(),
                                mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())
                                && (netCaps != null && netCaps.hasCapability(
                                        NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) {
                            if (DBG) {
                                log("Tearing down unmetered net:" + apnContext);
                            }
                    if (DBG) log("tearing down restricted metered net: " + apnContext);
                            // The APN settings is metered, but the data was still marked as
                            // unmetered data, must be the unmetered data connection brought up when
                            // data is off. We need to tear that down when data is enabled again.
                            // This will allow reestablishing a new full capability data connection.
                            apnContext.setReason(Phone.REASON_DATA_ENABLED);
                            cleanUpConnection(true, apnContext);
                        }
                    }
                }
            }
        }
    }

    private void onDeviceProvisionedChange() {
        if (getDataEnabled()) {
            mDataEnabledSettings.setUserDataEnabled(true);
            teardownRestrictedMeteredConnections();
            reevaluateDataConnections();
            onTrySetupData(Phone.REASON_DATA_ENABLED);
        } else {
            mDataEnabledSettings.setUserDataEnabled(false);
@@ -1306,7 +1322,7 @@ public class DcTracker extends Handler {
     * {@code true} otherwise.
     */
    public boolean getAnyDataEnabled() {
        if (!mDataEnabledSettings.isDataEnabled(true)) return false;
        if (!mDataEnabledSettings.isDataEnabled()) return false;
        DataAllowFailReason failureReason = new DataAllowFailReason();
        if (!isDataAllowed(failureReason)) {
            if (DBG) log(failureReason.getDataAllowFailReason());
@@ -1323,8 +1339,8 @@ public class DcTracker extends Handler {
    }

    @VisibleForTesting
    public boolean isDataEnabled(boolean checkUserDataEnabled) {
        return mDataEnabledSettings.isDataEnabled(checkUserDataEnabled);
    public boolean isDataEnabled() {
        return mDataEnabledSettings.isDataEnabled();
    }

    private boolean isDataAllowedForApn(ApnContext apnContext) {
@@ -1556,29 +1572,53 @@ public class DcTracker extends Handler {
        boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
        final ServiceStateTracker sst = mPhone.getServiceStateTracker();

        // set to false if apn type is non-metered or if we have a restricted (privileged)
        // request for the network.
        // TODO - may want restricted requests to only apply to carrier-limited data access
        //        rather than applying to user limited as well.
        // Exclude DUN for the purposes of the override until we get finer grained
        // intention in NetworkRequests
        boolean checkUserDataEnabled =
                ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) &&
                apnContext.hasNoRestrictedRequests(true /*exclude DUN */);

        DataAllowFailReason failureReason = new DataAllowFailReason();

        // allow data if currently in roaming service, roaming setting disabled
        // and requested apn type is non-metered for roaming.
        boolean isDataAllowed = isDataAllowed(failureReason) ||
                (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED) &&
                !(ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
                mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())));

        if (apnContext.isConnectable() && (isEmergencyApn ||
                (isDataAllowed && isDataAllowedForApn(apnContext) &&
                        mDataEnabledSettings.isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
        boolean unmeteredUseOnly = false;
        boolean isDataAllowed = isDataAllowed(failureReason);
        boolean isMeteredApnType = ApnSetting.isMeteredApnType(apnContext.getApnType(),
                mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming());
        if (!isDataAllowed) {
            // If the data not allowed due to roaming disabled, but the request APN type is not
            // metered, we should allow data (because the user won't be charged anyway)
            if (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED)
                    && !isMeteredApnType) {
                isDataAllowed = true;
                unmeteredUseOnly = true;
            }
        }

        if (isDataAllowed) {
            if (!mDataEnabledSettings.isDataEnabled()) {
                // If the data is turned off, we should not allow a data connection.
                isDataAllowed = false;

                // But there are some exceptions we should allow data even when data is turned off.
                if (!apnContext.hasNoRestrictedRequests(true /*exclude DUN */)) {
                    // A restricted request can request data even when data is turned off.
                    // Note this takes precedence over unmetered request.
                    isDataAllowed = true;
                    unmeteredUseOnly = false;
                } else if (!isMeteredApnType) {
                    // If the APN is unmetered, we should allow data even if data is turned off.
                    // This will allow users to make VoLTE calls or send MMS while data is
                    // turned off.
                    isDataAllowed = true;

                    // When data is off, if we allow a data call because it's unmetered, we
                    // should restrict it for unmetered use only. For example, if one
                    // carrier has both internet (metered) and MMS (unmetered) APNs mixed in one
                    // APN setting, when we bring up a data call for MMS purpose, we should
                    // restrict it for unmetered use only. We should not allow it for other
                    // metered purposes such as internet.
                    unmeteredUseOnly = true;
                }
            }
        }

        if (apnContext.isConnectable()
                && (isEmergencyApn
                || (isDataAllowed && isDataAllowedForApn(apnContext) && !isEmergency()))) {
            if (apnContext.getState() == DctConstants.State.FAILED) {
                String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
                if (DBG) log(str);
@@ -1607,7 +1647,7 @@ public class DcTracker extends Handler {
                }
            }

            boolean retValue = setupData(apnContext, radioTech);
            boolean retValue = setupData(apnContext, radioTech, unmeteredUseOnly);
            notifyOffApnsOfAvailability(apnContext.getReason());

            if (DBG) log("trySetupData: X retValue=" + retValue);
@@ -1636,13 +1676,13 @@ public class DcTracker extends Handler {
                str.append("isDataAllowedForApn = false. RAT = " +
                        mPhone.getServiceState().getRilDataRadioTechnology());
            }
            if (!mDataEnabledSettings.isDataEnabled(checkUserDataEnabled)) {
                str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
                        "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled() +
                        ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled() +
                        ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled() +
                        ", isCarrierDataEnabled = " +
                        mDataEnabledSettings.isCarrierDataEnabled());
            if (!mDataEnabledSettings.isDataEnabled()) {
                str.append("isDataEnabled() = false. "
                        + "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled()
                        + ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled()
                        + ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled()
                        + ", isCarrierDataEnabled = "
                        + mDataEnabledSettings.isCarrierDataEnabled());
            }
            if (isEmergency()) {
                str.append("emergency = true");
@@ -2068,7 +2108,7 @@ public class DcTracker extends Handler {
        return null;
    }

    private boolean setupData(ApnContext apnContext, int radioTech) {
    private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) {
        if (DBG) log("setupData: apnContext=" + apnContext);
        apnContext.requestLog("setupData");
        ApnSetting apnSetting;
@@ -2150,7 +2190,7 @@ public class DcTracker extends Handler {
        Message msg = obtainMessage();
        msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
        msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
        dcac.bringUp(apnContext, profileId, radioTech, msg, generation);
        dcac.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation);

        if (DBG) log("setupData: initing!");
        return true;
@@ -2433,11 +2473,11 @@ public class DcTracker extends Handler {
                    // Tear down all metered apns
                    cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
                } else {
                    // Re-evauluate Otasp state
                    // Re-evaluate Otasp state
                    int otaspState = mPhone.getServiceStateTracker().getOtasp();
                    mPhone.notifyOtaspChanged(otaspState);

                    teardownRestrictedMeteredConnections();
                    reevaluateDataConnections();
                    setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
                }
            }
@@ -2488,7 +2528,7 @@ public class DcTracker extends Handler {
                // handle the rest from there.
                if (prevEnabled != getAnyDataEnabled()) {
                    if (!prevEnabled) {
                        teardownRestrictedMeteredConnections();
                        reevaluateDataConnections();
                        onTrySetupData(Phone.REASON_DATA_ENABLED);
                    } else {
                        onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);