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

Commit c1e52b80 authored by Hai Shalom's avatar Hai Shalom Committed by Gerrit Code Review
Browse files

Merge "Support for Terms & Conditions notification"

parents e95ab5e3 c3289a19
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -6006,11 +6006,15 @@ package android.net {
    method public long getExpiryTimeMillis();
    method public long getRefreshTimeMillis();
    method @Nullable public android.net.Uri getUserPortalUrl();
    method public int getUserPortalUrlSource();
    method @Nullable public String getVenueFriendlyName();
    method @Nullable public android.net.Uri getVenueInfoUrl();
    method public int getVenueInfoUrlSource();
    method public boolean isCaptive();
    method public boolean isSessionExtendable();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
    field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
  }
@@ -6024,8 +6028,10 @@ package android.net {
    method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
    method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
    method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
  }
  public class ConnectivityManager {
+81 −7
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@

package android.net;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;

/**
@@ -40,10 +43,29 @@ public final class CaptivePortalData implements Parcelable {
    private final long mExpiryTimeMillis;
    private final boolean mCaptive;
    private final String mVenueFriendlyName;
    private final int mVenueInfoUrlSource;
    private final int mTermsAndConditionsSource;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"CAPTIVE_PORTAL_DATA_SOURCE_"}, value = {
            CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
            CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT})
    public @interface CaptivePortalDataSource {}

    /**
     * Source of information: Other (default)
     */
    public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0;

    /**
     * Source of information: Wi-Fi Passpoint
     */
    public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1;

    private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
            boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
            String venueFriendlyName) {
            String venueFriendlyName, int venueInfoUrlSource, int termsAndConditionsSource) {
        mRefreshTimeMillis = refreshTimeMillis;
        mUserPortalUrl = userPortalUrl;
        mVenueInfoUrl = venueInfoUrl;
@@ -52,11 +74,14 @@ public final class CaptivePortalData implements Parcelable {
        mExpiryTimeMillis = expiryTimeMillis;
        mCaptive = captive;
        mVenueFriendlyName = venueFriendlyName;
        mVenueInfoUrlSource = venueInfoUrlSource;
        mTermsAndConditionsSource = termsAndConditionsSource;
    }

    private CaptivePortalData(Parcel p) {
        this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
                p.readLong(), p.readLong(), p.readBoolean(), p.readString());
                p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
                p.readInt());
    }

    @Override
@@ -74,6 +99,8 @@ public final class CaptivePortalData implements Parcelable {
        dest.writeLong(mExpiryTimeMillis);
        dest.writeBoolean(mCaptive);
        dest.writeString(mVenueFriendlyName);
        dest.writeInt(mVenueInfoUrlSource);
        dest.writeInt(mTermsAndConditionsSource);
    }

    /**
@@ -88,6 +115,9 @@ public final class CaptivePortalData implements Parcelable {
        private long mExpiryTime = -1;
        private boolean mCaptive;
        private String mVenueFriendlyName;
        private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
        private @CaptivePortalDataSource int mUserPortalUrlSource =
                CAPTIVE_PORTAL_DATA_SOURCE_OTHER;

        /**
         * Create an empty builder.
@@ -100,8 +130,8 @@ public final class CaptivePortalData implements Parcelable {
        public Builder(@Nullable CaptivePortalData data) {
            if (data == null) return;
            setRefreshTime(data.mRefreshTimeMillis)
                    .setUserPortalUrl(data.mUserPortalUrl)
                    .setVenueInfoUrl(data.mVenueInfoUrl)
                    .setUserPortalUrl(data.mUserPortalUrl, data.mTermsAndConditionsSource)
                    .setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource)
                    .setSessionExtendable(data.mIsSessionExtendable)
                    .setBytesRemaining(data.mByteLimit)
                    .setExpiryTime(data.mExpiryTimeMillis)
@@ -123,7 +153,18 @@ public final class CaptivePortalData implements Parcelable {
         */
        @NonNull
        public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
            return setUserPortalUrl(userPortalUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
        }

        /**
         * Set the URL to be used for users to login to the portal, if captive, and the source of
         * the data, see {@link CaptivePortalDataSource}
         */
        @NonNull
        public Builder setUserPortalUrl(@Nullable Uri userPortalUrl,
                @CaptivePortalDataSource int source) {
            mUserPortalUrl = userPortalUrl;
            mUserPortalUrlSource = source;
            return this;
        }

@@ -132,7 +173,18 @@ public final class CaptivePortalData implements Parcelable {
         */
        @NonNull
        public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
            return setVenueInfoUrl(venueInfoUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
        }

        /**
         * Set the URL that can be used by users to view information about the network venue, and
         * the source of the data, see {@link CaptivePortalDataSource}
         */
        @NonNull
        public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl,
                @CaptivePortalDataSource int source) {
            mVenueInfoUrl = venueInfoUrl;
            mVenueInfoUrlSource = source;
            return this;
        }

@@ -188,7 +240,8 @@ public final class CaptivePortalData implements Parcelable {
        public CaptivePortalData build() {
            return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
                    mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive,
                    mVenueFriendlyName);
                    mVenueFriendlyName, mVenueInfoUrlSource,
                    mUserPortalUrlSource);
        }
    }

@@ -248,6 +301,22 @@ public final class CaptivePortalData implements Parcelable {
        return mCaptive;
    }

    /**
     * Get the information source of the Venue URL
     * @return The source that the Venue URL was obtained from
     */
    public @CaptivePortalDataSource int getVenueInfoUrlSource() {
        return mVenueInfoUrlSource;
    }

    /**
     * Get the information source of the user portal URL
     * @return The source that the user portal URL was obtained from
     */
    public @CaptivePortalDataSource int getUserPortalUrlSource() {
        return mTermsAndConditionsSource;
    }

    /**
     * Get the venue friendly name
     */
@@ -272,7 +341,8 @@ public final class CaptivePortalData implements Parcelable {
    @Override
    public int hashCode() {
        return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
                mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName);
                mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName,
                mVenueInfoUrlSource, mTermsAndConditionsSource);
    }

    @Override
@@ -286,7 +356,9 @@ public final class CaptivePortalData implements Parcelable {
                && mByteLimit == other.mByteLimit
                && mExpiryTimeMillis == other.mExpiryTimeMillis
                && mCaptive == other.mCaptive
                && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName);
                && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName)
                && mVenueInfoUrlSource == other.mVenueInfoUrlSource
                && mTermsAndConditionsSource == other.mTermsAndConditionsSource;
    }

    @Override
@@ -300,6 +372,8 @@ public final class CaptivePortalData implements Parcelable {
                + ", expiryTime: " + mExpiryTimeMillis
                + ", captive: " + mCaptive
                + ", venueFriendlyName: " + mVenueFriendlyName
                + ", venueInfoUrlSource: " + mVenueInfoUrlSource
                + ", termsAndConditionsSource: " + mTermsAndConditionsSource
                + "}";
    }
}
+12 −14
Original line number Diff line number Diff line
@@ -6407,20 +6407,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    Math.max(naData.getRefreshTimeMillis(), apiData.getRefreshTimeMillis()));
        }

        // Prioritize the user portal URL from the network agent.
        if (apiData.getUserPortalUrl() != null && (naData.getUserPortalUrl() == null
                || TextUtils.isEmpty(naData.getUserPortalUrl().toSafeString()))) {
            captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl());
        }
        // Prioritize the venue information URL from the network agent.
        if (apiData.getVenueInfoUrl() != null && (naData.getVenueInfoUrl() == null
                || TextUtils.isEmpty(naData.getVenueInfoUrl().toSafeString()))) {
            captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl());

            // Note that venue friendly name can only come from the network agent because it is not
            // in use in RFC8908. However, if using the Capport venue URL, make sure that the
            // friendly name is not set from the network agent.
            captivePortalBuilder.setVenueFriendlyName(null);
        // Prioritize the user portal URL from the network agent if the source is authenticated.
        if (apiData.getUserPortalUrl() != null && naData.getUserPortalUrlSource()
                != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
            captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl(),
                    apiData.getUserPortalUrlSource());
        }
        // Prioritize the venue information URL from the network agent if the source is
        // authenticated.
        if (apiData.getVenueInfoUrl() != null && naData.getVenueInfoUrlSource()
                != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
            captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl(),
                    apiData.getVenueInfoUrlSource());
        }
        return captivePortalBuilder.build();
    }
+14 −12
Original line number Diff line number Diff line
@@ -161,13 +161,20 @@ public class NetworkNotificationManager {
        if (nai != null) {
            transportType = approximateTransportType(nai);
            final String extraInfo = nai.networkInfo.getExtraInfo();
            name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSsid() : extraInfo;
            if (nai.linkProperties != null && nai.linkProperties.getCaptivePortalData() != null
                    && !TextUtils.isEmpty(nai.linkProperties.getCaptivePortalData()
                    .getVenueFriendlyName())) {
                name = nai.linkProperties.getCaptivePortalData().getVenueFriendlyName();
            } else {
                name = TextUtils.isEmpty(extraInfo)
                        ? WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()) : extraInfo;
            }
            // Only notify for Internet-capable networks.
            if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
        } else {
            // Legacy notifications.
            transportType = TRANSPORT_CELLULAR;
            name = null;
            name = "";
        }

        // Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -193,35 +200,30 @@ public class NetworkNotificationManager {
        final CharSequence details;
        int icon = getIcon(transportType);
        if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
            title = r.getString(R.string.wifi_no_internet,
                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
            title = r.getString(R.string.wifi_no_internet, name);
            details = r.getString(R.string.wifi_no_internet_detailed);
        } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
            if (transportType == TRANSPORT_CELLULAR) {
                title = r.getString(R.string.mobile_no_internet);
            } else if (transportType == TRANSPORT_WIFI) {
                title = r.getString(R.string.wifi_no_internet,
                        WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
                title = r.getString(R.string.wifi_no_internet, name);
            } else {
                title = r.getString(R.string.other_networks_no_internet);
            }
            details = r.getString(R.string.private_dns_broken_detailed);
        } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
                && transportType == TRANSPORT_WIFI) {
            title = r.getString(R.string.network_partial_connectivity,
                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
            title = r.getString(R.string.network_partial_connectivity, name);
            details = r.getString(R.string.network_partial_connectivity_detailed);
        } else if (notifyType == NotificationType.LOST_INTERNET &&
                transportType == TRANSPORT_WIFI) {
            title = r.getString(R.string.wifi_no_internet,
                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
            title = r.getString(R.string.wifi_no_internet, name);
            details = r.getString(R.string.wifi_no_internet_detailed);
        } else if (notifyType == NotificationType.SIGN_IN) {
            switch (transportType) {
                case TRANSPORT_WIFI:
                    title = r.getString(R.string.wifi_available_sign_in, 0);
                    details = r.getString(R.string.network_available_sign_in_detailed,
                            WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
                    details = r.getString(R.string.network_available_sign_in_detailed, name);
                    break;
                case TRANSPORT_CELLULAR:
                    title = r.getString(R.string.network_available_sign_in, 0);
+52 −1
Original line number Diff line number Diff line
@@ -54,12 +54,26 @@ class CaptivePortalDataTest {
            }
            .build()

    private val dataFromPasspoint = CaptivePortalData.Builder()
            .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
            .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
            .setCaptive(true)
            .apply {
                if (SdkLevel.isAtLeastS()) {
                    setVenueFriendlyName("venue friendly name")
                }
            }
            .build()

    private fun makeBuilder() = CaptivePortalData.Builder(data)

    @Test
    fun testParcelUnparcel() {
        val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7
        val fieldCount = if (SdkLevel.isAtLeastS()) 10 else 7
        assertParcelSane(data, fieldCount)
        assertParcelSane(dataFromPasspoint, fieldCount)

        assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
        assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
@@ -83,6 +97,27 @@ class CaptivePortalDataTest {
            assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
            assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
        }

        assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
        assertNotEqualsAfterChange { it.setUserPortalUrl(
                Uri.parse("https://tc.example.com/passpoint")) }
        assertNotEqualsAfterChange { it.setUserPortalUrl(
                Uri.parse("https://tc.example.com/passpoint"),
                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
        assertNotEqualsAfterChange { it.setUserPortalUrl(
                Uri.parse("https://tc.example.com/other"),
                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
        assertNotEqualsAfterChange { it.setUserPortalUrl(
                Uri.parse("https://tc.example.com/passpoint"),
                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
        assertNotEqualsAfterChange { it.setVenueInfoUrl(
                Uri.parse("https://venue.example.com/passpoint")) }
        assertNotEqualsAfterChange { it.setVenueInfoUrl(
                Uri.parse("https://venue.example.com/other"),
                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
        assertNotEqualsAfterChange { it.setVenueInfoUrl(
                Uri.parse("https://venue.example.com/passpoint"),
                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
    }

    @Test
@@ -130,6 +165,22 @@ class CaptivePortalDataTest {
        assertEquals("venue friendly name", data.venueFriendlyName)
    }

    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
    fun testGetVenueInfoUrlSource() {
        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
                data.venueInfoUrlSource)
        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
                dataFromPasspoint.venueInfoUrlSource)
    }

    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
    fun testGetUserPortalUrlSource() {
        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
                data.userPortalUrlSource)
        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
                dataFromPasspoint.userPortalUrlSource)
    }

    private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
            CaptivePortalData.Builder(this).apply { mutator(this) }.build()

Loading