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

Commit d2fb46ea authored by Adam Newman's avatar Adam Newman Committed by Android (Google) Code Review
Browse files

Merge "Observe NetworkCallback instead of polling" into pi-dev

parents 74ac3b1f 5178a9d0
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.settings.wifi;

import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;

import com.android.internal.util.Preconditions;

/** Listens for changes to NetworkCapabilities to update the ConnectedAccessPointPreference. */
final class CaptivePortalNetworkCallback extends NetworkCallback {

    private final ConnectedAccessPointPreference mConnectedApPreference;
    private final Network mNetwork;

    private boolean mIsCaptivePortal;

    CaptivePortalNetworkCallback(
            Network network, ConnectedAccessPointPreference connectedApPreference) {
        mNetwork = Preconditions.checkNotNull(network);
        mConnectedApPreference = Preconditions.checkNotNull(connectedApPreference);
    }

    @Override
    public void onLost(Network network) {
        if (mNetwork.equals(network)) {
            mIsCaptivePortal = false;
        }
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        if (mNetwork.equals(network)) {
            mIsCaptivePortal = WifiUtils.canSignIntoNetwork(networkCapabilities);
            mConnectedApPreference.setCaptivePortal(mIsCaptivePortal);
        }
    }

    /**
     * Returns true if the supplied network and preference are not null and are the same as the
     * originally supplied values.
     */
    public boolean isSameNetworkAndPreference(
            Network network, ConnectedAccessPointPreference connectedApPreference) {
        return mNetwork.equals(network) && mConnectedApPreference == connectedApPreference;
    }

    /**
     * Returns true if the most recent update to the NetworkCapabilities indicates a captive portal
     * network and the Network was not lost in the interim.
     */
    public boolean isCaptivePortal() {
        return mIsCaptivePortal;
    }

    /** Returns the currently associated network. */
    public Network getNetwork() {
        return mNetwork;
    }
}
+13 −13
Original line number Diff line number Diff line
@@ -31,15 +31,12 @@ import com.android.settingslib.wifi.AccessPointPreference;
public class ConnectedAccessPointPreference extends AccessPointPreference implements
        View.OnClickListener {

    private final CaptivePortalStatus mCaptivePortalStatus;
    private OnGearClickListener mOnGearClickListener;
    private boolean mCaptivePortalNetwork;
    private boolean mIsCaptivePortal;

    public ConnectedAccessPointPreference(AccessPoint accessPoint, Context context,
            UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks,
            CaptivePortalStatus captivePortalStatus) {
            UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks) {
        super(accessPoint, context, cache, iconResId, forSavedNetworks);
        mCaptivePortalStatus = captivePortalStatus;
    }

    @Override
@@ -51,9 +48,8 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem
    public void refresh() {
        super.refresh();

        mCaptivePortalNetwork = mCaptivePortalStatus.isCaptivePortalNetwork();
        setShowDivider(mCaptivePortalNetwork);
        if (mCaptivePortalNetwork) {
        setShowDivider(mIsCaptivePortal);
        if (mIsCaptivePortal) {
            setSummary(R.string.wifi_tap_to_sign_in);
        }
    }
@@ -71,8 +67,8 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem
        gear.setOnClickListener(this);

        final View gearNoBg = holder.findViewById(R.id.settings_button_no_background);
        gearNoBg.setVisibility(mCaptivePortalNetwork ? View.INVISIBLE : View.VISIBLE);
        gear.setVisibility(mCaptivePortalNetwork ? View.VISIBLE : View.INVISIBLE);
        gearNoBg.setVisibility(mIsCaptivePortal ? View.INVISIBLE : View.VISIBLE);
        gear.setVisibility(mIsCaptivePortal ? View.VISIBLE : View.INVISIBLE);
    }

    @Override
@@ -84,11 +80,15 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem
        }
    }

    public void setCaptivePortal(boolean isCaptivePortal) {
        if (mIsCaptivePortal != isCaptivePortal) {
            mIsCaptivePortal = isCaptivePortal;
            refresh();
        }
    }

    public interface OnGearClickListener {
        void onGearClick(ConnectedAccessPointPreference p);
    }

    public interface CaptivePortalStatus {
        boolean isCaptivePortalNetwork();
    }
}
+58 −40
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.settings.wifi;

import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.os.UserManager.DISALLOW_CONFIG_WIFI;

import android.annotation.NonNull;
@@ -27,14 +28,15 @@ import android.content.Intent;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.NetworkRequest;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
@@ -124,6 +126,7 @@ public class WifiSettings extends RestrictedSettingsFragment
    private WifiManager.ActionListener mConnectListener;
    private WifiManager.ActionListener mSaveListener;
    private WifiManager.ActionListener mForgetListener;
    private CaptivePortalNetworkCallback mCaptivePortalNetworkCallback;

    /**
     * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is neccesary to
@@ -400,6 +403,7 @@ public class WifiSettings extends RestrictedSettingsFragment
    public void onStop() {
        getView().removeCallbacks(mUpdateAccessPointsRunnable);
        getView().removeCallbacks(mHideProgressBarRunnable);
        unregisterCaptivePortalNetworkCallback();
        super.onStop();
    }

@@ -786,11 +790,9 @@ public class WifiSettings extends RestrictedSettingsFragment

    @NonNull
    private ConnectedAccessPointPreference createConnectedAccessPointPreference(
            AccessPoint accessPoint,
            ConnectedAccessPointPreference.CaptivePortalStatus captivePortalStatus) {
            AccessPoint accessPoint) {
        return new ConnectedAccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache,
                R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */,
                captivePortalStatus);
                R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */);
    }

    /**
@@ -817,7 +819,8 @@ public class WifiSettings extends RestrictedSettingsFragment
        }

        // Is the previous currently connected SSID different from the new one?
        AccessPointPreference preference = (AccessPointPreference)
        ConnectedAccessPointPreference preference =
                (ConnectedAccessPointPreference)
                        (mConnectedAccessPointPreferenceCategory.getPreference(0));
        // The AccessPoints need to be the same reference to ensure that updates are reflected
        // in the UI.
@@ -829,8 +832,10 @@ public class WifiSettings extends RestrictedSettingsFragment

        // Else same AP is connected, simply refresh the connected access point preference
        // (first and only access point in this category).
        ((AccessPointPreference) mConnectedAccessPointPreferenceCategory.getPreference(0))
                .refresh();
        preference.refresh();
        // Update any potential changes to the connected network and ensure that the callback is
        // registered after an onStop lifecycle event.
        registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), preference);
        return true;
    }

@@ -840,18 +845,19 @@ public class WifiSettings extends RestrictedSettingsFragment
     */
    private void addConnectedAccessPointPreference(AccessPoint connectedAp) {
        final ConnectedAccessPointPreference pref =
                createConnectedAccessPointPreference(
                        connectedAp, this::isConnectedToCaptivePortalNetwork);
                createConnectedAccessPointPreference(connectedAp);
        registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), pref);

        // Launch details page or captive portal on click.
        pref.setOnPreferenceClickListener(
                preference -> {
                    pref.getAccessPoint().saveWifiState(pref.getExtras());
                    Network network = getConnectedWifiNetwork();
                    if (isConnectedToCaptivePortalNetwork(network)) {
                    if (mCaptivePortalNetworkCallback != null
                            && mCaptivePortalNetworkCallback.isCaptivePortal()) {
                        ConnectivityManagerWrapper connectivityManagerWrapper =
                                new ConnectivityManagerWrapper(mConnectivityManager);
                        connectivityManagerWrapper.startCaptivePortalApp(network);
                        connectivityManagerWrapper.startCaptivePortalApp(
                                mCaptivePortalNetworkCallback.getNetwork());
                    } else {
                        launchNetworkDetailsFragment(pref);
                    }
@@ -874,47 +880,59 @@ public class WifiSettings extends RestrictedSettingsFragment
        }
    }

    private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) {
        new SubSettingLauncher(getContext())
                .setTitle(getContext().getString(R.string.pref_title_network_details))
                .setDestination(WifiNetworkDetailsFragment.class.getName())
                .setArguments(pref.getExtras())
                .setSourceMetricsCategory(getMetricsCategory())
                .launch();
    private void registerCaptivePortalNetworkCallback(
            Network wifiNetwork, ConnectedAccessPointPreference pref) {
        if (wifiNetwork == null || pref == null) {
            Log.w(TAG, "Network or Preference were null when registering callback.");
            return;
        }

    private boolean isConnectedToCaptivePortalNetwork() {
        return isConnectedToCaptivePortalNetwork(getConnectedWifiNetwork());
        if (mCaptivePortalNetworkCallback != null
                && mCaptivePortalNetworkCallback.isSameNetworkAndPreference(wifiNetwork, pref)) {
            return;
        }

    private boolean isConnectedToCaptivePortalNetwork(Network network) {
        if (mConnectivityManager == null || network == null) {
            return false;
        }
        return WifiUtils.canSignIntoNetwork(mConnectivityManager.getNetworkCapabilities(network));
        unregisterCaptivePortalNetworkCallback();

        mCaptivePortalNetworkCallback = new CaptivePortalNetworkCallback(wifiNetwork, pref);
        mConnectivityManager.registerNetworkCallback(
                new NetworkRequest.Builder()
                        .clearCapabilities()
                        .addTransportType(TRANSPORT_WIFI)
                        .build(),
                mCaptivePortalNetworkCallback,
                new Handler(Looper.getMainLooper()));
    }

    private Network getConnectedWifiNetwork() {
        if (mConnectivityManager != null) {
            Network networks[] = mConnectivityManager.getAllNetworks();
            if (networks != null) {
                for (Network network : networks) {
                    NetworkCapabilities capabilities =
                            mConnectivityManager.getNetworkCapabilities(network);
                    if (capabilities != null
                            && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                        return network;
    private void unregisterCaptivePortalNetworkCallback() {
        if (mCaptivePortalNetworkCallback != null) {
            try {
                mConnectivityManager.unregisterNetworkCallback(mCaptivePortalNetworkCallback);
            } catch (RuntimeException e) {
                Log.e(TAG, "Unregistering CaptivePortalNetworkCallback failed.", e);
            }
            mCaptivePortalNetworkCallback = null;
        }
    }

    private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) {
        new SubSettingLauncher(getContext())
                .setTitle(getContext().getString(R.string.pref_title_network_details))
                .setDestination(WifiNetworkDetailsFragment.class.getName())
                .setArguments(pref.getExtras())
                .setSourceMetricsCategory(getMetricsCategory())
                .launch();
    }
        return null;

    private Network getCurrentWifiNetwork() {
        return mWifiManager != null ? mWifiManager.getCurrentNetwork() : null;
    }

    /** Removes all preferences and hide the {@link #mConnectedAccessPointPreferenceCategory}. */
    private void removeConnectedAccessPointPreference() {
        mConnectedAccessPointPreferenceCategory.removeAll();
        mConnectedAccessPointPreferenceCategory.setVisible(false);
        unregisterCaptivePortalNetworkCallback();
    }

    private void setAdditionalSettingsSummaries() {
+4 −8
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settings.wifi;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,7 +33,6 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;

@@ -45,8 +45,6 @@ public class ConnectedAccessPointPreferenceTest {
    private View mView;
    @Mock
    private ConnectedAccessPointPreference.OnGearClickListener mOnGearClickListener;
    @Mock
    private ConnectedAccessPointPreference.CaptivePortalStatus mCaptivePortalStatus;
    private Context mContext;
    private ConnectedAccessPointPreference mConnectedAccessPointPreference;

@@ -56,7 +54,7 @@ public class ConnectedAccessPointPreferenceTest {

        mContext = RuntimeEnvironment.application;
        mConnectedAccessPointPreference = new ConnectedAccessPointPreference(mAccessPoint, mContext,
                null, 0 /* iconResId */, false /* forSavedNetworks */, mCaptivePortalStatus);
                null, 0 /* iconResId */, false /* forSavedNetworks */);
        mConnectedAccessPointPreference.setOnGearClickListener(mOnGearClickListener);
    }

@@ -78,15 +76,13 @@ public class ConnectedAccessPointPreferenceTest {

    @Test
    public void testCaptivePortalStatus_isCaptivePortal_dividerDrawn() {
        Mockito.when(mCaptivePortalStatus.isCaptivePortalNetwork()).thenReturn(true);
        mConnectedAccessPointPreference.refresh();
        mConnectedAccessPointPreference.setCaptivePortal(true);
        assertThat(mConnectedAccessPointPreference.shouldShowDivider()).isTrue();
    }

    @Test
    public void testCaptivePortalStatus_isNotCaptivePortal_dividerNotDrawn() {
        Mockito.when(mCaptivePortalStatus.isCaptivePortalNetwork()).thenReturn(false);
        mConnectedAccessPointPreference.refresh();
        mConnectedAccessPointPreference.setCaptivePortal(false);
        assertThat(mConnectedAccessPointPreference.shouldShowDivider()).isFalse();
    }