diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8e62c452d35..3b53d32e79b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2705,10 +2705,8 @@ - implements WifiTracker.WifiListener { @@ -84,7 +84,7 @@ public class WifiScanWorker extends SliceBackgroundWorker implement protected void onSliceUnpinned() { mWifiTracker.onStop(); unregisterNetworkCallback(); - clearClickedWifi(); + clearClickedWifiOnSliceUnpinned(); } @Override @@ -157,6 +157,14 @@ public class WifiScanWorker extends SliceBackgroundWorker implement return !TextUtils.isEmpty(ssid) && TextUtils.equals(ssid, sClickedWifiSsid); } + protected void clearClickedWifiOnSliceUnpinned() { + clearClickedWifi(); + } + + protected boolean isSessionValid() { + return true; + } + public void registerNetworkCallback(Network wifiNetwork) { if (wifiNetwork == null) { return; @@ -224,12 +232,13 @@ public class WifiScanWorker extends SliceBackgroundWorker implement // Automatically start captive portal if (!prevIsCaptivePortal && mIsCaptivePortal - && isWifiClicked(mWifiTracker.getManager().getConnectionInfo())) { + && isWifiClicked(mWifiTracker.getManager().getConnectionInfo()) + && isSessionValid()) { final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) .putExtra(ConnectivityManager.EXTRA_NETWORK, network) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // Starting activity in the system process needs to specify a user - mContext.startActivityAsUser(intent, UserHandle.CURRENT); + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + // Sending a broadcast in the system process needs to specify a user + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); } } diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java index a687b935393..9be98988d6b 100644 --- a/src/com/android/settings/wifi/slice/WifiSlice.java +++ b/src/com/android/settings/wifi/slice/WifiSlice.java @@ -94,6 +94,7 @@ public class WifiSlice implements CustomSliceable { final boolean isWifiEnabled = isWifiEnabled(); ListBuilder listBuilder = getHeaderRow(isWifiEnabled); if (!isWifiEnabled) { + WifiScanWorker.clearClickedWifi(); return listBuilder.build(); } @@ -133,6 +134,17 @@ public class WifiSlice implements CustomSliceable { return listBuilder.build(); } + private void handleNetworkCallback(WifiScanWorker worker, boolean isFirstApActive) { + if (worker == null) { + return; + } + if (isFirstApActive) { + worker.registerNetworkCallback(mWifiManager.getCurrentNetwork()); + } else { + worker.unregisterNetworkCallback(); + } + } + private ListBuilder getHeaderRow(boolean isWifiEnabled) { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_wireless); @@ -155,17 +167,6 @@ public class WifiSlice implements CustomSliceable { .setPrimaryAction(primarySliceAction)); } - private void handleNetworkCallback(WifiScanWorker worker, boolean isFirstApActive) { - if (worker == null) { - return; - } - if (isFirstApActive) { - worker.registerNetworkCallback(mWifiManager.getCurrentNetwork()); - } else { - worker.unregisterNetworkCallback(); - } - } - private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) { final boolean isCaptivePortal = accessPoint.isActive() && isCaptivePortal(); final CharSequence title = accessPoint.getTitle(); @@ -175,9 +176,8 @@ public class WifiSlice implements CustomSliceable { .setTitleItem(levelIcon, ListBuilder.ICON_IMAGE) .setTitle(title) .setSubtitle(summary) - .setPrimaryAction(SliceAction.createDeeplink( - getAccessPointAction(accessPoint, isCaptivePortal), levelIcon, - ListBuilder.ICON_IMAGE, title)); + .setPrimaryAction(getAccessPointAction(accessPoint, isCaptivePortal, levelIcon, + title)); if (isCaptivePortal) { rowBuilder.addEndItem(getCaptivePortalEndAction(accessPoint, title)); @@ -203,7 +203,7 @@ public class WifiSlice implements CustomSliceable { final Drawable d = mContext.getDrawable( com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel())); - @ColorInt int color; + final @ColorInt int color; if (accessPoint.isActive()) { final NetworkInfo.State state = accessPoint.getNetworkInfo().getState(); if (state == NetworkInfo.State.CONNECTED) { @@ -232,36 +232,54 @@ public class WifiSlice implements CustomSliceable { } private SliceAction getCaptivePortalEndAction(AccessPoint accessPoint, CharSequence title) { - return SliceAction.createDeeplink( - getAccessPointAction(accessPoint, false /* isCaptivePortal */), - IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent), - ListBuilder.ICON_IMAGE, title); + return getAccessPointAction(accessPoint, false /* isCaptivePortal */, + IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent), title); } - private PendingIntent getAccessPointAction(AccessPoint accessPoint, boolean isCaptivePortal) { + private SliceAction getAccessPointAction(AccessPoint accessPoint, boolean isCaptivePortal, + IconCompat icon, CharSequence title) { + final int requestCode = accessPoint.hashCode(); + if (isCaptivePortal) { + final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) + .putExtra(ConnectivityManager.EXTRA_NETWORK, mWifiManager.getCurrentNetwork()); + return getBroadcastAction(requestCode, intent, icon, title); + } + final Bundle extras = new Bundle(); accessPoint.saveWifiState(extras); - Intent intent; - if (isCaptivePortal) { - intent = new Intent(mContext, ConnectToWifiHandler.class); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK, mWifiManager.getCurrentNetwork()); - } else if (accessPoint.isActive()) { - intent = new SubSettingLauncher(mContext) + if (accessPoint.isActive()) { + final Intent intent = new SubSettingLauncher(mContext) .setTitleRes(R.string.pref_title_network_details) .setDestination(WifiNetworkDetailsFragment.class.getName()) .setArguments(extras) .setSourceMetricsCategory(SettingsEnums.WIFI) .toIntent(); + return getActivityAction(requestCode, intent, icon, title); } else if (WifiUtils.getConnectingType(accessPoint) != WifiUtils.CONNECT_TYPE_OTHERS) { - intent = new Intent(mContext, ConnectToWifiHandler.class); - intent.putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras); + final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) + .putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras); + return getBroadcastAction(requestCode, intent, icon, title); } else { - intent = new Intent(mContext, WifiDialogActivity.class); - intent.putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras); + final Intent intent = new Intent(mContext, WifiDialogActivity.class) + .putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras); + return getActivityAction(requestCode, intent, icon, title); } - return PendingIntent.getActivity(mContext, accessPoint.hashCode() /* requestCode */, - intent, 0 /* flags */); + } + + private SliceAction getActivityAction(int requestCode, Intent intent, IconCompat icon, + CharSequence title) { + final PendingIntent pi = PendingIntent.getActivity(mContext, requestCode, intent, + 0 /* flags */); + return SliceAction.createDeeplink(pi, icon, ListBuilder.ICON_IMAGE, title); + } + + private SliceAction getBroadcastAction(int requestCode, Intent intent, IconCompat icon, + CharSequence title) { + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + final PendingIntent pi = PendingIntent.getBroadcast(mContext, requestCode, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + return SliceAction.create(pi, icon, ListBuilder.ICON_IMAGE, title); } private ListBuilder.RowBuilder getLoadingRow(CharSequence placeholder) { @@ -277,7 +295,7 @@ public class WifiSlice implements CustomSliceable { .setSubtitle(title); } - protected boolean isCaptivePortal() { + private boolean isCaptivePortal() { final NetworkCapabilities nc = mConnectivityManager.getNetworkCapabilities( mWifiManager.getCurrentNetwork()); return WifiUtils.canSignIntoNetwork(nc); diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java index cea8365190e..1eb78183daa 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.Context; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiManager; @@ -35,8 +36,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @@ -44,6 +45,7 @@ import org.robolectric.annotation.Config; public class ConnectToWifiHandlerTest { private static final String AP_SSID = "\"ap\""; + private Context mContext; private ConnectToWifiHandler mHandler; private WifiConfiguration mWifiConfig; @Mock @@ -53,7 +55,8 @@ public class ConnectToWifiHandlerTest { public void setUp() { MockitoAnnotations.initMocks(this); - mHandler = Robolectric.setupActivity(ConnectToWifiHandler.class); + mContext = RuntimeEnvironment.application; + mHandler = new ConnectToWifiHandler(); mWifiConfig = new WifiConfiguration(); mWifiConfig.SSID = AP_SSID; doReturn(mWifiConfig).when(mAccessPoint).getConfig(); @@ -64,7 +67,7 @@ public class ConnectToWifiHandlerTest { when(mAccessPoint.isSaved()).thenReturn(false); when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_NONE); - mHandler.connect(mAccessPoint); + mHandler.connect(mContext, mAccessPoint); assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID); } @@ -74,7 +77,7 @@ public class ConnectToWifiHandlerTest { when(mAccessPoint.isSaved()).thenReturn(false); when(mAccessPoint.isOsuProvider()).thenReturn(true); - mHandler.connect(mAccessPoint); + mHandler.connect(mContext, mAccessPoint); verify(mAccessPoint).startOsuProvisioning(any(WifiManager.ActionListener.class)); } @@ -85,7 +88,7 @@ public class ConnectToWifiHandlerTest { when(mAccessPoint.isSaved()).thenReturn(false); when(mAccessPoint.isPasspoint()).thenReturn(true); - mHandler.connect(mAccessPoint); + mHandler.connect(mContext, mAccessPoint); assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID); } @@ -98,7 +101,7 @@ public class ConnectToWifiHandlerTest { status.setHasEverConnected(true); mWifiConfig.setNetworkSelectionStatus(status); - mHandler.connect(mAccessPoint); + mHandler.connect(mContext, mAccessPoint); assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID); } @@ -108,7 +111,7 @@ public class ConnectToWifiHandlerTest { when(mAccessPoint.isSaved()).thenReturn(false); when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_PSK); - mHandler.connect(mAccessPoint); + mHandler.connect(mContext, mAccessPoint); assertThat(ShadowWifiManager.get().savedWifiConfig).isNull(); } diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiScanWorkerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiScanWorkerTest.java new file mode 100644 index 00000000000..0e525207caa --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiScanWorkerTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 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.slice; + +import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.wifi.WifiManager; +import android.os.UserHandle; + +import com.android.settings.testutils.shadow.ShadowWifiManager; + +import org.junit.After; +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; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowWifiManager.class, + WifiScanWorkerTest.ShadowWifiTracker.class, +}) +public class ContextualWifiScanWorkerTest { + + private Context mContext; + private WifiManager mWifiManager; + private ConnectivityManager mConnectivityManager; + private ContextualWifiScanWorker mWifiScanWorker; + private ConnectToWifiHandler mConnectToWifiHandler; + + @Before + public void setUp() { + mContext = spy(RuntimeEnvironment.application); + mWifiManager = mContext.getSystemService(WifiManager.class); + mWifiManager.setWifiEnabled(true); + + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mWifiScanWorker = new ContextualWifiScanWorker(mContext, CONTEXTUAL_WIFI_SLICE_URI); + mConnectToWifiHandler = new ConnectToWifiHandler(); + } + + @After + public void tearDown() { + mWifiScanWorker.clearClickedWifi(); + } + + @Test + public void NetworkCallback_onCapabilitiesChanged_sliceIsUnpinned_shouldSendBroadcast() { + final Intent intent = WifiScanWorkerTest.getIntentWithAccessPoint("ap1"); + WifiScanWorkerTest.setConnectionInfoSSID("ap1"); + final Network network = mConnectivityManager.getActiveNetwork(); + mWifiScanWorker.registerNetworkCallback(network); + final NetworkCallback callback = mWifiScanWorker.mNetworkCallback; + + mWifiScanWorker.onSlicePinned(); + mConnectToWifiHandler.onReceive(mContext, intent); + mWifiScanWorker.onSliceUnpinned(); + callback.onCapabilitiesChanged(network, + WifiSliceTest.makeCaptivePortalNetworkCapabilities()); + + verify(mContext).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + } + + @Test + public void NetworkCallback_onCapabilitiesChanged_newSession_shouldNotSendBroadcast() { + final Intent intent = WifiScanWorkerTest.getIntentWithAccessPoint("ap1"); + WifiScanWorkerTest.setConnectionInfoSSID("ap1"); + final Network network = mConnectivityManager.getActiveNetwork(); + mWifiScanWorker.registerNetworkCallback(network); + + mConnectToWifiHandler.onReceive(mContext, intent); + ContextualWifiScanWorker.newVisibleUiSession(); + mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, + WifiSliceTest.makeCaptivePortalNetworkCapabilities()); + + verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java index b246e9a6603..1c84eb6a66e 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java @@ -17,6 +17,7 @@ package com.android.settings.wifi.slice; import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI; +import static com.android.settings.wifi.WifiDialogActivity.KEY_ACCESS_POINT_STATE; import static com.google.common.truth.Truth.assertThat; @@ -42,9 +43,6 @@ import android.net.wifi.WifiSsid; import android.os.Bundle; import android.os.UserHandle; -import androidx.slice.SliceProvider; -import androidx.slice.widget.SliceLiveData; - import com.android.settings.testutils.shadow.ShadowWifiManager; import com.android.settingslib.wifi.AccessPoint; import com.android.settingslib.wifi.WifiTracker; @@ -57,7 +55,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -85,14 +82,11 @@ public class WifiScanWorkerTest { mResolver = mock(ContentResolver.class); doReturn(mResolver).when(mContext).getContentResolver(); mWifiManager = mContext.getSystemService(WifiManager.class); - - // Set-up specs for SliceMetadata. - SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); mWifiManager.setWifiEnabled(true); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mWifiScanWorker = new WifiScanWorker(mContext, WIFI_SLICE_URI); - mConnectToWifiHandler = Robolectric.setupActivity(ConnectToWifiHandler.class); + mConnectToWifiHandler = new ConnectToWifiHandler(); } @After @@ -147,42 +141,36 @@ public class WifiScanWorkerTest { verify(mResolver).notifyChange(WIFI_SLICE_URI, null); } - private void setConnectionInfoSSID(String ssid) { - final WifiInfo wifiInfo = new WifiInfo(); - wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(ssid)); - ShadowWifiManager.get().setConnectionInfo(wifiInfo); - } - @Test - public void NetworkCallback_onCapabilitiesChanged_isClickedWifi_shouldStartActivity() { - final AccessPoint accessPoint = createAccessPoint("ap1"); + public void NetworkCallback_onCapabilitiesChanged_isClickedWifi_shouldSendBroadcast() { + final Intent intent = getIntentWithAccessPoint("ap1"); setConnectionInfoSSID("ap1"); final Network network = mConnectivityManager.getActiveNetwork(); mWifiScanWorker.registerNetworkCallback(network); - mConnectToWifiHandler.connect(accessPoint); + mConnectToWifiHandler.onReceive(mContext, intent); mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - verify(mContext).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + verify(mContext).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); } @Test - public void NetworkCallback_onCapabilitiesChanged_isNotClickedWifi_shouldNotStartActivity() { - final AccessPoint accessPoint = createAccessPoint("ap1"); + public void NetworkCallback_onCapabilitiesChanged_isNotClickedWifi_shouldNotSendBroadcast() { + final Intent intent = getIntentWithAccessPoint("ap1"); setConnectionInfoSSID("ap2"); final Network network = mConnectivityManager.getActiveNetwork(); mWifiScanWorker.registerNetworkCallback(network); - mConnectToWifiHandler.connect(accessPoint); + mConnectToWifiHandler.onReceive(mContext, intent); mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - verify(mContext, never()).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); } @Test - public void NetworkCallback_onCapabilitiesChanged_neverClickWifi_shouldNotStartActivity() { + public void NetworkCallback_onCapabilitiesChanged_neverClickWifi_shouldNotSendBroadcast() { setConnectionInfoSSID("ap1"); final Network network = mConnectivityManager.getActiveNetwork(); mWifiScanWorker.registerNetworkCallback(network); @@ -190,24 +178,36 @@ public class WifiScanWorkerTest { mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - verify(mContext, never()).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); } @Test - public void NetworkCallback_onCapabilitiesChanged_sliceIsUnpinned_shouldNotStartActivity() { - final AccessPoint accessPoint = createAccessPoint("ap1"); + public void NetworkCallback_onCapabilitiesChanged_sliceIsUnpinned_shouldNotSendBroadcast() { + final Intent intent = getIntentWithAccessPoint("ap1"); setConnectionInfoSSID("ap1"); final Network network = mConnectivityManager.getActiveNetwork(); mWifiScanWorker.registerNetworkCallback(network); final NetworkCallback callback = mWifiScanWorker.mNetworkCallback; mWifiScanWorker.onSlicePinned(); - mConnectToWifiHandler.connect(accessPoint); + mConnectToWifiHandler.onReceive(mContext, intent); mWifiScanWorker.onSliceUnpinned(); callback.onCapabilitiesChanged(network, WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - verify(mContext, never()).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + } + + static Intent getIntentWithAccessPoint(String ssid) { + final Bundle savedState = new Bundle(); + savedState.putString("key_ssid", ssid); + return new Intent().putExtra(KEY_ACCESS_POINT_STATE, savedState); + } + + static void setConnectionInfoSSID(String ssid) { + final WifiInfo wifiInfo = new WifiInfo(); + wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(ssid)); + ShadowWifiManager.get().setConnectionInfo(wifiInfo); } private AccessPoint createAccessPoint(String ssid, DetailedState detailedState) { @@ -223,10 +223,6 @@ public class WifiScanWorkerTest { return createAccessPoint("ap", detailedState); } - private AccessPoint createAccessPoint(String ssid) { - return createAccessPoint(ssid, DetailedState.DISCONNECTED); - } - @Implements(WifiTracker.class) public static class ShadowWifiTracker { @Implementation