Merge "[Provider Model] Hide Connectivity Subsystems when recovering" into sc-dev
diff --git a/src/com/android/settings/network/InternetResetHelper.java b/src/com/android/settings/network/InternetResetHelper.java
new file mode 100644
index 0000000..d6c5476
--- /dev/null
+++ b/src/com/android/settings/network/InternetResetHelper.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2021 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.network;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+
+import com.android.settingslib.connectivity.ConnectivitySubsystemsRecoveryManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class to restart connectivity for all requested subsystems.
+ */
+public class InternetResetHelper implements LifecycleObserver,
+        ConnectivitySubsystemsRecoveryManager.RecoveryStatusCallback {
+
+    protected static final String TAG = "InternetResetHelper";
+    public static final long RESTART_TIMEOUT_MS = 15_000; // 15 seconds
+
+    protected final Context mContext;
+    protected Preference mResettingPreference;
+    protected NetworkMobileProviderController mMobileNetworkController;
+    protected Preference mWifiTogglePreferences;
+    protected List<PreferenceCategory> mWifiNetworkPreferences =
+            new ArrayList<PreferenceCategory>();
+
+    protected final WifiManager mWifiManager;
+    protected final IntentFilter mWifiStateFilter;
+    protected final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+        @Override
+        @WorkerThread
+        public void onReceive(Context context, Intent intent) {
+            if (intent != null && TextUtils.equals(intent.getAction(),
+                    WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                updateWifiStateChange();
+            }
+        }
+    };
+
+    protected ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+    protected HandlerThread mWorkerThread;
+    protected boolean mIsRecoveryReady;
+    protected boolean mIsWifiReady;
+    protected HandlerInjector mHandlerInjector;
+    protected final Runnable mResumeRunnable = () -> {
+        resumePreferences();
+    };
+    protected final Runnable mTimeoutRunnable = () -> {
+        mIsRecoveryReady = true;
+        mIsWifiReady = true;
+        resumePreferences();
+    };
+
+    public InternetResetHelper(Context context, Lifecycle lifecycle) {
+        mContext = context;
+        mHandlerInjector = new HandlerInjector(context);
+        mWifiManager = mContext.getSystemService(WifiManager.class);
+        mWifiStateFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+
+        mWorkerThread = new HandlerThread(TAG
+                + "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
+                Process.THREAD_PRIORITY_BACKGROUND);
+        mWorkerThread.start();
+        mConnectivitySubsystemsRecoveryManager = new ConnectivitySubsystemsRecoveryManager(
+                mContext, mWorkerThread.getThreadHandler());
+
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
+    }
+
+    /** @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) */
+    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+    public void onResume() {
+        mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
+    }
+
+    /** @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) */
+    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
+    public void onPause() {
+        mContext.unregisterReceiver(mWifiStateReceiver);
+    }
+
+    /** @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) */
+    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+    public void onDestroy() {
+        mHandlerInjector.removeCallbacks(mResumeRunnable);
+        mHandlerInjector.removeCallbacks(mTimeoutRunnable);
+        mWorkerThread.quit();
+    }
+
+    @Override
+    @WorkerThread
+    public void onSubsystemRestartOperationBegin() {
+        Log.d(TAG, "The connectivity subsystem is starting for recovery.");
+    }
+
+    @Override
+    @WorkerThread
+    public void onSubsystemRestartOperationEnd() {
+        Log.d(TAG, "The connectivity subsystem is done for recovery.");
+        if (!mIsRecoveryReady) {
+            mIsRecoveryReady = true;
+            mHandlerInjector.postDelayed(mResumeRunnable, 0 /* delayMillis */);
+        }
+    }
+
+    @VisibleForTesting
+    @WorkerThread
+    protected void updateWifiStateChange() {
+        if (!mIsWifiReady && mWifiManager.isWifiEnabled()) {
+            Log.d(TAG, "The Wi-Fi subsystem is done for recovery.");
+            mIsWifiReady = true;
+            mHandlerInjector.postDelayed(mResumeRunnable, 0 /* delayMillis */);
+        }
+    }
+
+    /**
+     * Sets the resetting preference.
+     */
+    @UiThread
+    public void setResettingPreference(Preference preference) {
+        mResettingPreference = preference;
+    }
+
+    /**
+     * Sets the mobile network controller.
+     */
+    @UiThread
+    public void setMobileNetworkController(NetworkMobileProviderController controller) {
+        mMobileNetworkController = controller;
+    }
+
+    /**
+     * Sets the Wi-Fi toggle preference.
+     */
+    @UiThread
+    public void setWifiTogglePreference(Preference preference) {
+        mWifiTogglePreferences = preference;
+    }
+
+    /**
+     * Adds the Wi-Fi network preference.
+     */
+    @UiThread
+    public void addWifiNetworkPreference(PreferenceCategory preference) {
+        if (preference != null) {
+            mWifiNetworkPreferences.add(preference);
+        }
+    }
+
+    @UiThread
+    protected void suspendPreferences() {
+        Log.d(TAG, "Suspend the subsystem preferences");
+        if (mMobileNetworkController != null) {
+            mMobileNetworkController.hidePreference(true /* hide */, true /* immediately */);
+        }
+        if (mWifiTogglePreferences != null) {
+            mWifiTogglePreferences.setVisible(false);
+        }
+        for (PreferenceCategory pref : mWifiNetworkPreferences) {
+            pref.removeAll();
+            pref.setVisible(false);
+        }
+        if (mResettingPreference != null) {
+            mResettingPreference.setVisible(true);
+        }
+    }
+
+    @UiThread
+    protected void resumePreferences() {
+        if (mIsRecoveryReady && mMobileNetworkController != null) {
+            Log.d(TAG, "Resume the Mobile Network controller");
+            mMobileNetworkController.hidePreference(false /* hide */, false /* immediately */);
+        }
+        if (mIsWifiReady && mWifiTogglePreferences != null) {
+            Log.d(TAG, "Resume the Wi-Fi preferences");
+            mWifiTogglePreferences.setVisible(true);
+            for (PreferenceCategory pref : mWifiNetworkPreferences) {
+                pref.setVisible(true);
+            }
+        }
+        if (mIsRecoveryReady && mIsWifiReady) {
+            mHandlerInjector.removeCallbacks(mTimeoutRunnable);
+            if (mResettingPreference != null) {
+                Log.d(TAG, "Resume the Resetting preference");
+                mResettingPreference.setVisible(false);
+            }
+        }
+    }
+
+    /**
+     * Restart connectivity for all requested subsystems.
+     */
+    @UiThread
+    public void restart() {
+        if (!mConnectivitySubsystemsRecoveryManager.isRecoveryAvailable()) {
+            Log.e(TAG, "The connectivity subsystem is not available to restart.");
+            return;
+        }
+
+        Log.d(TAG, "The connectivity subsystem is restarting for recovery.");
+        suspendPreferences();
+        mIsRecoveryReady = false;
+        mIsWifiReady = !mWifiManager.isWifiEnabled();
+        mHandlerInjector.postDelayed(mTimeoutRunnable, RESTART_TIMEOUT_MS);
+        mConnectivitySubsystemsRecoveryManager.triggerSubsystemRestart(null /* reason */, this);
+    }
+
+    /**
+     * Wrapper for testing compatibility.
+     */
+    @VisibleForTesting
+    static class HandlerInjector {
+        protected final Handler mHandler;
+
+        HandlerInjector(Context context) {
+            mHandler = context.getMainThreadHandler();
+        }
+
+        public void postDelayed(Runnable runnable, long delayMillis) {
+            mHandler.postDelayed(runnable, delayMillis);
+        }
+
+        public void removeCallbacks(Runnable runnable) {
+            mHandler.removeCallbacks(runnable);
+        }
+    }
+}
diff --git a/src/com/android/settings/network/NetworkMobileProviderController.java b/src/com/android/settings/network/NetworkMobileProviderController.java
index 5dc6c0d..33123b3 100644
--- a/src/com/android/settings/network/NetworkMobileProviderController.java
+++ b/src/com/android/settings/network/NetworkMobileProviderController.java
@@ -50,6 +50,7 @@
     private SubscriptionsPreferenceController mSubscriptionsController;
 
     private int mOriginalExpandedChildrenCount;
+    private boolean mHide;
 
     public NetworkMobileProviderController(Context context, String key) {
         super(context, key);
@@ -94,7 +95,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        if (mSubscriptionsController == null) {
+        if (mHide || mSubscriptionsController == null) {
             return CONDITIONALLY_UNAVAILABLE;
         }
         return mSubscriptionsController.isAvailable() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
@@ -122,4 +123,14 @@
             mSubscriptionsController.setWifiPickerTrackerHelper(helper);
         }
     }
+
+    /**
+     * Hides the preference.
+     */
+    public void hidePreference(boolean hide, boolean immediately) {
+        mHide = hide;
+        if (immediately) {
+            mPreferenceCategory.setVisible(hide ? false : isAvailable());
+        }
+    }
 }
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index 88e732a..f6e7917 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -32,9 +32,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.PowerManager;
-import android.os.Process;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -78,7 +76,6 @@
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.settingslib.connectivity.ConnectivitySubsystemsRecoveryManager;
 import com.android.settingslib.search.Indexable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.utils.ThreadUtils;
@@ -101,7 +98,6 @@
 public class NetworkProviderSettings extends RestrictedSettingsFragment
         implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
         WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener,
-        ConnectivitySubsystemsRecoveryManager.RecoveryStatusCallback,
         AirplaneModeEnabler.OnAirplaneModeChangedListener, InternetUpdater.InternetChangeListener {
 
     public static final String ACTION_NETWORK_PROVIDER_SETTINGS =
@@ -192,9 +188,7 @@
     private WifiManager.ActionListener mSaveListener;
     private WifiManager.ActionListener mForgetListener;
 
-    @VisibleForTesting
-    protected ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
-    private HandlerThread mRecoveryThread;
+    protected InternetResetHelper mInternetResetHelper;
 
     /**
      * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is necessary to
@@ -1274,39 +1268,17 @@
     }
 
     private void fixConnectivity() {
-        if (mConnectivitySubsystemsRecoveryManager == null) {
-            mRecoveryThread = new HandlerThread(TAG
-                    + "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
-                    Process.THREAD_PRIORITY_BACKGROUND);
-            mRecoveryThread.start();
-            mConnectivitySubsystemsRecoveryManager = new ConnectivitySubsystemsRecoveryManager(
-                    getContext(), mRecoveryThread.getThreadHandler());
+        if (mInternetResetHelper == null) {
+            mInternetResetHelper = new InternetResetHelper(getContext(), getLifecycle());
+            mInternetResetHelper.setResettingPreference(mResetInternetPreference);
+            mInternetResetHelper.setMobileNetworkController(mNetworkMobileProviderController);
+            mInternetResetHelper.setWifiTogglePreference(
+                    findPreference(WifiSwitchPreferenceController.KEY));
+            mInternetResetHelper.addWifiNetworkPreference(mConnectedWifiEntryPreferenceCategory);
+            mInternetResetHelper.addWifiNetworkPreference(mFirstWifiEntryPreferenceCategory);
+            mInternetResetHelper.addWifiNetworkPreference(mWifiEntryPreferenceCategory);
         }
-        if (mConnectivitySubsystemsRecoveryManager.isRecoveryAvailable()) {
-            mConnectivitySubsystemsRecoveryManager.triggerSubsystemRestart(null /* reason */, this);
-        }
-    }
-
-    /**
-     * Callback for the internet recovery started.
-     */
-    public void onSubsystemRestartOperationBegin() {
-        if (mResetInternetPreference != null) {
-            mResetInternetPreference.setVisible(true);
-        }
-        updateAirplaneModeMsgPreference(false /* visible */);
-    }
-
-    /**
-     * Callback for the internet recovery ended.
-     */
-    public void onSubsystemRestartOperationEnd() {
-        if (mResetInternetPreference != null) {
-            mResetInternetPreference.setVisible(false);
-        }
-        if (mAirplaneModeEnabler.isAirplaneModeOn()) {
-            updateAirplaneModeMsgPreference(true /* visible */);
-        }
+        mInternetResetHelper.restart();
     }
 
     /**
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index 9951449..47cd87c 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -66,7 +66,6 @@
 import com.android.settings.wifi.ConnectedWifiEntryPreference;
 import com.android.settings.wifi.WifiConfigController2;
 import com.android.settings.wifi.WifiDialog2;
-import com.android.settingslib.connectivity.ConnectivitySubsystemsRecoveryManager;
 import com.android.settingslib.widget.LayoutPreference;
 import com.android.settingslib.wifi.LongPressWifiEntryPreference;
 import com.android.wifitrackerlib.WifiEntry;
@@ -105,7 +104,7 @@
     @Mock
     private PreferenceManager mPreferenceManager;
     @Mock
-    private ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+    private InternetResetHelper mInternetResetHelper;
     @Mock
     private Preference mAirplaneModeMsgPreference;
     @Mock
@@ -439,49 +438,14 @@
     }
 
     @Test
-    public void onOptionsItemSelected_fixConnectivity_triggerSubsystemRestart() {
-        doReturn(true).when(mConnectivitySubsystemsRecoveryManager).isRecoveryAvailable();
-        mNetworkProviderSettings.mConnectivitySubsystemsRecoveryManager =
-                mConnectivitySubsystemsRecoveryManager;
+    public void onOptionsItemSelected_fixConnectivity_restartInternet() {
+        mNetworkProviderSettings.mInternetResetHelper = mInternetResetHelper;
         doReturn(false).when(mNetworkProviderSettings).isPhoneOnCall();
         doReturn(NetworkProviderSettings.MENU_FIX_CONNECTIVITY).when(mMenuItem).getItemId();
 
         mNetworkProviderSettings.onOptionsItemSelected(mMenuItem);
 
-        verify(mConnectivitySubsystemsRecoveryManager).triggerSubsystemRestart(any(), any());
-    }
-
-    @Test
-    public void onOptionsItemSelected_fixConnectivityOnCall_neverTriggerSubsystemRestart() {
-        doReturn(true).when(mConnectivitySubsystemsRecoveryManager).isRecoveryAvailable();
-        mNetworkProviderSettings.mConnectivitySubsystemsRecoveryManager =
-                mConnectivitySubsystemsRecoveryManager;
-        doReturn(true).when(mNetworkProviderSettings).isPhoneOnCall();
-        doNothing().when(mNetworkProviderSettings).showResetInternetDialog();
-        doReturn(NetworkProviderSettings.MENU_FIX_CONNECTIVITY).when(mMenuItem).getItemId();
-
-        mNetworkProviderSettings.onOptionsItemSelected(mMenuItem);
-
-        verify(mConnectivitySubsystemsRecoveryManager, never()).triggerSubsystemRestart(any(),
-                any());
-    }
-
-    @Test
-    public void onSubsystemRestartOperationBegin_showResetInternetHideApmMsg() {
-        mNetworkProviderSettings.onSubsystemRestartOperationBegin();
-
-        verify(mResetInternetPreference).setVisible(true);
-        verify(mAirplaneModeMsgPreference).setVisible(false);
-    }
-
-    @Test
-    public void onSubsystemRestartOperationEnd_showApmMsgHideResetInternet() {
-        doReturn(true).when(mAirplaneModeEnabler).isAirplaneModeOn();
-
-        mNetworkProviderSettings.onSubsystemRestartOperationEnd();
-
-        verify(mResetInternetPreference).setVisible(false);
-        verify(mAirplaneModeMsgPreference).setVisible(true);
+        verify(mInternetResetHelper).restart();
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/network/InternetResetHelperTest.java b/tests/unit/src/com/android/settings/network/InternetResetHelperTest.java
new file mode 100644
index 0000000..00ca8e1
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/InternetResetHelperTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2021 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.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.connectivity.ConnectivitySubsystemsRecoveryManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class InternetResetHelperTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    public HandlerThread mWorkerThread;
+    @Mock
+    public ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+    @Mock
+    public NetworkMobileProviderController mMobileNetworkController;
+
+    private Context mContext;
+    private InternetResetHelper mInternetResetHelper;
+    private Preference mResettingPreference;
+    private Preference mWifiTogglePreferences;
+    private PreferenceCategory mConnectedWifiEntryPreferences;
+    private PreferenceCategory mWifiEntryPreferences;
+
+    private FakeHandlerInjector mFakeHandlerInjector;
+
+    private static class FakeHandlerInjector extends InternetResetHelper.HandlerInjector {
+
+        private Runnable mRunnable;
+
+        FakeHandlerInjector(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void postDelayed(Runnable runnable, long delayMillis) {
+            mRunnable = runnable;
+        }
+
+        public Runnable getRunnable() {
+            return mRunnable;
+        }
+    }
+
+    @Before
+    public void setUp() {
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        mResettingPreference = new Preference(mContext);
+        mWifiTogglePreferences = new Preference(mContext);
+        mConnectedWifiEntryPreferences = spy(new PreferenceCategory(mContext));
+        mWifiEntryPreferences = spy(new PreferenceCategory(mContext));
+
+        final Lifecycle lifecycle = mock(Lifecycle.class);
+        mInternetResetHelper = new InternetResetHelper(mContext, lifecycle);
+        mInternetResetHelper.mWorkerThread = mWorkerThread;
+        mFakeHandlerInjector = new FakeHandlerInjector(mContext);
+        mInternetResetHelper.mHandlerInjector = mFakeHandlerInjector;
+        mInternetResetHelper.mConnectivitySubsystemsRecoveryManager =
+                mConnectivitySubsystemsRecoveryManager;
+        mInternetResetHelper.setResettingPreference(mResettingPreference);
+        mInternetResetHelper.setMobileNetworkController(mMobileNetworkController);
+        mInternetResetHelper.setWifiTogglePreference(mWifiTogglePreferences);
+        mInternetResetHelper.addWifiNetworkPreference(mConnectedWifiEntryPreferences);
+        mInternetResetHelper.addWifiNetworkPreference(mWifiEntryPreferences);
+    }
+
+    @Test
+    public void onResume_registerReceiver() {
+        mInternetResetHelper.onResume();
+
+        verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+    }
+
+    @Test
+    public void onPause_unregisterReceiver() {
+        mInternetResetHelper.onResume();
+
+        mInternetResetHelper.onPause();
+
+        verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
+    }
+
+    @Test
+    public void onDestroy_quitWorkerThread() {
+        mInternetResetHelper.onDestroy();
+
+        verify(mWorkerThread).quit();
+    }
+
+    @Test
+    public void onSubsystemRestartOperationEnd_recoveryIsNotReady_postResumeRunnable() {
+        mInternetResetHelper.mIsRecoveryReady = false;
+
+        mInternetResetHelper.onSubsystemRestartOperationEnd();
+
+        assertThat(mInternetResetHelper.mIsRecoveryReady).isTrue();
+        assertThat(mFakeHandlerInjector.getRunnable())
+                .isEqualTo(mInternetResetHelper.mResumeRunnable);
+    }
+
+    @Test
+    public void onSubsystemRestartOperationEnd_recoveryIsReady_doNothing() {
+        mInternetResetHelper.mIsRecoveryReady = true;
+
+        mInternetResetHelper.onSubsystemRestartOperationEnd();
+
+        assertThat(mFakeHandlerInjector.getRunnable()).isNull();
+    }
+
+    @Test
+    public void updateWifiStateChange_wifiIsNotReadyAndWifiDisabled_doNothing() {
+        mInternetResetHelper.mIsWifiReady = false;
+        when(mWifiManager.isWifiEnabled()).thenReturn(false);
+
+        mInternetResetHelper.updateWifiStateChange();
+
+        assertThat(mInternetResetHelper.mIsWifiReady).isFalse();
+        assertThat(mFakeHandlerInjector.getRunnable()).isNull();
+    }
+
+    @Test
+    public void updateWifiStateChange_wifiIsNotReadyAndWifiEnabled_postResumeRunnable() {
+        mInternetResetHelper.mIsWifiReady = false;
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+
+        mInternetResetHelper.updateWifiStateChange();
+
+        assertThat(mInternetResetHelper.mIsWifiReady).isTrue();
+        assertThat(mFakeHandlerInjector.getRunnable())
+                .isEqualTo(mInternetResetHelper.mResumeRunnable);
+    }
+
+    @Test
+    public void updateWifiStateChange_wifiIsReady_doNothing() {
+        mInternetResetHelper.mIsWifiReady = true;
+
+        mInternetResetHelper.updateWifiStateChange();
+
+        assertThat(mInternetResetHelper.mIsWifiReady).isTrue();
+        assertThat(mFakeHandlerInjector.getRunnable()).isNull();
+    }
+
+    @Test
+    public void suspendPreferences_shouldShowResettingHideSubSys() {
+        mInternetResetHelper.suspendPreferences();
+
+        // Show resetting preference
+        assertThat(mResettingPreference.isVisible()).isTrue();
+        // Hide subsystem preferences
+        verify(mMobileNetworkController).hidePreference(true /* hide */, true /* immediately*/);
+        assertThat(mWifiTogglePreferences.isVisible()).isFalse();
+        verify(mConnectedWifiEntryPreferences).removeAll();
+        assertThat(mConnectedWifiEntryPreferences.isVisible()).isFalse();
+        verify(mWifiEntryPreferences).removeAll();
+        assertThat(mWifiEntryPreferences.isVisible()).isFalse();
+    }
+
+    @Test
+    public void resumePreferences_onlyRecoveryReady_shouldShowSubSysHideResetting() {
+        mInternetResetHelper.suspendPreferences();
+        mInternetResetHelper.mIsRecoveryReady = true;
+        mInternetResetHelper.mIsWifiReady = false;
+
+        mInternetResetHelper.resumePreferences();
+
+        // Show resetting preference
+        assertThat(mResettingPreference.isVisible()).isTrue();
+        // Show Mobile Network controller
+        verify(mMobileNetworkController).hidePreference(false /* hide */, false /* immediately*/);
+        // Hide Wi-Fi preferences
+        assertThat(mWifiTogglePreferences.isVisible()).isFalse();
+        assertThat(mConnectedWifiEntryPreferences.isVisible()).isFalse();
+        assertThat(mWifiEntryPreferences.isVisible()).isFalse();
+    }
+
+    @Test
+    public void resumePreferences_onlyWifiReady_shouldShowSubSysHideResetting() {
+        mInternetResetHelper.suspendPreferences();
+        mInternetResetHelper.mIsRecoveryReady = false;
+        mInternetResetHelper.mIsWifiReady = true;
+
+        mInternetResetHelper.resumePreferences();
+
+        // Show resetting preference
+        assertThat(mResettingPreference.isVisible()).isTrue();
+        // Show Wi-Fi preferences
+        assertThat(mWifiTogglePreferences.isVisible()).isTrue();
+        assertThat(mConnectedWifiEntryPreferences.isVisible()).isTrue();
+        assertThat(mWifiEntryPreferences.isVisible()).isTrue();
+        // Hide Mobile Network controller
+        verify(mMobileNetworkController, never())
+                .hidePreference(false /* hide */, false /* immediately*/);
+    }
+
+    @Test
+    public void resumePreferences_allReady_shouldShowSubSysHideResetting() {
+        mInternetResetHelper.suspendPreferences();
+        mInternetResetHelper.mIsRecoveryReady = true;
+        mInternetResetHelper.mIsWifiReady = true;
+        mInternetResetHelper.resumePreferences();
+
+        // Show subsystem preferences
+        verify(mMobileNetworkController).hidePreference(false, false);
+        assertThat(mWifiTogglePreferences.isVisible()).isTrue();
+        assertThat(mConnectedWifiEntryPreferences.isVisible()).isTrue();
+        assertThat(mWifiEntryPreferences.isVisible()).isTrue();
+        // Hide resetting preference
+        assertThat(mResettingPreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void restart_recoveryNotAvailable_shouldDoTriggerSubsystemRestart() {
+        when(mConnectivitySubsystemsRecoveryManager.isRecoveryAvailable()).thenReturn(false);
+
+        mInternetResetHelper.restart();
+
+        verify(mConnectivitySubsystemsRecoveryManager, never())
+                .triggerSubsystemRestart(any(), any());
+    }
+
+    @Test
+    public void restart_recoveryAvailable_triggerSubsystemRestart() {
+        when(mConnectivitySubsystemsRecoveryManager.isRecoveryAvailable()).thenReturn(true);
+
+        mInternetResetHelper.restart();
+
+        assertThat(mFakeHandlerInjector.getRunnable())
+                .isEqualTo(mInternetResetHelper.mTimeoutRunnable);
+        verify(mConnectivitySubsystemsRecoveryManager).triggerSubsystemRestart(any(), any());
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java
index 31c68da..b626bff 100644
--- a/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java
@@ -173,6 +173,44 @@
         assertEquals(mPreferenceScreen.getInitialExpandedChildrenCount(), Integer.MAX_VALUE);
     }
 
+    @Test
+    public void hidePreference_hidePreferenceTrue_preferenceIsNotVisible() {
+        when(mSubscriptionsController.isAvailable()).thenReturn(true);
+        setupNetworkMobileProviderController();
+        mPreferenceCategory.setVisible(true);
+
+        mNetworkMobileProviderController.hidePreference(true /* hide */, true /* immediately*/);
+
+        assertThat(mPreferenceCategory.isVisible()).isFalse();
+    }
+
+    @Test
+    public void hidePreference_hidePreferenceFalse_preferenceIsVisible() {
+        when(mSubscriptionsController.isAvailable()).thenReturn(true);
+        setupNetworkMobileProviderController();
+
+        mNetworkMobileProviderController.hidePreference(false /* hide */, true /* immediately*/);
+
+        assertThat(mPreferenceCategory.isVisible()).isTrue();
+    }
+
+    @Test
+    public void hidePreference_hidePreferenceFalse_preferenceIsNotVisibleImmediately() {
+        when(mSubscriptionsController.isAvailable()).thenReturn(true);
+        setupNetworkMobileProviderController();
+        mPreferenceCategory.setVisible(false);
+
+        mNetworkMobileProviderController.hidePreference(false /* hide */, false /* immediately*/);
+
+        // The preference is not visible immediately.
+        assertThat(mPreferenceCategory.isVisible()).isFalse();
+
+        mNetworkMobileProviderController.displayPreference(mPreferenceScreen);
+
+        // The preference is visible after displayPreference() updated.
+        assertThat(mPreferenceCategory.isVisible()).isTrue();
+    }
+
     private void setupNetworkMobileProviderController() {
         mNetworkMobileProviderController.init(mLifecycle);
         mNetworkMobileProviderController.displayPreference(mPreferenceScreen);