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

Commit 425af45d authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Cherrypick: Define the calculateRankingScore method and Key."

parents 4a04c07d 0d79bdef
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -25826,8 +25826,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);
    }
}