From 7577624db7bf9d9c8382161bab25849589822601 Mon Sep 17 00:00:00 2001 From: Adam Newman Date: Thu, 8 Mar 2018 16:59:34 -0800 Subject: [PATCH] Enable launching captive portal directly Whenever a user has connected to a captive portal network, split the ConnectedAccessPointPreference to allow directly signing into the captive portal or modifying the network's settings. When in any other network state, use the old behavior of a single tappable preference that takes the user to settings. Bug: 63929546 Bug: 68031656 Test: make RunSettingsRoboTests Test: manual by connecting to Captive Portal and normal WiFi networks. Change-Id: I444202a12138d90c94bda94945c121c8c0810536 --- ...erence_widget_gear_optional_background.xml | 48 ++++++++++ res/values/strings.xml | 2 + .../wifi/ConnectedAccessPointPreference.java | 39 ++++++++- .../android/settings/wifi/WifiSettings.java | 87 +++++++++++++++---- src/com/android/settings/wifi/WifiUtils.java | 8 +- .../WifiDetailPreferenceController.java | 3 +- .../ConnectedAccessPointPreferenceTest.java | 21 ++++- 7 files changed, 186 insertions(+), 22 deletions(-) create mode 100644 res/layout/preference_widget_gear_optional_background.xml diff --git a/res/layout/preference_widget_gear_optional_background.xml b/res/layout/preference_widget_gear_optional_background.xml new file mode 100644 index 00000000000..d02f638bddd --- /dev/null +++ b/res/layout/preference_widget_gear_optional_background.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index a611a82257d..99aee0fc5f9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1731,6 +1731,8 @@ 5 GHz Sign in + + Tap here to sign in to network %1$d Mbps diff --git a/src/com/android/settings/wifi/ConnectedAccessPointPreference.java b/src/com/android/settings/wifi/ConnectedAccessPointPreference.java index 514525caa6c..e9e1560cfbb 100644 --- a/src/com/android/settings/wifi/ConnectedAccessPointPreference.java +++ b/src/com/android/settings/wifi/ConnectedAccessPointPreference.java @@ -31,12 +31,31 @@ import com.android.settingslib.wifi.AccessPointPreference; public class ConnectedAccessPointPreference extends AccessPointPreference implements View.OnClickListener { + private final CaptivePortalStatus mCaptivePortalStatus; private OnGearClickListener mOnGearClickListener; + private boolean mCaptivePortalNetwork; public ConnectedAccessPointPreference(AccessPoint accessPoint, Context context, - UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks) { + UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks, + CaptivePortalStatus captivePortalStatus) { super(accessPoint, context, cache, iconResId, forSavedNetworks); - setWidgetLayoutResource(R.layout.preference_widget_gear_no_bg); + mCaptivePortalStatus = captivePortalStatus; + } + + @Override + protected int getWidgetLayoutResourceId() { + return R.layout.preference_widget_gear_optional_background; + } + + @Override + public void refresh() { + super.refresh(); + + mCaptivePortalNetwork = mCaptivePortalStatus.isCaptivePortalNetwork(); + setShowDivider(mCaptivePortalNetwork); + if (mCaptivePortalNetwork) { + setSummary(R.string.wifi_tap_to_sign_in); + } } public void setOnGearClickListener(OnGearClickListener l) { @@ -44,6 +63,18 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem notifyChanged(); } + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + + final View gear = holder.findViewById(R.id.settings_button); + 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); + } + @Override public void onClick(View v) { if (v.getId() == R.id.settings_button) { @@ -56,4 +87,8 @@ public class ConnectedAccessPointPreference extends AccessPointPreference implem public interface OnGearClickListener { void onGearClick(ConnectedAccessPointPreference p); } + + public interface CaptivePortalStatus { + boolean isCaptivePortalNetwork(); + } } diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 3972b851480..4f6701267fe 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -26,6 +26,8 @@ import android.content.Context; 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.wifi.WifiConfiguration; @@ -60,6 +62,7 @@ import com.android.settings.search.SearchIndexableRaw; import com.android.settings.widget.SummaryUpdater.OnSummaryChangeListener; import com.android.settings.widget.SwitchBarController; import com.android.settings.wifi.details.WifiNetworkDetailsFragment; +import com.android.settings.wrapper.ConnectivityManagerWrapper; import com.android.settings.wrapper.WifiManagerWrapper; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.wifi.AccessPoint; @@ -117,6 +120,7 @@ public class WifiSettings extends RestrictedSettingsFragment }; protected WifiManager mWifiManager; + private ConnectivityManager mConnectivityManager; private WifiManager.ActionListener mConnectListener; private WifiManager.ActionListener mSaveListener; private WifiManager.ActionListener mForgetListener; @@ -238,6 +242,11 @@ public class WifiSettings extends RestrictedSettingsFragment getActivity(), this, getLifecycle(), true, true); mWifiManager = mWifiTracker.getManager(); + final Activity activity = getActivity(); + if (activity != null) { + mConnectivityManager = getActivity().getSystemService(ConnectivityManager.class); + } + mConnectListener = new WifiManager.ActionListener() { @Override public void onSuccess() { @@ -777,9 +786,11 @@ public class WifiSettings extends RestrictedSettingsFragment @NonNull private ConnectedAccessPointPreference createConnectedAccessPointPreference( - AccessPoint accessPoint) { + AccessPoint accessPoint, + ConnectedAccessPointPreference.CaptivePortalStatus captivePortalStatus) { return new ConnectedAccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache, - R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */); + R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */, + captivePortalStatus); } /** @@ -828,21 +839,30 @@ public class WifiSettings extends RestrictedSettingsFragment * {@link #mConnectedAccessPointPreferenceCategory}. */ private void addConnectedAccessPointPreference(AccessPoint connectedAp) { - final ConnectedAccessPointPreference pref = createConnectedAccessPointPreference( - connectedAp); + final ConnectedAccessPointPreference pref = + createConnectedAccessPointPreference( + connectedAp, this::isConnectedToCaptivePortalNetwork); - // Launch details page on click. - pref.setOnPreferenceClickListener(preference -> { - pref.getAccessPoint().saveWifiState(pref.getExtras()); + // Launch details page or captive portal on click. + pref.setOnPreferenceClickListener( + preference -> { + pref.getAccessPoint().saveWifiState(pref.getExtras()); + Network network = getConnectedWifiNetwork(); + if (isConnectedToCaptivePortalNetwork(network)) { + ConnectivityManagerWrapper connectivityManagerWrapper = + new ConnectivityManagerWrapper(mConnectivityManager); + connectivityManagerWrapper.startCaptivePortalApp(network); + } else { + launchNetworkDetailsFragment(pref); + } + return true; + }); - new SubSettingLauncher(getContext()) - .setTitle(pref.getTitle()) - .setDestination(WifiNetworkDetailsFragment.class.getName()) - .setArguments(pref.getExtras()) - .setSourceMetricsCategory(getMetricsCategory()) - .launch(); - return true; - }); + pref.setOnGearClickListener( + preference -> { + pref.getAccessPoint().saveWifiState(pref.getExtras()); + launchNetworkDetailsFragment(pref); + }); pref.refresh(); @@ -854,6 +874,43 @@ public class WifiSettings extends RestrictedSettingsFragment } } + private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) { + new SubSettingLauncher(getContext()) + .setTitle(pref.getTitle()) + .setDestination(WifiNetworkDetailsFragment.class.getName()) + .setArguments(pref.getExtras()) + .setSourceMetricsCategory(getMetricsCategory()) + .launch(); + } + + private boolean isConnectedToCaptivePortalNetwork() { + return isConnectedToCaptivePortalNetwork(getConnectedWifiNetwork()); + } + + private boolean isConnectedToCaptivePortalNetwork(Network network) { + if (mConnectivityManager == null || network == null) { + return false; + } + return WifiUtils.canSignIntoNetwork(mConnectivityManager.getNetworkCapabilities(network)); + } + + 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; + } + } + } + } + return null; + } + /** Removes all preferences and hide the {@link #mConnectedAccessPointPreferenceCategory}. */ private void removeConnectedAccessPointPreference() { mConnectedAccessPointPreferenceCategory.removeAll(); diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java index 34c86d17054..5ef66c046d3 100644 --- a/src/com/android/settings/wifi/WifiUtils.java +++ b/src/com/android/settings/wifi/WifiUtils.java @@ -16,11 +16,11 @@ package com.android.settings.wifi; -import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; +import android.net.NetworkCapabilities; import android.net.wifi.WifiConfiguration; import android.provider.Settings; import android.text.TextUtils; @@ -101,4 +101,10 @@ public class WifiUtils { Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; return isLockdownFeatureEnabled; } + + /** Returns true if the provided NetworkCapabilities indicate a captive portal network. */ + public static boolean canSignIntoNetwork(NetworkCapabilities capabilities) { + return (capabilities != null + && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)); + } } diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 4d9ad271007..e7f0fdd7c1f 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -511,8 +511,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController * Returns whether the user can sign into the network represented by this preference. */ private boolean canSignIntoNetwork() { - return mNetworkCapabilities != null && mNetworkCapabilities.hasCapability( - NET_CAPABILITY_CAPTIVE_PORTAL); + return WifiUtils.canSignIntoNetwork(mNetworkCapabilities); } /** diff --git a/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java index 8d1b8ac99cd..b9b29d27133 100644 --- a/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java @@ -32,6 +32,7 @@ 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; @@ -44,6 +45,8 @@ public class ConnectedAccessPointPreferenceTest { private View mView; @Mock private ConnectedAccessPointPreference.OnGearClickListener mOnGearClickListener; + @Mock + private ConnectedAccessPointPreference.CaptivePortalStatus mCaptivePortalStatus; private Context mContext; private ConnectedAccessPointPreference mConnectedAccessPointPreference; @@ -53,7 +56,7 @@ public class ConnectedAccessPointPreferenceTest { mContext = RuntimeEnvironment.application; mConnectedAccessPointPreference = new ConnectedAccessPointPreference(mAccessPoint, mContext, - null, 0 /* iconResId */, false /* forSavedNetworks */); + null, 0 /* iconResId */, false /* forSavedNetworks */, mCaptivePortalStatus); mConnectedAccessPointPreference.setOnGearClickListener(mOnGearClickListener); } @@ -73,9 +76,23 @@ public class ConnectedAccessPointPreferenceTest { verify(mOnGearClickListener, never()).onGearClick(mConnectedAccessPointPreference); } + @Test + public void testCaptivePortalStatus_isCaptivePortal_dividerDrawn() { + Mockito.when(mCaptivePortalStatus.isCaptivePortalNetwork()).thenReturn(true); + mConnectedAccessPointPreference.refresh(); + assertThat(mConnectedAccessPointPreference.shouldShowDivider()).isTrue(); + } + + @Test + public void testCaptivePortalStatus_isNotCaptivePortal_dividerNotDrawn() { + Mockito.when(mCaptivePortalStatus.isCaptivePortalNetwork()).thenReturn(false); + mConnectedAccessPointPreference.refresh(); + assertThat(mConnectedAccessPointPreference.shouldShowDivider()).isFalse(); + } + @Test public void testWidgetLayoutPreference() { assertThat(mConnectedAccessPointPreference.getWidgetLayoutResource()) - .isEqualTo(R.layout.preference_widget_gear_no_bg); + .isEqualTo(R.layout.preference_widget_gear_optional_background); } }