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

Commit 0a5570d4 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Jeff Sharkey
Browse files

APIs to disable data usage notifications.

Certain carriers have requested the ability to disable the warning,
limit, and rapid data usage notifications shown by the OS, so give
them that ability on a per-subId basis.  (The notifications are still
enabled by default.)

Unhide NOT_CONGESTED to match setSubscriptionOverrideCongested().

Fix bug in getPrimarySubscriptionPlanLocked() to find the first
currently active plan; the first non-recurring plan may be no longer
active.  Fix bug in SubscriptionPlan which allowed invalid negative
or zero-length Period objects.

Bug: 77851691, 77506882, 77662747
Test: atest com.android.server.NetworkPolicyManagerServiceTest
Test: atest android.telephony.cts.SubscriptionManagerTest
Exempt-From-Owner-Approval: SDK deadline, responding to API feedback
Change-Id: Ib6e6dbadd5022937c3f0661ab4b66aa617f0b5af
parent 42c68686
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -27202,6 +27202,7 @@ package android.net {
    field public static final int NET_CAPABILITY_IMS = 4; // 0x4
    field public static final int NET_CAPABILITY_IMS = 4; // 0x4
    field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
    field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
    field public static final int NET_CAPABILITY_MMS = 0; // 0x0
    field public static final int NET_CAPABILITY_MMS = 0; // 0x0
    field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
    field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
    field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
    field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
    field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
    field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
    field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
@@ -41682,7 +41683,10 @@ package android.telephony {
    field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
    field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
    field public static final java.lang.String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
    field public static final java.lang.String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
    field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
    field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
    field public static final java.lang.String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool";
    field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
    field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
    field public static final java.lang.String KEY_DATA_RAPID_NOTIFICATION_BOOL = "data_rapid_notification_bool";
    field public static final java.lang.String KEY_DATA_WARNING_NOTIFICATION_BOOL = "data_warning_notification_bool";
    field public static final java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
    field public static final java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
    field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
    field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
    field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
    field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
+2 −3
Original line number Original line Diff line number Diff line
@@ -254,9 +254,8 @@ public final class NetworkCapabilities implements Parcelable {
    /**
    /**
     * Indicates that this network is not congested.
     * Indicates that this network is not congested.
     * <p>
     * <p>
     * When a network is congested, the device should defer network traffic that
     * When a network is congested, applications should defer network traffic
     * can be done at a later time without breaking developer contracts.
     * that can be done at a later time, such as uploading analytics.
     * @hide
     */
     */
    public static final int NET_CAPABILITY_NOT_CONGESTED = 20;
    public static final int NET_CAPABILITY_NOT_CONGESTED = 20;


+4 −0
Original line number Original line Diff line number Diff line
@@ -149,6 +149,10 @@ public class RecurrenceRule implements Parcelable {
        }
        }
    };
    };


    public boolean isRecurring() {
        return period != null;
    }

    @Deprecated
    @Deprecated
    public boolean isMonthly() {
    public boolean isMonthly() {
        return start != null
        return start != null
+76 −36
Original line number Original line Diff line number Diff line
@@ -80,6 +80,9 @@ import static android.provider.Settings.Global.NETPOLICY_QUOTA_UNLIMITED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_NOTIFICATION_BOOL;
import static android.telephony.CarrierConfigManager.KEY_DATA_RAPID_NOTIFICATION_BOOL;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;


import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.appendInt;
@@ -1093,8 +1096,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        final long now = mClock.millis();
        final long now = mClock.millis();
        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
            final int subId = findRelevantSubId(policy.template);

            // ignore policies that aren't relevant to user
            // ignore policies that aren't relevant to user
            if (!isTemplateRelevant(policy.template)) continue;
            if (subId == INVALID_SUBSCRIPTION_ID) continue;
            if (!policy.hasCycle()) continue;
            if (!policy.hasCycle()) continue;


            final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
            final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
@@ -1103,7 +1108,27 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            final long cycleEnd = cycle.second.toInstant().toEpochMilli();
            final long cycleEnd = cycle.second.toInstant().toEpochMilli();
            final long totalBytes = getTotalBytes(policy.template, cycleStart, cycleEnd);
            final long totalBytes = getTotalBytes(policy.template, cycleStart, cycleEnd);


            // Notify when data usage is over warning/limit
            // Carrier might want to manage notifications themselves
            final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
            final boolean notifyWarning = getBooleanDefeatingNullable(config,
                    KEY_DATA_WARNING_NOTIFICATION_BOOL, true);
            final boolean notifyLimit = getBooleanDefeatingNullable(config,
                    KEY_DATA_LIMIT_NOTIFICATION_BOOL, true);
            final boolean notifyRapid = getBooleanDefeatingNullable(config,
                    KEY_DATA_RAPID_NOTIFICATION_BOOL, true);

            // Notify when data usage is over warning
            if (notifyWarning) {
                if (policy.isOverWarning(totalBytes) && !policy.isOverLimit(totalBytes)) {
                    final boolean snoozedThisCycle = policy.lastWarningSnooze >= cycleStart;
                    if (!snoozedThisCycle) {
                        enqueueNotification(policy, TYPE_WARNING, totalBytes, null);
                    }
                }
            }

            // Notify when data usage is over limit
            if (notifyLimit) {
                if (policy.isOverLimit(totalBytes)) {
                if (policy.isOverLimit(totalBytes)) {
                    final boolean snoozedThisCycle = policy.lastLimitSnooze >= cycleStart;
                    final boolean snoozedThisCycle = policy.lastLimitSnooze >= cycleStart;
                    if (snoozedThisCycle) {
                    if (snoozedThisCycle) {
@@ -1112,19 +1137,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        enqueueNotification(policy, TYPE_LIMIT, totalBytes, null);
                        enqueueNotification(policy, TYPE_LIMIT, totalBytes, null);
                        notifyOverLimitNL(policy.template);
                        notifyOverLimitNL(policy.template);
                    }
                    }

                } else {
                } else {
                    notifyUnderLimitNL(policy.template);
                    notifyUnderLimitNL(policy.template);

                final boolean snoozedThisCycle = policy.lastWarningSnooze >= cycleStart;
                if (policy.isOverWarning(totalBytes) && !snoozedThisCycle) {
                    enqueueNotification(policy, TYPE_WARNING, totalBytes, null);
                }
                }
            }
            }


            // Warn if average usage over last 4 days is on track to blow pretty
            // Warn if average usage over last 4 days is on track to blow pretty
            // far past the plan limits.
            // far past the plan limits.
            if (policy.limitBytes != LIMIT_DISABLED) {
            if (notifyRapid && policy.limitBytes != LIMIT_DISABLED) {
                final long recentDuration = TimeUnit.DAYS.toMillis(4);
                final long recentDuration = TimeUnit.DAYS.toMillis(4);
                final long recentStart = now - recentDuration;
                final long recentStart = now - recentDuration;
                final long recentEnd = now;
                final long recentEnd = now;
@@ -1201,9 +1221,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     * current device state, such as when
     * current device state, such as when
     * {@link TelephonyManager#getSubscriberId()} matches. This is regardless of
     * {@link TelephonyManager#getSubscriberId()} matches. This is regardless of
     * data connection status.
     * data connection status.
     *
     * @return relevant subId, or {@link #INVALID_SUBSCRIPTION_ID} when no
     *         matching subId found.
     */
     */
    private boolean isTemplateRelevant(NetworkTemplate template) {
    private int findRelevantSubId(NetworkTemplate template) {
        if (template.isMatchRuleMobile()) {
        final TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
        final TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
        final SubscriptionManager sub = mContext.getSystemService(SubscriptionManager.class);
        final SubscriptionManager sub = mContext.getSystemService(SubscriptionManager.class);


@@ -1215,13 +1237,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
                    TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
                    true);
                    true);
            if (template.matches(probeIdent)) {
            if (template.matches(probeIdent)) {
                    return true;
                return subId;
            }
            }
        }
        }
            return false;
        return INVALID_SUBSCRIPTION_ID;
        } else {
            return true;
        }
    }
    }


    /**
    /**
@@ -3086,9 +3105,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {


        // We can only override when carrier told us about plans
        // We can only override when carrier told us about plans
        synchronized (mNetworkPoliciesSecondLock) {
        synchronized (mNetworkPoliciesSecondLock) {
            if (ArrayUtils.isEmpty(mSubscriptionPlans.get(subId))) {
            final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
            if (plan == null
                    || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) {
                throw new IllegalStateException(
                throw new IllegalStateException(
                        "Must provide SubscriptionPlan information before overriding");
                        "Must provide valid SubscriptionPlan to enable overriding");
            }
            }
        }
        }


@@ -4831,7 +4852,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    @GuardedBy("mNetworkPoliciesSecondLock")
    @GuardedBy("mNetworkPoliciesSecondLock")
    private SubscriptionPlan getPrimarySubscriptionPlanLocked(int subId) {
    private SubscriptionPlan getPrimarySubscriptionPlanLocked(int subId) {
        final SubscriptionPlan[] plans = mSubscriptionPlans.get(subId);
        final SubscriptionPlan[] plans = mSubscriptionPlans.get(subId);
        return ArrayUtils.isEmpty(plans) ? null : plans[0];
        if (!ArrayUtils.isEmpty(plans)) {
            for (SubscriptionPlan plan : plans) {
                if (plan.getCycleRule().isRecurring()) {
                    // Recurring plans will always have an active cycle
                    return plan;
                } else {
                    // Non-recurring plans need manual test for active cycle
                    final Range<ZonedDateTime> cycle = plan.cycleIterator().next();
                    if (cycle.contains(ZonedDateTime.now(mClock))) {
                        return plan;
                    }
                }
            }
        }
        return null;
    }
    }


    /**
    /**
@@ -4878,6 +4913,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        return (val != null) ? val : new NetworkState[0];
        return (val != null) ? val : new NetworkState[0];
    }
    }


    private static boolean getBooleanDefeatingNullable(@Nullable PersistableBundle bundle,
            String key, boolean defaultValue) {
        return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
    }

    private class NotificationId {
    private class NotificationId {
        private final String mTag;
        private final String mTag;
        private final int mId;
        private final int mId;
+2 −0
Original line number Original line Diff line number Diff line
@@ -1714,6 +1714,8 @@ public class NetworkPolicyManagerServiceTest {
    }
    }


    private void expectNetworkState(boolean roaming) throws Exception {
    private void expectNetworkState(boolean roaming) throws Exception {
        when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
                .thenReturn(CarrierConfigManager.getDefaultConfig());
        when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
        when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
                new NetworkState(buildNetworkInfo(),
                new NetworkState(buildNetworkInfo(),
                        buildLinkProperties(TEST_IFACE),
                        buildLinkProperties(TEST_IFACE),
Loading