Merge "[Wi-Fi] Support disconnect button for connected Wi-Fi AP"
diff --git a/res/drawable/ic_settings_close.xml b/res/drawable/ic_settings_close.xml
index 058b4b5..141a2c3 100644
--- a/res/drawable/ic_settings_close.xml
+++ b/res/drawable/ic_settings_close.xml
@@ -18,7 +18,8 @@
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
-    android:viewportHeight="24">
+    android:viewportHeight="24"
+    android:tint="?android:attr/colorControlNormal">
   <path
       android:fillColor="#FF000000"
       android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41z"/>
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index 50927e3..5eed9e3 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -78,6 +78,8 @@
 import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
 import com.android.wifitrackerlib.WifiEntry.ConnectCallback.ConnectStatus;
 import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
+import com.android.wifitrackerlib.WifiEntry.DisconnectCallback;
+import com.android.wifitrackerlib.WifiEntry.DisconnectCallback.DisconnectStatus;
 import com.android.wifitrackerlib.WifiEntry.ForgetCallback;
 import com.android.wifitrackerlib.WifiEntry.ForgetCallback.ForgetStatus;
 import com.android.wifitrackerlib.WifiEntry.SignInCallback;
@@ -97,7 +99,8 @@
  */
 public class WifiDetailPreferenceController2 extends AbstractPreferenceController
         implements PreferenceControllerMixin, WifiDialog2Listener, LifecycleObserver, OnPause,
-        OnResume, WifiEntryCallback, ConnectCallback, ForgetCallback, SignInCallback {
+        OnResume, WifiEntryCallback, ConnectCallback, DisconnectCallback, ForgetCallback,
+        SignInCallback {
 
     private static final String TAG = "WifiDetailsPrefCtrl2";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -298,17 +301,15 @@
         setupEntityHeader(screen);
 
         mButtonsPref = ((ActionButtonsPreference) screen.findPreference(KEY_BUTTONS_PREF))
-                .setButton1Text(!mWifiEntry.isSaved()
-                        ? R.string.wifi_disconnect_button_text : R.string.forget)
+                .setButton1Text(R.string.forget)
                 .setButton1Icon(R.drawable.ic_settings_delete)
                 .setButton1OnClickListener(view -> forgetNetwork())
                 .setButton2Text(R.string.wifi_sign_in_button_text)
                 .setButton2Icon(R.drawable.ic_settings_sign_in)
                 .setButton2OnClickListener(view -> signIntoNetwork())
-                .setButton3Text(R.string.wifi_connect)
-                .setButton3Icon(R.drawable.ic_settings_wireless)
-                .setButton3OnClickListener(view -> connectNetwork())
-                .setButton3Enabled(true)
+                .setButton3Text(getConnectDisconnectButtonTextResource())
+                .setButton3Icon(getConnectDisconnectButtonIconResource())
+                .setButton3OnClickListener(view -> connectDisconnectNetwork())
                 .setButton4Text(R.string.share)
                 .setButton4Icon(R.drawable.ic_qrcode_24dp)
                 .setButton4OnClickListener(view -> shareNetwork());
@@ -587,29 +588,50 @@
     }
 
     private void refreshButtons() {
-        boolean canForgetNetwork = mWifiEntry.canForget();
-        boolean canSignIntoNetwork = canSignIntoNetwork();
-        boolean showConnectButton = mWifiEntry.canConnect()
-                || mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTING;
-        boolean canShareNetwork = canShareNetwork();
+        final boolean canForgetNetwork = mWifiEntry.canForget();
+        final boolean canSignIntoNetwork = canSignIntoNetwork();
+        final boolean canConnectDisconnectNetwork = mWifiEntry.canConnect()
+                || mWifiEntry.canDisconnect();
+        final boolean canShareNetwork = canShareNetwork();
 
         mButtonsPref.setButton1Visible(canForgetNetwork);
         mButtonsPref.setButton2Visible(canSignIntoNetwork);
-        mButtonsPref.setButton3Visible(showConnectButton);
-        if (showConnectButton) {
-            if (mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTING) {
-                mButtonsPref.setButton3Text(R.string.wifi_connecting).setButton3Enabled(false);
-            } else {
-                mButtonsPref.setButton3Text(R.string.wifi_connect).setButton3Enabled(true);
-            }
-        }
+        mButtonsPref.setButton3Visible(mWifiEntry.getLevel() != WifiEntry.WIFI_LEVEL_UNREACHABLE);
+        mButtonsPref.setButton3Enabled(canConnectDisconnectNetwork);
+        mButtonsPref.setButton3Text(getConnectDisconnectButtonTextResource());
+        mButtonsPref.setButton3Icon(getConnectDisconnectButtonIconResource());
         mButtonsPref.setButton4Visible(canShareNetwork);
         mButtonsPref.setVisible(canForgetNetwork
                 || canSignIntoNetwork
-                || showConnectButton
+                || canConnectDisconnectNetwork
                 || canShareNetwork);
     }
 
+    private int getConnectDisconnectButtonTextResource() {
+        switch (mWifiEntry.getConnectedState()) {
+            case WifiEntry.CONNECTED_STATE_DISCONNECTED:
+                return R.string.wifi_connect;
+            case WifiEntry.CONNECTED_STATE_CONNECTED:
+                return R.string.wifi_disconnect_button_text;
+            case WifiEntry.CONNECTED_STATE_CONNECTING:
+                return R.string.wifi_connecting;
+            default:
+                throw new IllegalStateException("Invalid WifiEntry connected state");
+        }
+    }
+
+    private int getConnectDisconnectButtonIconResource() {
+        switch (mWifiEntry.getConnectedState()) {
+            case WifiEntry.CONNECTED_STATE_DISCONNECTED:
+            case WifiEntry.CONNECTED_STATE_CONNECTING:
+                return R.drawable.ic_settings_wireless;
+            case WifiEntry.CONNECTED_STATE_CONNECTED:
+                return R.drawable.ic_settings_close;
+            default:
+                throw new IllegalStateException("Invalid WifiEntry connected state");
+        }
+    }
+
     private void refreshIpLayerInfo() {
         // Hide IP layer info if not a connected network.
         if (mWifiEntry.getConnectedState() != WifiEntry.CONNECTED_STATE_CONNECTED
@@ -813,8 +835,12 @@
     }
 
     @VisibleForTesting
-    void connectNetwork() {
-        mWifiEntry.connect(this);
+    void connectDisconnectNetwork() {
+        if (mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
+            mWifiEntry.connect(this);
+        } else {
+            mWifiEntry.disconnect(this);
+        }
     }
 
     private void refreshMacTitle() {
@@ -862,25 +888,17 @@
                     R.string.wifi_failed_connect_message,
                     Toast.LENGTH_SHORT).show();
         }
-        mButtonsPref.setButton3Text(R.string.wifi_connect)
-                .setButton3Icon(R.drawable.ic_settings_wireless)
-                .setButton3Enabled(true)
-                .setButton3Visible(true);
     }
 
-    // TODO: Add disconnect button.
     /**
      * Result of the disconnect request indicated by the DISCONNECT_STATUS constants.
      */
-    //@Override
-    //public void onDisconnectResult(@DisconnectStatus int status) {
-    //    if (status != DisconnectCallback.DISCONNECT_STATUS_SUCCESS) {
-    //        Log.e(TAG, "Disconnect Wi-Fi network failed");
-    //    }
-    //
-    //    updateNetworkInfo();
-    //    refreshPage();
-    //}
+    @Override
+    public void onDisconnectResult(@DisconnectStatus int status) {
+        if (status != DisconnectCallback.DISCONNECT_STATUS_SUCCESS) {
+            Log.e(TAG, "Disconnect Wi-Fi network failed");
+        }
+    }
 
     /**
      * Result of the forget request indicated by the FORGET_STATUS constants.
diff --git a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
index e60303e..b48cd3c 100644
--- a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
@@ -1303,22 +1303,35 @@
     }
 
     @Test
-    public void testConnectButton_shouldInvisibleForConnectNetwork() {
+    public void testDisconnectButton_connectedNetwork_shouldVisible() {
         setUpForConnectedNetwork();
+        when(mMockWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_MAX);
 
         displayAndResume();
 
-        verify(mMockButtonsPref, times(1)).setButton3Visible(false);
+        verify(mMockButtonsPref).setButton3Visible(true);
+        verify(mMockButtonsPref).setButton3Text(R.string.wifi_disconnect);
     }
 
     @Test
-    public void testConnectButton_shouldVisibleForDisconnectNetwork() {
+    public void testConnectButton_disconnectedNetwork_shouldVisibleIfReachable() {
         setUpForDisconnectedNetwork();
+        when(mMockWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_MAX);
 
         displayAndResume();
 
-        verify(mMockButtonsPref, times(1)).setButton3Visible(true);
-        verify(mMockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect);
+        verify(mMockButtonsPref).setButton3Visible(true);
+        verify(mMockButtonsPref).setButton3Text(R.string.wifi_connect);
+    }
+
+    @Test
+    public void testConnectButton_disconnectedNetwork_shouldInvisibleIfUnreachable() {
+        setUpForDisconnectedNetwork();
+        when(mMockWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
+
+        displayAndResume();
+
+        verify(mMockButtonsPref).setButton3Visible(false);
     }
 
     private void setUpForToast() {
@@ -1337,11 +1350,11 @@
 
         displayAndResume();
 
-        // check connect button exist
-        verifyConnectBtnSetUpAsVisible(inOrder);
+        // check connect button enabled
+        verifyConnectBtnSetUpAsEnabled(inOrder);
 
         // click connect button
-        mController.connectNetwork();
+        mController.connectDisconnectNetwork();
 
         // check display button as connecting
         verify(mMockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
@@ -1352,7 +1365,7 @@
 
         // check connect button invisible, be init as default state and toast success message
         verifyConnectBtnBeInitAsDefault(inOrder);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Visible(false);
+        inOrder.verify(mMockButtonsPref).setButton3Enabled(false);
         assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
                 mContext.getString(R.string.wifi_connected_to_message, label));
     }
@@ -1368,11 +1381,11 @@
 
         displayAndResume();
 
-        // check connect button exist
-        verifyConnectBtnSetUpAsVisible(inOrder);
+        // check connect button enabled
+        verifyConnectBtnSetUpAsEnabled(inOrder);
 
         // click connect button
-        mController.connectNetwork();
+        mController.connectDisconnectNetwork();
 
         // check display button as connecting
         verify(mMockWifiManager, times(1)).connect(anyInt(), connectListenerCaptor.capture());
@@ -1383,26 +1396,26 @@
 
         // check connect button visible, be init as default and toast failed message
         verifyConnectBtnBeInitAsDefault(inOrder);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Visible(true);
+        inOrder.verify(mMockButtonsPref).setButton3Enabled(true);
         assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
                 mContext.getString(R.string.wifi_failed_connect_message));
     }
 
-    private void verifyConnectBtnSetUpAsVisible(InOrder inOrder) {
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Icon(R.drawable.ic_settings_wireless);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Visible(true);
+    private void verifyConnectBtnSetUpAsEnabled(InOrder inOrder) {
+        inOrder.verify(mMockButtonsPref).setButton3Text(R.string.wifi_connect);
+        inOrder.verify(mMockButtonsPref).setButton3Icon(R.drawable.ic_settings_wireless);
+        inOrder.verify(mMockButtonsPref).setButton3Enabled(true);
     }
 
     private void verifyConnectBtnSetUpAsConnecting(InOrder inOrder) {
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Text(R.string.wifi_connecting);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Enabled(false);
+        inOrder.verify(mMockButtonsPref).setButton3Text(R.string.wifi_connecting);
+        inOrder.verify(mMockButtonsPref).setButton3Enabled(false);
     }
 
     private void verifyConnectBtnBeInitAsDefault(InOrder inOrder) {
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Icon(R.drawable.ic_settings_wireless);
-        inOrder.verify(mMockButtonsPref, times(1)).setButton3Enabled(true);
+        inOrder.verify(mMockButtonsPref).setButton3Text(R.string.wifi_connect);
+        inOrder.verify(mMockButtonsPref).setButton3Icon(R.drawable.ic_settings_wireless);
+        inOrder.verify(mMockButtonsPref).setButton3Enabled(true);
     }
 
     @Test