Loading src/com/android/settings/wifi/ConnectedAccessPointPreference.java +0 −1 Original line number Diff line number Diff line Loading @@ -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 Loading src/com/android/settings/wifi/slice/ContextualWifiSlice.java +20 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } src/com/android/settings/wifi/slice/WifiScanWorker.java +34 −35 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -81,7 +83,7 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement @Override protected void onSliceUnpinned() { mWifiTracker.onStop(); unregisterCaptivePortalNetworkCallback(); unregisterNetworkCallback(); clearClickedWifi(); } Loading Loading @@ -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(); } Loading @@ -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); Loading src/com/android/settings/wifi/slice/WifiSlice.java +30 −83 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } Loading @@ -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, Loading @@ -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)); Loading @@ -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) { Loading Loading @@ -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 Loading @@ -283,6 +273,7 @@ public class WifiSlice implements CustomSliceable { return new ListBuilder.RowBuilder() .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE) .setTitle(placeholder) .setSubtitle(title); } Loading Loading @@ -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: Loading @@ -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); Loading @@ -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 */, Loading tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java +24 −21 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -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(); Loading @@ -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(); Loading @@ -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(); Loading @@ -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(); Loading @@ -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
src/com/android/settings/wifi/ConnectedAccessPointPreference.java +0 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
src/com/android/settings/wifi/slice/ContextualWifiSlice.java +20 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } }
src/com/android/settings/wifi/slice/WifiScanWorker.java +34 −35 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -81,7 +83,7 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement @Override protected void onSliceUnpinned() { mWifiTracker.onStop(); unregisterCaptivePortalNetworkCallback(); unregisterNetworkCallback(); clearClickedWifi(); } Loading Loading @@ -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(); } Loading @@ -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); Loading
src/com/android/settings/wifi/slice/WifiSlice.java +30 −83 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } Loading @@ -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, Loading @@ -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)); Loading @@ -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) { Loading Loading @@ -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 Loading @@ -283,6 +273,7 @@ public class WifiSlice implements CustomSliceable { return new ListBuilder.RowBuilder() .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE) .setTitle(placeholder) .setSubtitle(title); } Loading Loading @@ -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: Loading @@ -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); Loading @@ -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 */, Loading
tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java +24 −21 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -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(); Loading @@ -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(); Loading @@ -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(); Loading @@ -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(); Loading @@ -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; } }