Restrict WiFi network connection

- Use StandardWifiEntry#canConnect() to determine if the network should
  be disabled or not.

- Use StandardWifiEntry#getSummary() to retrieve the restriction message.

- Disabled WiFi network if it cannot connect.

- If WiFi network is connected or saved network, leave it enabled to
disconnect or configure.

- See the result screenshot in b/203168943#comment11

Bug: 203168938
Bug: 203168943
Test: manual test
make RunSettingsRoboTests ROBOTEST_FILTER=LongPressWifiEntryPreferenceTest
make RunSettingsRoboTests ROBOTEST_FILTER=NetworkProviderSettingsTest

Merged-In: I04aafaa5b383598a0f87eea15d06b38bbc662b9e
Change-Id: I04aafaa5b383598a0f87eea15d06b38bbc662b9e
(cherry picked from commit f86bdc9c696990c818ecc6ab3704176052cf2972)
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index ea864ea..faf5010 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -628,15 +628,7 @@
         }
 
         if (preference instanceof LongPressWifiEntryPreference) {
-            final WifiEntry selectedEntry =
-                    ((LongPressWifiEntryPreference) preference).getWifiEntry();
-
-            if (selectedEntry.shouldEditBeforeConnect()) {
-                launchConfigNewNetworkFragment(selectedEntry);
-                return true;
-            }
-
-            connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */);
+            onSelectedWifiPreferenceClick((LongPressWifiEntryPreference) preference);
         } else if (preference == mAddWifiNetworkPreference) {
             onAddNetworkPressed();
         } else {
@@ -645,6 +637,25 @@
         return true;
     }
 
+    @VisibleForTesting
+    void onSelectedWifiPreferenceClick(LongPressWifiEntryPreference preference) {
+        final WifiEntry selectedEntry = preference.getWifiEntry();
+
+        if (selectedEntry.shouldEditBeforeConnect()) {
+            launchConfigNewNetworkFragment(selectedEntry);
+            return;
+        }
+
+        if (selectedEntry.canConnect()) {
+            connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */);
+            return;
+        }
+
+        if (selectedEntry.isSaved()) {
+            launchNetworkDetailsFragment(preference);
+        }
+    }
+
     private void launchWifiDppConfiguratorActivity(WifiEntry wifiEntry) {
         final Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntentOrNull(getContext(),
                 mWifiManager, wifiEntry);
@@ -984,7 +995,8 @@
         return new FirstWifiEntryPreference(getPrefContext(), wifiEntry, this);
     }
 
-    private void launchNetworkDetailsFragment(LongPressWifiEntryPreference pref) {
+    @VisibleForTesting
+    void launchNetworkDetailsFragment(LongPressWifiEntryPreference pref) {
         final WifiEntry wifiEntry = pref.getWifiEntry();
         final Context context = getContext();
         final CharSequence title =
@@ -1253,7 +1265,8 @@
         }
     }
 
-    private void launchConfigNewNetworkFragment(WifiEntry wifiEntry) {
+    @VisibleForTesting
+    void launchConfigNewNetworkFragment(WifiEntry wifiEntry) {
         final Bundle bundle = new Bundle();
         bundle.putString(WifiNetworkDetailsFragment.KEY_CHOSEN_WIFIENTRY_KEY,
                 wifiEntry.getKey());
diff --git a/src/com/android/settings/wifi/LongPressWifiEntryPreference.java b/src/com/android/settings/wifi/LongPressWifiEntryPreference.java
index bee92cf..c509f1a 100644
--- a/src/com/android/settings/wifi/LongPressWifiEntryPreference.java
+++ b/src/com/android/settings/wifi/LongPressWifiEntryPreference.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
 import androidx.preference.PreferenceViewHolder;
 
@@ -43,4 +44,23 @@
             view.itemView.setLongClickable(true);
         }
     }
+
+    @Override
+    public void refresh() {
+        super.refresh();
+        setEnabled(shouldEnabled());
+    }
+
+    @VisibleForTesting
+    boolean shouldEnabled() {
+        WifiEntry wifiEntry = getWifiEntry();
+        if (wifiEntry == null) return false;
+
+        boolean enabled = wifiEntry.canConnect();
+        // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure.
+        if (!enabled && (wifiEntry.canDisconnect() || wifiEntry.isSaved())) {
+            enabled = true;
+        }
+        return enabled;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index 9994876..3182cd0 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -108,6 +108,8 @@
     @Mock
     private WifiPickerTracker mMockWifiPickerTracker;
     @Mock
+    private WifiEntry mWifiEntry;
+    @Mock
     private PreferenceManager mPreferenceManager;
     @Mock
     private InternetResetHelper mInternetResetHelper;
@@ -309,14 +311,13 @@
         when(activity.getApplicationContext()).thenReturn(mContext);
         when(mNetworkProviderSettings.getActivity()).thenReturn(activity);
 
-        final WifiEntry wifiEntry = mock(WifiEntry.class);
-        when(wifiEntry.canDisconnect()).thenReturn(true);
-        when(wifiEntry.canForget()).thenReturn(true);
-        when(wifiEntry.isSaved()).thenReturn(true);
-        when(wifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+        when(mWifiEntry.canForget()).thenReturn(true);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
 
         final LongPressWifiEntryPreference connectedWifiEntryPreference =
-                mNetworkProviderSettings.createLongPressWifiEntryPreference(wifiEntry);
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
         final View view = mock(View.class);
         when(view.getTag()).thenReturn(connectedWifiEntryPreference);
 
@@ -334,15 +335,14 @@
         when(activity.getApplicationContext()).thenReturn(mContext);
         when(mNetworkProviderSettings.getActivity()).thenReturn(activity);
 
-        final WifiEntry wifiEntry = mock(WifiEntry.class);
-        when(wifiEntry.canDisconnect()).thenReturn(true);
-        when(wifiEntry.canShare()).thenReturn(true);
-        when(wifiEntry.canForget()).thenReturn(true);
-        when(wifiEntry.isSaved()).thenReturn(true);
-        when(wifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+        when(mWifiEntry.canShare()).thenReturn(true);
+        when(mWifiEntry.canForget()).thenReturn(true);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
 
         final LongPressWifiEntryPreference connectedWifiEntryPreference =
-            mNetworkProviderSettings.createLongPressWifiEntryPreference(wifiEntry);
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
         final View view = mock(View.class);
         when(view.getTag()).thenReturn(connectedWifiEntryPreference);
 
@@ -358,15 +358,14 @@
         when(activity.getApplicationContext()).thenReturn(mContext);
         when(mNetworkProviderSettings.getActivity()).thenReturn(activity);
 
-        final WifiEntry wifiEntry = mock(WifiEntry.class);
-        when(wifiEntry.canDisconnect()).thenReturn(true);
-        when(wifiEntry.canShare()).thenReturn(false);
-        when(wifiEntry.canForget()).thenReturn(true);
-        when(wifiEntry.isSaved()).thenReturn(true);
-        when(wifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+        when(mWifiEntry.canShare()).thenReturn(false);
+        when(mWifiEntry.canForget()).thenReturn(true);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
 
         final LongPressWifiEntryPreference connectedWifiEntryPreference =
-            mNetworkProviderSettings.createLongPressWifiEntryPreference(wifiEntry);
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
         final View view = mock(View.class);
         when(view.getTag()).thenReturn(connectedWifiEntryPreference);
 
@@ -390,10 +389,9 @@
                 FAKE_URI_STRING);
         doNothing().when(mNetworkProviderSettings).startActivityForResult(any(Intent.class),
                 anyInt());
-        final WifiEntry mockWifiEntry = mock(WifiEntry.class);
-        when(mockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
+        when(mWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
 
-        mNetworkProviderSettings.openSubscriptionHelpPage(mockWifiEntry);
+        mNetworkProviderSettings.openSubscriptionHelpPage(mWifiEntry);
 
         verify(mNetworkProviderSettings, times(1)).startActivityForResult(any(), anyInt());
     }
@@ -461,12 +459,11 @@
     }
 
     private WifiDialog2 createWifiDialog2(int mode, WifiConfiguration config) {
-        final WifiEntry wifiEntry = mock(WifiEntry.class);
-        when(wifiEntry.canConnect()).thenReturn(true);
+        when(mWifiEntry.canConnect()).thenReturn(true);
         final WifiConfigController2 controller = mock(WifiConfigController2.class);
         when(controller.getConfig()).thenReturn(config);
-        final WifiDialog2 wifiDialog2 =  spy(WifiDialog2.createModal(mContext, null /* listener */,
-                wifiEntry, mode));
+        final WifiDialog2 wifiDialog2 = spy(WifiDialog2.createModal(mContext, null /* listener */,
+                mWifiEntry, mode));
         when(wifiDialog2.getController()).thenReturn(controller);
         return wifiDialog2;
     }
@@ -537,20 +534,18 @@
 
     @Test
     public void createConnectedWifiEntryPreference_internetWiFi_createConnectedPreference() {
-        final WifiEntry wifiEntry = mock(WifiEntry.class);
         doReturn(InternetUpdater.INTERNET_WIFI).when(mInternetUpdater).getInternetType();
 
-        final Preference p = mNetworkProviderSettings.createConnectedWifiEntryPreference(wifiEntry);
+        Preference p = mNetworkProviderSettings.createConnectedWifiEntryPreference(mWifiEntry);
 
         assertThat(p instanceof ConnectedWifiEntryPreference).isTrue();
     }
 
     @Test
     public void createConnectedWifiEntryPreference_internetCellular_createFirstWifiPreference() {
-        final WifiEntry wifiEntry = mock(WifiEntry.class);
         doReturn(InternetUpdater.INTERNET_CELLULAR).when(mInternetUpdater).getInternetType();
 
-        final Preference p = mNetworkProviderSettings.createConnectedWifiEntryPreference(wifiEntry);
+        Preference p = mNetworkProviderSettings.createConnectedWifiEntryPreference(mWifiEntry);
 
         assertThat(p instanceof NetworkProviderSettings.FirstWifiEntryPreference).isTrue();
     }
@@ -635,6 +630,42 @@
     }
 
     @Test
+    public void onSelectedWifiPreferenceClick_shouldEditBeforeConnect_launchNewNetworkFragment() {
+        when(mWifiEntry.shouldEditBeforeConnect()).thenReturn(true);
+        final LongPressWifiEntryPreference preference =
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
+        doNothing().when(mNetworkProviderSettings).launchConfigNewNetworkFragment(mWifiEntry);
+
+        mNetworkProviderSettings.onSelectedWifiPreferenceClick(preference);
+
+        verify(mNetworkProviderSettings).launchConfigNewNetworkFragment(mWifiEntry);
+    }
+
+    @Test
+    public void onSelectedWifiPreferenceClick_canConnect_connectWifi() {
+        when(mWifiEntry.canConnect()).thenReturn(true);
+        final LongPressWifiEntryPreference preference =
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
+        doNothing().when(mNetworkProviderSettings).connect(any(), anyBoolean(), anyBoolean());
+
+        mNetworkProviderSettings.onSelectedWifiPreferenceClick(preference);
+
+        verify(mNetworkProviderSettings).connect(any(), anyBoolean(), anyBoolean());
+    }
+
+    @Test
+    public void onSelectedWifiPreferenceClick_isSaved_launchNetworkDetailsFragment() {
+        when(mWifiEntry.isSaved()).thenReturn(true);
+        final LongPressWifiEntryPreference preference =
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
+        doNothing().when(mNetworkProviderSettings).launchNetworkDetailsFragment(preference);
+
+        mNetworkProviderSettings.onSelectedWifiPreferenceClick(preference);
+
+        verify(mNetworkProviderSettings).launchNetworkDetailsFragment(preference);
+    }
+
+    @Test
     @Config(shadows = ShadowPreferenceFragmentCompat.class)
     public void onStop_shouldRemoveCallbacks() {
         View fragmentView = mock(View.class);
diff --git a/tests/robotests/src/com/android/settings/wifi/LongPressWifiEntryPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/LongPressWifiEntryPreferenceTest.java
new file mode 100644
index 0000000..fd7cc89
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/LongPressWifiEntryPreferenceTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.fragment.app.Fragment;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongPressWifiEntryPreferenceTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Spy
+    Context mContext = ApplicationProvider.getApplicationContext();
+    @Mock
+    Fragment mFragment;
+    @Mock
+    WifiEntry mWifiEntry;
+
+    LongPressWifiEntryPreference mPreference;
+
+    @Before
+    public void setUp() {
+        // Fake mWifiEntry as an available Wi-Fi network, and it's not connected.
+        when(mWifiEntry.canConnect()).thenReturn(true);
+        when(mWifiEntry.canDisconnect()).thenReturn(false);
+        when(mWifiEntry.isSaved()).thenReturn(false);
+
+        mPreference = new LongPressWifiEntryPreference(mContext, mWifiEntry, mFragment);
+    }
+
+    @Test
+    public void shouldEnabled_canConnect_returnTrue() {
+        // Fake mWifiEntry as an available Wi-Fi network, and it's not connected.
+        when(mWifiEntry.canConnect()).thenReturn(true);
+
+        assertThat(mPreference.shouldEnabled()).isTrue();
+    }
+
+    @Test
+    public void shouldEnabled_canNotConnect_returnFalse() {
+        // Fake mWifiEntry as a restricted Wi-Fi network, and cannot connect.
+        when(mWifiEntry.canConnect()).thenReturn(false);
+
+        assertThat(mPreference.shouldEnabled()).isFalse();
+    }
+
+    @Test
+    public void shouldEnabled_canNotConnectButCanDisconnect_returnTrue() {
+        // Fake mWifiEntry as a connected Wi-Fi network without saved configuration.
+        when(mWifiEntry.canConnect()).thenReturn(false);
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+
+        assertThat(mPreference.shouldEnabled()).isTrue();
+    }
+
+    @Test
+    public void shouldEnabled_canNotConnectButIsSaved_returnTrue() {
+        // Fake mWifiEntry as a saved Wi-Fi network
+        when(mWifiEntry.canConnect()).thenReturn(false);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+
+        assertThat(mPreference.shouldEnabled()).isTrue();
+    }
+
+    @Test
+    public void shouldEnabled_canNotConnectButCanDisconnectAndIsSaved_returnTrue() {
+        // Fake mWifiEntry as a connected Wi-Fi network
+        when(mWifiEntry.canConnect()).thenReturn(false);
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+
+        assertThat(mPreference.shouldEnabled()).isTrue();
+    }
+}