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

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

Merge "Add subtext for Wi-Fi items on Wi-Fi slice" into qt-dev

parents 65a258e2 6a6787cd
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import androidx.preference.PreferenceViewHolder;

import com.android.settings.R;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.AccessPointPreference;

/**
 * An AP preference for the currently connected AP
+20 −1
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@
package com.android.settings.wifi.slice;

import android.content.Context;
import android.net.NetworkCapabilities;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
import android.text.TextUtils;
import android.util.Log;
@@ -69,6 +72,22 @@ public class ContextualWifiSlice extends WifiSlice {
    }

    private boolean hasWorkingNetwork() {
        return !TextUtils.equals(getActiveSSID(), WifiSsid.NONE) && !isCaptivePortal();
        return !TextUtils.equals(getActiveSSID(), WifiSsid.NONE) && hasInternetAccess();
    }

    private String getActiveSSID() {
        if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
            return WifiSsid.NONE;
        }
        return WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo().getSSID());
    }

    private boolean hasInternetAccess() {
        final NetworkCapabilities nc = mConnectivityManager.getNetworkCapabilities(
                mWifiManager.getCurrentNetwork());
        return nc != null
                && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)
                && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)
                && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }
}
+34 −35
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package com.android.settings.wifi.slice;

import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;

import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;

import android.content.Context;
@@ -25,7 +29,6 @@ import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.Uri;
import android.net.wifi.WifiInfo;
@@ -40,7 +43,6 @@ import androidx.annotation.VisibleForTesting;

import com.android.internal.util.Preconditions;
import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.wifi.WifiUtils;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.WifiTracker;

@@ -56,7 +58,7 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
    private static final String TAG = "WifiScanWorker";

    @VisibleForTesting
    CaptivePortalNetworkCallback mCaptivePortalNetworkCallback;
    WifiNetworkCallback mNetworkCallback;

    private final Context mContext;
    private final ConnectivityManager mConnectivityManager;
@@ -81,7 +83,7 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
    @Override
    protected void onSliceUnpinned() {
        mWifiTracker.onStop();
        unregisterCaptivePortalNetworkCallback();
        unregisterNetworkCallback();
        clearClickedWifi();
    }

@@ -135,21 +137,13 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
        // compare access point states one by one
        final int listSize = a.size();
        for (int i = 0; i < listSize; i++) {
            if (getState(a.get(i)) != getState(b.get(i))) {
            if (a.get(i).getDetailedState() != b.get(i).getDetailedState()) {
                return false;
            }
        }
        return true;
    }

    private NetworkInfo.State getState(AccessPoint accessPoint) {
        final NetworkInfo networkInfo = accessPoint.getNetworkInfo();
        if (networkInfo != null) {
            return networkInfo.getState();
        }
        return null;
    }

    static void saveClickedWifi(AccessPoint accessPoint) {
        sClickedWifiSsid = accessPoint.getSsidStr();
    }
@@ -163,69 +157,74 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
        return !TextUtils.isEmpty(ssid) && TextUtils.equals(ssid, sClickedWifiSsid);
    }

    public void registerCaptivePortalNetworkCallback(Network wifiNetwork) {
    public void registerNetworkCallback(Network wifiNetwork) {
        if (wifiNetwork == null) {
            return;
        }

        if (mCaptivePortalNetworkCallback != null
                && mCaptivePortalNetworkCallback.isSameNetwork(wifiNetwork)) {
        if (mNetworkCallback != null && mNetworkCallback.isSameNetwork(wifiNetwork)) {
            return;
        }

        unregisterCaptivePortalNetworkCallback();
        unregisterNetworkCallback();

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

    public void unregisterCaptivePortalNetworkCallback() {
        if (mCaptivePortalNetworkCallback != null) {
    public void unregisterNetworkCallback() {
        if (mNetworkCallback != null) {
            try {
                mConnectivityManager.unregisterNetworkCallback(mCaptivePortalNetworkCallback);
                mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
            } catch (RuntimeException e) {
                Log.e(TAG, "Unregistering CaptivePortalNetworkCallback failed.", e);
            }
            mCaptivePortalNetworkCallback = null;
            mNetworkCallback = null;
        }
    }

    class CaptivePortalNetworkCallback extends NetworkCallback {
    class WifiNetworkCallback extends NetworkCallback {

        private final Network mNetwork;
        private boolean mIsCaptivePortal;
        private boolean mHasPartialConnectivity;
        private boolean mIsValidated;

        CaptivePortalNetworkCallback(Network network) {
        WifiNetworkCallback(Network network) {
            mNetwork = Preconditions.checkNotNull(network);
        }

        @Override
        public void onCapabilitiesChanged(Network network,
                NetworkCapabilities networkCapabilities) {
        public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
            if (!isSameNetwork(network)) {
                return;
            }

            final boolean isCaptivePortal = WifiUtils.canSignIntoNetwork(networkCapabilities);
            if (mIsCaptivePortal == isCaptivePortal) {
            final boolean prevIsCaptivePortal = mIsCaptivePortal;
            final boolean prevHasPartialConnectivity = mHasPartialConnectivity;
            final boolean prevIsValidated = mIsValidated;

            mIsCaptivePortal = nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
            mHasPartialConnectivity = nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
            mIsValidated = nc.hasCapability(NET_CAPABILITY_VALIDATED);

            if (prevIsCaptivePortal == mIsCaptivePortal
                    && prevHasPartialConnectivity == mHasPartialConnectivity
                    && prevIsValidated == mIsValidated) {
                return;
            }

            mIsCaptivePortal = isCaptivePortal;
            notifySliceChange();

            // Automatically start captive portal
            if (mIsCaptivePortal) {
                if (!isWifiClicked(mWifiTracker.getManager().getConnectionInfo())) {
                    return;
                }

            if (!prevIsCaptivePortal && mIsCaptivePortal
                    && isWifiClicked(mWifiTracker.getManager().getConnectionInfo())) {
                final Intent intent = new Intent(mContext, ConnectToWifiHandler.class)
                        .putExtra(ConnectivityManager.EXTRA_NETWORK, network)
                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+30 −83
Original line number Diff line number Diff line
@@ -34,17 +34,10 @@ import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.NetworkInfo.DetailedState;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;

import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
@@ -99,16 +92,16 @@ public class WifiSlice implements CustomSliceable {
        mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);

        final boolean isWifiEnabled = isWifiEnabled();
        ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* accessPoint */);
        ListBuilder listBuilder = getHeaderRow(isWifiEnabled);
        if (!isWifiEnabled) {
            return listBuilder.build();
        }

        final WifiScanWorker worker = SliceBackgroundWorker.getInstance(getUri());
        final List<AccessPoint> results = worker != null ? worker.getResults() : null;
        final int apCount = results == null ? 0 : results.size();
        final boolean isFirstApActive = apCount > 0 && results.get(0).isActive();
        handleCaptivePortalCallback(worker, isFirstApActive);
        final List<AccessPoint> apList = worker != null ? worker.getResults() : null;
        final int apCount = apList == null ? 0 : apList.size();
        final boolean isFirstApActive = apCount > 0 && apList.get(0).isActive();
        handleNetworkCallback(worker, isFirstApActive);

        // Need a loading text when results are not ready or out of date.
        boolean needLoadingRow = true;
@@ -117,7 +110,7 @@ public class WifiSlice implements CustomSliceable {
        // This loop checks the existence of reachable APs to determine the validity of the current
        // AP list.
        for (; index < apCount; index++) {
            if (results.get(index).isReachable()) {
            if (apList.get(index).isReachable()) {
                needLoadingRow = false;
                break;
            }
@@ -127,28 +120,24 @@ public class WifiSlice implements CustomSliceable {
        final CharSequence placeholder = mContext.getText(R.string.summary_placeholder);
        for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) {
            if (i < apCount) {
                final AccessPoint accessPoint = results.get(i);
                if (accessPoint.isActive()) {
                    // update summary
                    listBuilder = getListBuilder(isWifiEnabled, accessPoint);
                }
                listBuilder.addRow(getAccessPointRow(accessPoint));
                listBuilder.addRow(getAccessPointRow(apList.get(i)));
            } else if (needLoadingRow) {
                listBuilder.addRow(getLoadingRow());
                listBuilder.addRow(getLoadingRow(placeholder));
                needLoadingRow = false;
            } else {
                listBuilder.addRow(new ListBuilder.RowBuilder()
                        .setTitle(placeholder));
                        .setTitle(placeholder)
                        .setSubtitle(placeholder));
            }
        }
        return listBuilder.build();
    }

    private ListBuilder getListBuilder(boolean isWifiEnabled, AccessPoint accessPoint) {
    private ListBuilder getHeaderRow(boolean isWifiEnabled) {
        final IconCompat icon = IconCompat.createWithResource(mContext,
                R.drawable.ic_settings_wireless);
        final String title = mContext.getString(R.string.wifi_settings);
        final CharSequence summary = getSummary(accessPoint);
        final CharSequence summary = getSummary();
        final PendingIntent toggleAction = getBroadcastIntent(mContext);
        final PendingIntent primaryAction = getPrimaryAction();
        final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
@@ -166,24 +155,26 @@ public class WifiSlice implements CustomSliceable {
                        .setPrimaryAction(primarySliceAction));
    }

    private void handleCaptivePortalCallback(WifiScanWorker worker, boolean isFirstApActive) {
    private void handleNetworkCallback(WifiScanWorker worker, boolean isFirstApActive) {
        if (worker == null) {
            return;
        }
        if (isFirstApActive) {
            worker.registerCaptivePortalNetworkCallback(mWifiManager.getCurrentNetwork());
            worker.registerNetworkCallback(mWifiManager.getCurrentNetwork());
        } else {
            worker.unregisterCaptivePortalNetworkCallback();
            worker.unregisterNetworkCallback();
        }
    }

    private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) {
        final CharSequence title = getAccessPointName(accessPoint);
        final IconCompat levelIcon = getAccessPointLevelIcon(accessPoint);
        final boolean isCaptivePortal = accessPoint.isActive() && isCaptivePortal();
        final CharSequence title = accessPoint.getTitle();
        final CharSequence summary = getAccessPointSummary(accessPoint, isCaptivePortal);
        final IconCompat levelIcon = getAccessPointLevelIcon(accessPoint);
        final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
                .setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
                .setSubtitle(title)
                .setTitle(title)
                .setSubtitle(summary)
                .setPrimaryAction(SliceAction.createDeeplink(
                        getAccessPointAction(accessPoint, isCaptivePortal), levelIcon,
                        ListBuilder.ICON_IMAGE, title));
@@ -199,14 +190,13 @@ public class WifiSlice implements CustomSliceable {
        return rowBuilder;
    }

    private CharSequence getAccessPointName(AccessPoint accessPoint) {
        final CharSequence name = accessPoint.getTitle();
        final Spannable span = new SpannableString(name);
        @ColorInt final int color = Utils.getColorAttrDefaultColor(mContext,
                android.R.attr.textColorPrimary);
        span.setSpan(new ForegroundColorSpan(color), 0, name.length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return span;
    private CharSequence getAccessPointSummary(AccessPoint accessPoint, boolean isCaptivePortal) {
        if (isCaptivePortal) {
            return mContext.getText(R.string.wifi_tap_to_sign_in);
        }

        final CharSequence summary = accessPoint.getSettingsSummary();
        return TextUtils.isEmpty(summary) ? mContext.getText(R.string.disconnected) : summary;
    }

    private IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) {
@@ -274,7 +264,7 @@ public class WifiSlice implements CustomSliceable {
                intent, 0 /* flags */);
    }

    private ListBuilder.RowBuilder getLoadingRow() {
    private ListBuilder.RowBuilder getLoadingRow(CharSequence placeholder) {
        final CharSequence title = mContext.getText(R.string.wifi_empty_list_wifi_on);

        // for aligning to the Wi-Fi AP's name
@@ -283,6 +273,7 @@ public class WifiSlice implements CustomSliceable {

        return new ListBuilder.RowBuilder()
                .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE)
                .setTitle(placeholder)
                .setSubtitle(title);
    }

@@ -319,13 +310,6 @@ public class WifiSlice implements CustomSliceable {
        return intent;
    }

    protected String getActiveSSID() {
        if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
            return WifiSsid.NONE;
        }
        return WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo().getSSID());
    }

    private boolean isWifiEnabled() {
        switch (mWifiManager.getWifiState()) {
            case WifiManager.WIFI_STATE_ENABLED:
@@ -339,13 +323,8 @@ public class WifiSlice implements CustomSliceable {
    private CharSequence getSummary() {
        switch (mWifiManager.getWifiState()) {
            case WifiManager.WIFI_STATE_ENABLED:
                final String ssid = getActiveSSID();
                if (TextUtils.equals(ssid, WifiSsid.NONE)) {
                    return mContext.getText(R.string.disconnected);
                }
                return ssid;
            case WifiManager.WIFI_STATE_ENABLING:
                return mContext.getText(R.string.disconnected);
                return mContext.getText(R.string.switch_on_text);
            case WifiManager.WIFI_STATE_DISABLED:
            case WifiManager.WIFI_STATE_DISABLING:
                return mContext.getText(R.string.switch_off_text);
@@ -355,38 +334,6 @@ public class WifiSlice implements CustomSliceable {
        }
    }

    private CharSequence getSummary(AccessPoint accessPoint) {
        if (isCaptivePortal()) {
            final int id = mContext.getResources()
                    .getIdentifier("network_available_sign_in", "string", "android");
            return mContext.getText(id);
        }

        if (accessPoint == null) {
            return getSummary();
        }

        final NetworkInfo networkInfo = accessPoint.getNetworkInfo();
        if (networkInfo == null) {
            return getSummary();
        }

        final State state = networkInfo.getState();
        DetailedState detailedState;
        if (state == State.CONNECTING) {
            detailedState = DetailedState.CONNECTING;
        } else if (state == State.CONNECTED) {
            detailedState = DetailedState.CONNECTED;
        } else {
            return getSummary();
        }

        final String[] formats = mContext.getResources().getStringArray(
                R.array.wifi_status_with_ssid);
        final int index = detailedState.ordinal();
        return String.format(formats[index], accessPoint.getTitle());
    }

    private PendingIntent getPrimaryAction() {
        final Intent intent = getIntent();
        return PendingIntent.getActivity(mContext, 0 /* requestCode */,
+24 −21
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settings.wifi.slice;

import static org.mockito.ArgumentMatchers.any;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.doReturn;
@@ -25,7 +24,7 @@ import static org.mockito.Mockito.spy;

import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;

@@ -40,22 +39,24 @@ import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.SlicesFeatureProviderImpl;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowConnectivityManager.class)
public class ContextualWifiSliceTest {

    private Context mContext;
    private ContentResolver mResolver;
    private WifiManager mWifiManager;
    private ConnectivityManager mConnectivityManager;
    private ContextualWifiSlice mWifiSlice;
    private FakeFeatureFactory mFeatureFactory;

@@ -73,9 +74,6 @@ public class ContextualWifiSliceTest {
        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
        mWifiManager.setWifiEnabled(true);

        mConnectivityManager = spy(mContext.getSystemService(ConnectivityManager.class));
        doReturn(mConnectivityManager).when(mContext).getSystemService(ConnectivityManager.class);

        mWifiSlice = new ContextualWifiSlice(mContext);
        mWifiSlice.sPreviouslyDisplayed = false;
    }
@@ -83,9 +81,7 @@ public class ContextualWifiSliceTest {
    @Test
    public void getWifiSlice_hasActiveConnection_shouldReturnNull() {
        mWifiSlice.sPreviouslyDisplayed = false;
        final WifiConfiguration config = new WifiConfiguration();
        config.SSID = "123";
        mWifiManager.connect(config, null /* listener */);
        connectToWifi(makeValidatedNetworkCapabilities());

        final Slice wifiSlice = mWifiSlice.getSlice();

@@ -98,10 +94,7 @@ public class ContextualWifiSliceTest {
        // previous displayed: yes
        mWifiSlice.sPreviouslyDisplayed = true;
        mWifiSlice.sActiveUiSession = ~mFeatureFactory.slicesFeatureProvider.getUiSessionToken();

        final WifiConfiguration config = new WifiConfiguration();
        config.SSID = "123";
        mWifiManager.connect(config, null /* listener */);
        connectToWifi(makeValidatedNetworkCapabilities());

        final Slice wifiSlice = mWifiSlice.getSlice();

@@ -112,9 +105,7 @@ public class ContextualWifiSliceTest {
    public void getWifiSlice_previousDisplayed_hasActiveConnection_shouldHaveTitleAndToggle() {
        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
        mWifiSlice.sPreviouslyDisplayed = true;
        final WifiConfiguration config = new WifiConfiguration();
        config.SSID = "123";
        mWifiManager.connect(config, null /* listener */);
        connectToWifi(makeValidatedNetworkCapabilities());

        final Slice wifiSlice = mWifiSlice.getSlice();

@@ -133,11 +124,7 @@ public class ContextualWifiSliceTest {
    @Test
    public void getWifiSlice_isCaptivePortal_shouldHaveTitleAndToggle() {
        mWifiSlice.sPreviouslyDisplayed = false;
        final WifiConfiguration config = new WifiConfiguration();
        config.SSID = "123";
        mWifiManager.connect(config, null /* listener */);
        doReturn(WifiSliceTest.makeCaptivePortalNetworkCapabilities()).when(mConnectivityManager)
                .getNetworkCapabilities(any());
        connectToWifi(WifiSliceTest.makeCaptivePortalNetworkCapabilities());

        final Slice wifiSlice = mWifiSlice.getSlice();

@@ -162,4 +149,20 @@ public class ContextualWifiSliceTest {

        assertThat(wifiSlice.getUri()).isEqualTo(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI);
    }

    private void connectToWifi(NetworkCapabilities nc) {
        final WifiConfiguration config = new WifiConfiguration();
        config.SSID = "123";
        mWifiManager.connect(config, null /* listener */);
        ShadowConnectivityManager.getShadow().setNetworkCapabilities(
                mWifiManager.getCurrentNetwork(), nc);
    }

    private NetworkCapabilities makeValidatedNetworkCapabilities() {
        final NetworkCapabilities nc = new NetworkCapabilities();
        nc.clearAll();
        nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
        return nc;
    }
}
Loading