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

Commit 34c4d2e2 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Support snoozing of data warning notification."

parents 96d4f4d8 0e2e5f8b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ interface INetworkPolicyManager {
    NetworkPolicy[] getNetworkPolicies();

    /** Snooze limit on policy matching given template. */
    void snoozePolicy(in NetworkTemplate template);
    void snoozeLimit(in NetworkTemplate template);

    /** Control if background data is restricted system-wide. */
    void setRestrictBackground(boolean restrictBackground);
+39 −11
Original line number Diff line number Diff line
@@ -38,18 +38,25 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
    public int cycleDay;
    public long warningBytes;
    public long limitBytes;
    public long lastSnooze;
    public long lastWarningSnooze;
    public long lastLimitSnooze;
    public boolean metered;

    private static final long DEFAULT_MTU = 1500;

    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes,
            long lastSnooze, boolean metered) {
    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
            long limitBytes, boolean metered) {
        this(template, cycleDay, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered);
    }

    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
            long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered) {
        this.template = checkNotNull(template, "missing NetworkTemplate");
        this.cycleDay = cycleDay;
        this.warningBytes = warningBytes;
        this.limitBytes = limitBytes;
        this.lastSnooze = lastSnooze;
        this.lastWarningSnooze = lastWarningSnooze;
        this.lastLimitSnooze = lastLimitSnooze;
        this.metered = metered;
    }

@@ -58,7 +65,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
        cycleDay = in.readInt();
        warningBytes = in.readLong();
        limitBytes = in.readLong();
        lastSnooze = in.readLong();
        lastWarningSnooze = in.readLong();
        lastLimitSnooze = in.readLong();
        metered = in.readInt() != 0;
    }

@@ -68,7 +76,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
        dest.writeInt(cycleDay);
        dest.writeLong(warningBytes);
        dest.writeLong(limitBytes);
        dest.writeLong(lastSnooze);
        dest.writeLong(lastWarningSnooze);
        dest.writeLong(lastLimitSnooze);
        dest.writeInt(metered ? 1 : 0);
    }

@@ -77,6 +86,13 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
        return 0;
    }

    /**
     * Test if given measurement is over {@link #warningBytes}.
     */
    public boolean isOverWarning(long totalBytes) {
        return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
    }

    /**
     * Test if given measurement is near enough to {@link #limitBytes} to be
     * considered over-limit.
@@ -88,6 +104,14 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
        return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
    }

    /**
     * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
     */
    public void clearSnooze() {
        lastWarningSnooze = SNOOZE_NEVER;
        lastLimitSnooze = SNOOZE_NEVER;
    }

    /** {@inheritDoc} */
    public int compareTo(NetworkPolicy another) {
        if (another == null || another.limitBytes == LIMIT_DISABLED) {
@@ -103,7 +127,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {

    @Override
    public int hashCode() {
        return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastSnooze, metered);
        return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastWarningSnooze,
                lastLimitSnooze, metered);
    }

    @Override
@@ -111,8 +136,10 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
        if (obj instanceof NetworkPolicy) {
            final NetworkPolicy other = (NetworkPolicy) obj;
            return cycleDay == other.cycleDay && warningBytes == other.warningBytes
                    && limitBytes == other.limitBytes && lastSnooze == other.lastSnooze
                    && metered == other.metered && Objects.equal(template, other.template);
                    && limitBytes == other.limitBytes
                    && lastWarningSnooze == other.lastWarningSnooze
                    && lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
                    && Objects.equal(template, other.template);
        }
        return false;
    }
@@ -120,8 +147,9 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
    @Override
    public String toString() {
        return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
                + warningBytes + ", limitBytes=" + limitBytes + ", lastSnooze=" + lastSnooze
                + ", metered=" + metered;
                + warningBytes + ", limitBytes=" + limitBytes + ", lastWarningSnooze="
                + lastWarningSnooze + ", lastLimitSnooze=" + lastLimitSnooze + ", metered="
                + metered;
    }

    public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
+1 −1
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ public class NetworkOverLimitActivity extends Activity {
        final INetworkPolicyManager policyService = INetworkPolicyManager.Stub.asInterface(
                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
        try {
            policyService.snoozePolicy(template);
            policyService.snoozeLimit(template);
        } catch (RemoteException e) {
            Slog.w(TAG, "problem snoozing network policy", e);
        }
+91 −25
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final int VERSION_ADDED_SNOOZE = 2;
    private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
    private static final int VERSION_ADDED_METERED = 4;
    private static final int VERSION_SPLIT_SNOOZE = 5;

    private static final long KB_IN_BYTES = 1024;
    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
@@ -176,6 +177,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final String ATTR_WARNING_BYTES = "warningBytes";
    private static final String ATTR_LIMIT_BYTES = "limitBytes";
    private static final String ATTR_LAST_SNOOZE = "lastSnooze";
    private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze";
    private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze";
    private static final String ATTR_METERED = "metered";
    private static final String ATTR_UID = "uid";
    private static final String ATTR_POLICY = "policy";
@@ -184,7 +187,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    // @VisibleForTesting
    public static final String ACTION_ALLOW_BACKGROUND =
            "com.android.server.action.ACTION_ALLOW_BACKGROUND";
            "com.android.server.net.action.ALLOW_BACKGROUND";
    public static final String ACTION_SNOOZE_WARNING =
            "com.android.server.net.action.SNOOZE_WARNING";

    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;

@@ -333,6 +338,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
        mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);

        // listen for snooze warning from notifications
        final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
        mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
                MANAGE_NETWORK_POLICY, mHandler);

    }

    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -417,6 +427,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    };

    /**
     * Receiver that watches for {@link Notification} control of
     * {@link NetworkPolicy#lastWarningSnooze}.
     */
    private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // on background handler thread, and verified MANAGE_NETWORK_POLICY
            // permission above.

            final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
            performSnooze(template, TYPE_WARNING);
        }
    };

    /**
     * Observer that watches for {@link INetworkManagementService} alerts.
     */
@@ -458,7 +483,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            final long totalBytes = getTotalBytes(policy.template, start, end);

            if (policy.isOverLimit(totalBytes)) {
                if (policy.lastSnooze >= start) {
                if (policy.lastLimitSnooze >= start) {
                    enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
                } else {
                    enqueueNotification(policy, TYPE_LIMIT, totalBytes);
@@ -468,7 +493,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            } else {
                notifyUnderLimitLocked(policy.template);

                if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
                if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
                    enqueueNotification(policy, TYPE_WARNING, totalBytes);
                }
            }
@@ -534,7 +559,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        final String tag = buildNotificationTag(policy, type);
        final Notification.Builder builder = new Notification.Builder(mContext);
        builder.setOnlyAlertOnce(true);
        builder.setOngoing(true);
        builder.setWhen(0L);

        final Resources res = mContext.getResources();
        switch (type) {
@@ -547,9 +572,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                builder.setContentTitle(title);
                builder.setContentText(body);

                final Intent intent = buildViewDataUsageIntent(policy.template);
                final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
                builder.setDeleteIntent(PendingIntent.getBroadcast(
                        mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));

                final Intent viewIntent = buildViewDataUsageIntent(policy.template);
                builder.setContentIntent(PendingIntent.getActivity(
                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
                        mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));

                break;
            }
            case TYPE_LIMIT: {
@@ -574,6 +604,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        break;
                }

                builder.setOngoing(true);
                builder.setSmallIcon(R.drawable.stat_notify_disabled);
                builder.setTicker(title);
                builder.setContentTitle(title);
@@ -608,6 +639,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        break;
                }

                builder.setOngoing(true);
                builder.setSmallIcon(R.drawable.stat_notify_error);
                builder.setTicker(title);
                builder.setContentTitle(title);
@@ -720,10 +752,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            final long totalBytes = getTotalBytes(policy.template, start, end);

            // disable data connection when over limit and not snoozed
            final boolean overLimit = policy.isOverLimit(totalBytes) && policy.lastSnooze < start;
            final boolean enabled = !overLimit;
            final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes)
                    && policy.lastLimitSnooze < start;
            final boolean networkEnabled = !overLimitWithoutSnooze;

            setNetworkTemplateEnabled(policy.template, enabled);
            setNetworkTemplateEnabled(policy.template, networkEnabled);
        }
    }

@@ -827,7 +860,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    // metered network, but no policy limit; we still need to
                    // restrict apps, so push really high quota.
                    quotaBytes = Long.MAX_VALUE;
                } else if (policy.lastSnooze >= start) {
                } else if (policy.lastLimitSnooze >= start) {
                    // snoozing past quota, but we still need to restrict apps,
                    // so push really high quota.
                    quotaBytes = Long.MAX_VALUE;
@@ -896,8 +929,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            final int cycleDay = time.monthDay;

            final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
            mNetworkPolicy.put(template, new NetworkPolicy(
                    template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, true));
            mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, warningBytes,
                    LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true));
            writePolicyLocked();
        }
    }
@@ -935,11 +968,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
                        final long lastSnooze;
                        if (version >= VERSION_ADDED_SNOOZE) {
                            lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
                        final long lastLimitSnooze;
                        if (version >= VERSION_SPLIT_SNOOZE) {
                            lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE);
                        } else if (version >= VERSION_ADDED_SNOOZE) {
                            lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
                        } else {
                            lastSnooze = SNOOZE_NEVER;
                            lastLimitSnooze = SNOOZE_NEVER;
                        }
                        final boolean metered;
                        if (version >= VERSION_ADDED_METERED) {
@@ -955,11 +990,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                                    metered = false;
                            }
                        }
                        final long lastWarningSnooze;
                        if (version >= VERSION_SPLIT_SNOOZE) {
                            lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE);
                        } else {
                            lastWarningSnooze = SNOOZE_NEVER;
                        }

                        final NetworkTemplate template = new NetworkTemplate(
                                networkTemplate, subscriberId);
                        mNetworkPolicy.put(template, new NetworkPolicy(
                                template, cycleDay, warningBytes, limitBytes, lastSnooze, metered));
                        mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
                                warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
                                metered));

                    } else if (TAG_UID_POLICY.equals(tag)) {
                        final int uid = readIntAttribute(in, ATTR_UID);
@@ -1014,7 +1056,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            out.startDocument(null, true);

            out.startTag(null, TAG_POLICY_LIST);
            writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_METERED);
            writeIntAttribute(out, ATTR_VERSION, VERSION_SPLIT_SNOOZE);
            writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);

            // write all known network policies
@@ -1030,7 +1072,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
                writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
                writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
                writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze);
                writeBooleanAttribute(out, ATTR_METERED, policy.metered);
                out.endTag(null, TAG_NETWORK_POLICY);
            }
@@ -1141,9 +1184,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    }

    @Override
    public void snoozePolicy(NetworkTemplate template) {
    public void snoozeLimit(NetworkTemplate template) {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
        performSnooze(template, TYPE_LIMIT);
    }

    private void performSnooze(NetworkTemplate template, int type) {
        maybeRefreshTrustedTime();
        final long currentTime = currentTimeMillis();
        synchronized (mRulesLock) {
@@ -1153,7 +1199,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                throw new IllegalArgumentException("unable to find policy for " + template);
            }

            policy.lastSnooze = currentTime;
            switch (type) {
                case TYPE_WARNING:
                    policy.lastWarningSnooze = currentTime;
                    break;
                case TYPE_LIMIT:
                    policy.lastLimitSnooze = currentTime;
                    break;
                default:
                    throw new IllegalArgumentException("unexpected type");
            }

            updateNetworkEnabledLocked();
            updateNetworkRulesLocked();
@@ -1246,12 +1301,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }

        synchronized (mRulesLock) {
            if (argSet.contains("unsnooze")) {
            if (argSet.contains("--unsnooze")) {
                for (NetworkPolicy policy : mNetworkPolicy.values()) {
                    policy.lastSnooze = SNOOZE_NEVER;
                    policy.clearSnooze();
                }

                updateNetworkEnabledLocked();
                updateNetworkRulesLocked();
                updateNotificationsLocked();
                writePolicyLocked();
                fout.println("Wiped snooze timestamps");

                fout.println("Cleared snooze timestamps");
                return;
            }

@@ -1599,6 +1659,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        return new Intent(ACTION_ALLOW_BACKGROUND);
    }

    private static Intent buildSnoozeWarningIntent(NetworkTemplate template) {
        final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
        return intent;
    }

    private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
        final Intent intent = new Intent();
        intent.setComponent(new ComponentName(
+28 −23
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -256,41 +255,49 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
    }

    public void testPidForegroundCombined() throws Exception {
        IdleFuture idle;

        // push all uid into background
        idle = expectIdle();
        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
        waitUntilIdle();
        idle.get();
        assertFalse(mService.isUidForeground(UID_A));
        assertFalse(mService.isUidForeground(UID_B));

        // push one of the shared pids into foreground
        idle = expectIdle();
        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
        waitUntilIdle();
        idle.get();
        assertTrue(mService.isUidForeground(UID_A));
        assertFalse(mService.isUidForeground(UID_B));

        // and swap another uid into foreground
        idle = expectIdle();
        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
        waitUntilIdle();
        idle.get();
        assertFalse(mService.isUidForeground(UID_A));
        assertTrue(mService.isUidForeground(UID_B));

        // push both pid into foreground
        idle = expectIdle();
        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
        waitUntilIdle();
        idle.get();
        assertTrue(mService.isUidForeground(UID_A));

        // pull one out, should still be foreground
        idle = expectIdle();
        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
        waitUntilIdle();
        idle.get();
        assertTrue(mService.isUidForeground(UID_A));

        // pull final pid out, should now be background
        idle = expectIdle();
        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
        waitUntilIdle();
        idle.get();
        assertFalse(mService.isUidForeground(UID_A));
    }

@@ -434,7 +441,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");

        final NetworkPolicy policy = new NetworkPolicy(
                sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER, false);
                sTemplateWifi, 5, 1024L, 1024L, false);
        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
        assertTimeEquals(expectedCycle, actualCycle);
    }
@@ -445,7 +452,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");

        final NetworkPolicy policy = new NetworkPolicy(
                sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER, false);
                sTemplateWifi, 20, 1024L, 1024L, false);
        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
        assertTimeEquals(expectedCycle, actualCycle);
    }
@@ -456,7 +463,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");

        final NetworkPolicy policy = new NetworkPolicy(
                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
                sTemplateWifi, 30, 1024L, 1024L, false);
        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
        assertTimeEquals(expectedCycle, actualCycle);
    }
@@ -467,14 +474,14 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
        final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");

        final NetworkPolicy policy = new NetworkPolicy(
                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
                sTemplateWifi, 30, 1024L, 1024L, false);
        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
        assertTimeEquals(expectedCycle, actualCycle);
    }

    public void testNextCycleSane() throws Exception {
        final NetworkPolicy policy = new NetworkPolicy(
                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();

        // walk forwards, ensuring that cycle boundaries don't get stuck
@@ -489,7 +496,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {

    public void testLastCycleSane() throws Exception {
        final NetworkPolicy policy = new NetworkPolicy(
                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();

        // walk backwards, ensuring that cycle boundaries look sane
@@ -547,7 +554,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {

        replay();
        setNetworkPolicies(new NetworkPolicy(
                sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, SNOOZE_NEVER, false));
                sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
        future.get();
        verifyAndReset();
    }
@@ -604,9 +611,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
            future = expectMeteredIfacesChanged();

            replay();
            setNetworkPolicies(
                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES,
                            SNOOZE_NEVER, false));
            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES,
                    2 * MB_IN_BYTES, false));
            future.get();
            verifyAndReset();
        }
@@ -698,7 +704,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
            tagFuture = expectEnqueueNotification();

            replay();
            mService.snoozePolicy(sTemplateWifi);
            mService.snoozeLimit(sTemplateWifi);
            assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
            future.get();
            verifyAndReset();
@@ -736,9 +742,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
            future = expectMeteredIfacesChanged(TEST_IFACE);

            replay();
            setNetworkPolicies(
                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED, LIMIT_DISABLED,
                            SNOOZE_NEVER, true));
            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED,
                    LIMIT_DISABLED, true));
            future.get();
            verifyAndReset();
        }
@@ -890,10 +895,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
    /**
     * Wait until {@link #mService} internal {@link Handler} is idle.
     */
    private void waitUntilIdle() throws Exception {
    private IdleFuture expectIdle() {
        final IdleFuture future = new IdleFuture();
        mService.addIdleHandler(future);
        future.get();
        return future;
    }

    private static void assertTimeEquals(long expected, long actual) {