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

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

Merge "Define the calculateRankingScore method and Key."

parents e9869cb0 c63d5b0c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -26194,8 +26194,9 @@ package android.net {
    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, android.os.Bundle);
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final java.lang.String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
    field public static final java.lang.String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
    field public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
    field public static final java.lang.String EXTRA_HAS_CAPTIVE_PORTAL = "android.net.extra.HAS_CAPTIVE_PORTAL";
    field public final android.os.Bundle attributes;
    field public final boolean meteredHint;
    field public final android.net.NetworkKey networkKey;
+67 −5
Original line number Diff line number Diff line
@@ -16,11 +16,14 @@

package android.net;

import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;

import java.lang.Math;
import java.lang.UnsupportedOperationException;
import java.util.Objects;

/**
@@ -43,7 +46,17 @@ public class ScoredNetwork implements Parcelable {
     * <p>
     * If no value is associated with this key then it's unknown.
     */
    public static final String EXTRA_HAS_CAPTIVE_PORTAL = "android.net.extra.HAS_CAPTIVE_PORTAL";
    public static final String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL =
            "android.net.attributes.key.HAS_CAPTIVE_PORTAL";

    /**
     * Key used with the {@link #attributes} bundle to define the rankingScoreOffset int value.
     *
     * <p>The rankingScoreOffset is used when calculating the ranking score used to rank networks
     * against one another. See {@link #calculateRankingScore} for more information.
     */
    public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET =
            "android.net.attributes.key.RANKING_SCORE_OFFSET";

    /** A {@link NetworkKey} uniquely identifying this network. */
    public final NetworkKey networkKey;
@@ -71,8 +84,10 @@ public class ScoredNetwork implements Parcelable {
     * An additional collection of optional attributes set by
     * the Network Recommendation Provider.
     *
     * @see #EXTRA_HAS_CAPTIVE_PORTAL
     * @see #ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL
     * @see #ATTRIBUTES_KEY_RANKING_SCORE_OFFSET_KEY
     */
    @Nullable
    public final Bundle attributes;

    /**
@@ -122,7 +137,7 @@ public class ScoredNetwork implements Parcelable {
     * @param attributes optional provider specific attributes
     */
    public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint,
            Bundle attributes) {
            @Nullable Bundle attributes) {
        this.networkKey = networkKey;
        this.rssiCurve = rssiCurve;
        this.meteredHint = meteredHint;
@@ -136,7 +151,7 @@ public class ScoredNetwork implements Parcelable {
        } else {
            rssiCurve = null;
        }
        meteredHint = in.readByte() != 0;
        meteredHint = (in.readByte() == 1);
        attributes = in.readBundle();
    }

@@ -156,7 +171,6 @@ public class ScoredNetwork implements Parcelable {
        }
        out.writeByte((byte) (meteredHint ? 1 : 0));
        out.writeBundle(attributes);

    }

    @Override
@@ -187,6 +201,54 @@ public class ScoredNetwork implements Parcelable {
                '}';
    }

    /**
     * Returns true if a ranking score can be calculated for this network.
     *
     * @hide
     */
    public boolean hasRankingScore() {
        return (rssiCurve != null)
                || (attributes != null
                        && attributes.containsKey(ATTRIBUTES_KEY_RANKING_SCORE_OFFSET));
    }

    /**
     * Returns a ranking score for a given RSSI which can be used to comparatively
     * rank networks.
     *
     * <p>The score obtained by the rssiCurve is bitshifted left by 8 bits to expand it to an
     * integer and then the offset is added. If the addition operation overflows or underflows,
     * Integer.MAX_VALUE and Integer.MIN_VALUE will be returned respectively.
     *
     * <p>{@link #hasRankingScore} should be called first to ensure this network is capable
     * of returning a ranking score.
     *
     * @throws UnsupportedOperationException if there is no RssiCurve and no rankingScoreOffset
     * for this network (hasRankingScore returns false).
     *
     * @hide
     */
    public int calculateRankingScore(int rssi) throws UnsupportedOperationException {
        if (!hasRankingScore()) {
            throw new UnsupportedOperationException(
                    "Either rssiCurve or rankingScoreOffset is required to calculate the "
                            + "ranking score");
        }

        int offset = 0;
        if (attributes != null) {
             offset += attributes.getInt(ATTRIBUTES_KEY_RANKING_SCORE_OFFSET, 0 /* default */);
        }

        int score = (rssiCurve == null) ? 0 : rssiCurve.lookupScore(rssi) << Byte.SIZE;

        try {
            return Math.addExact(score, offset);
        } catch (ArithmeticException e) {
            return (score < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
        }
    }

    public static final Parcelable.Creator<ScoredNetwork> CREATOR =
            new Parcelable.Creator<ScoredNetwork>() {
                @Override
+169 −0
Original line number Diff line number Diff line
/*
 t Copyright (C) 2016 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 android.net;

import static org.junit.Assert.*;

import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Arrays;

/** Unit tests for {@link ScoredNetwork}. */
@RunWith(AndroidJUnit4.class)
public class ScoredNetworkTest {

    private static final int RSSI_START = -110;
    private static final int TEST_RSSI = -50;
    private static final byte TEST_SCORE = 5;
    private static final RssiCurve CURVE =
            new RssiCurve(RSSI_START, 10, new byte[] {-1, 0, 1, 2, 3, 4, TEST_SCORE, 6, 7});

    private static final byte RANKING_SCORE_OFFSET = 13;
    private static final Bundle ATTRIBUTES;
    static {
        ATTRIBUTES = new Bundle();
        ATTRIBUTES.putInt(
                ScoredNetwork.ATTRIBUTES_KEY_RANKING_SCORE_OFFSET, RANKING_SCORE_OFFSET);
    }

    private static final NetworkKey KEY
        = new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00"));

    @Test
    public void calculateRankingOffsetShouldThrowUnsupportedOperationException() {
        // No curve or ranking score offset set in curve
        ScoredNetwork scoredNetwork = new ScoredNetwork(KEY, null);
        try {
            scoredNetwork.calculateRankingScore(TEST_RSSI);
            fail("Should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            // expected
        }
    }

    @Test
    public void calculateRankingOffsetWithRssiCurveShouldReturnExpectedScore() {
        ScoredNetwork scoredNetwork = new ScoredNetwork(KEY, CURVE);
        assertEquals(TEST_SCORE << Byte.SIZE, scoredNetwork.calculateRankingScore(TEST_RSSI));
    }

    @Test
    public void rankingScoresShouldDifferByRankingScoreOffset() {
        ScoredNetwork scoredNetwork1 = new ScoredNetwork(KEY, CURVE);
        ScoredNetwork scoredNetwork2
            = new ScoredNetwork(KEY, CURVE, false /* meteredHint */, ATTRIBUTES);
        int scoreDifference =
            scoredNetwork2.calculateRankingScore(TEST_RSSI)
            - scoredNetwork1.calculateRankingScore(TEST_RSSI);
        assertEquals(RANKING_SCORE_OFFSET, scoreDifference);
    }

    @Test
    public void calculateRankingScoreShouldNotResultInIntegerOverflow() {
        Bundle attr = new Bundle();
        attr.putInt(ScoredNetwork.ATTRIBUTES_KEY_RANKING_SCORE_OFFSET, Integer.MAX_VALUE);
        ScoredNetwork scoredNetwork
            = new ScoredNetwork(KEY, CURVE, false /* meteredHint */, attr);
        assertEquals(Integer.MAX_VALUE, scoredNetwork.calculateRankingScore(TEST_RSSI));
    }

    @Test
    public void calculateRankingScoreShouldNotResultInIntegerUnderflow() {
        Bundle attr = new Bundle();
        attr.putInt(ScoredNetwork.ATTRIBUTES_KEY_RANKING_SCORE_OFFSET, Integer.MIN_VALUE);
        ScoredNetwork scoredNetwork =
                new ScoredNetwork(KEY, CURVE, false /* meteredHint */, attr);
        assertEquals(Integer.MIN_VALUE, scoredNetwork.calculateRankingScore(RSSI_START));
    }

    @Test
    public void hasRankingScoreShouldReturnFalse() {
        ScoredNetwork network = new ScoredNetwork(KEY, null /* rssiCurve */);
        assertFalse(network.hasRankingScore());
    }

    @Test
    public void hasRankingScoreShouldReturnTrueWhenAttributesHasRankingScoreOffset() {
        ScoredNetwork network =
                new ScoredNetwork(KEY, null /* rssiCurve */, false /* meteredHint */, ATTRIBUTES);
        assertTrue(network.hasRankingScore());
    }

    @Test
    public void hasRankingScoreShouldReturnTrueWhenCurveIsPresent() {
        ScoredNetwork network =
                new ScoredNetwork(KEY, CURVE , false /* meteredHint */);
        assertTrue(network.hasRankingScore());
    }

    @Test
    public void shouldWriteAndReadFromParcelWhenAllFieldsSet() {
        ScoredNetwork network = new ScoredNetwork(KEY, CURVE, true /* meteredHint */, ATTRIBUTES);
        ScoredNetwork newNetwork;

        Parcel parcel = null;
        try {
            parcel = Parcel.obtain();
            network.writeToParcel(parcel, 0 /* flags */);
            parcel.setDataPosition(0);
            newNetwork = ScoredNetwork.CREATOR.createFromParcel(parcel);
        } finally {
            if (parcel != null) {
                parcel.recycle();
            }
        }
        assertEquals(CURVE.start, newNetwork.rssiCurve.start);
        assertEquals(CURVE.bucketWidth, newNetwork.rssiCurve.bucketWidth);
        assertTrue(Arrays.equals(CURVE.rssiBuckets, newNetwork.rssiCurve.rssiBuckets));
        assertTrue(newNetwork.meteredHint);
        assertNotNull(newNetwork.attributes);
        assertEquals(
                RANKING_SCORE_OFFSET,
                newNetwork.attributes.getInt(ScoredNetwork.ATTRIBUTES_KEY_RANKING_SCORE_OFFSET));
    }

    @Test
    public void shouldWriteAndReadFromParcelWithoutBundle() {
        ScoredNetwork network = new ScoredNetwork(KEY, CURVE, true /* meteredHint */);
        ScoredNetwork newNetwork;

        Parcel parcel = null;
        try {
            parcel = Parcel.obtain();
            network.writeToParcel(parcel, 0 /* flags */);
            parcel.setDataPosition(0);
            newNetwork = ScoredNetwork.CREATOR.createFromParcel(parcel);
        } finally {
            if (parcel != null) {
                parcel.recycle();
            }
        }
        assertEquals(CURVE.start, newNetwork.rssiCurve.start);
        assertEquals(CURVE.bucketWidth, newNetwork.rssiCurve.bucketWidth);
        assertTrue(Arrays.equals(CURVE.rssiBuckets, newNetwork.rssiCurve.rssiBuckets));
        assertTrue(newNetwork.meteredHint);
        assertNull(newNetwork.attributes);
    }
}