diff --git a/src/com/android/settings/network/BluetoothTetherPreferenceController.java b/src/com/android/settings/network/BluetoothTetherPreferenceController.java new file mode 100644 index 00000000000..10849a0d235 --- /dev/null +++ b/src/com/android/settings/network/BluetoothTetherPreferenceController.java @@ -0,0 +1,141 @@ +/* + * 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.network; + +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.text.TextUtils; +import android.util.Log; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.settingslib.core.AbstractPreferenceController; + +import com.google.common.annotations.VisibleForTesting; + +/** + * This controller helps to manage the switch state and visibility of bluetooth tether switch + * preference. It stores preference value when preference changed. + * TODO(b/147272749): Extend BasePreferenceController.java instead. + */ +public final class BluetoothTetherPreferenceController extends AbstractPreferenceController + implements LifecycleObserver, Preference.OnPreferenceChangeListener { + + private static final String TAG = "BluetoothTetherPreferenceController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + @VisibleForTesting + static final String PREF_KEY = "enable_bluetooth_tethering"; + private final ConnectivityManager mCm; + private int mBluetoothState; + private Preference mPreference; + private final SharedPreferences mSharedPreferences; + + public BluetoothTetherPreferenceController(Context context, Lifecycle lifecycle) { + super(context); + mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mSharedPreferences = + context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + public void onStart() { + mBluetoothState = BluetoothAdapter.getDefaultAdapter().getState(); + mContext.registerReceiver(mBluetoothChangeReceiver, + new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + mContext.unregisterReceiver(mBluetoothChangeReceiver); + } + + @Override + public boolean isAvailable() { + final String[] bluetoothRegexs = mCm.getTetherableBluetoothRegexs(); + return bluetoothRegexs != null && bluetoothRegexs.length > 0; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(PREF_KEY); + if (mPreference != null && mPreference instanceof SwitchPreference) { + ((SwitchPreference) mPreference) + .setChecked(mSharedPreferences.getBoolean(PREF_KEY, false)); + } + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + switch (mBluetoothState) { + case BluetoothAdapter.STATE_ON: + case BluetoothAdapter.STATE_OFF: + // fall through. + case BluetoothAdapter.ERROR: + preference.setEnabled(true); + break; + case BluetoothAdapter.STATE_TURNING_OFF: + case BluetoothAdapter.STATE_TURNING_ON: + // fall through. + default: + preference.setEnabled(false); + } + } + + @Override + public String getPreferenceKey() { + return PREF_KEY; + } + + @VisibleForTesting + final BroadcastReceiver mBluetoothChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, intent.getAction())) { + mBluetoothState = + intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + updateState(mPreference); + } + } + }; + + + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + if (DEBUG) { + Log.d(TAG, "preference changing to " + o); + } + final SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(PREF_KEY, (Boolean) o); + editor.apply(); + return true; + } +} diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java index 9106aa17fcb..6c6c95968d1 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -32,11 +32,11 @@ import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; +import android.util.Log; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; -import androidx.preference.PreferenceManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.datausage.DataSaverBackend; @@ -52,13 +52,20 @@ import java.util.concurrent.atomic.AtomicReference; */ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListener, - DataSaverBackend.Listener, LifecycleObserver { + DataSaverBackend.Listener, LifecycleObserver, + SharedPreferences.OnSharedPreferenceChangeListener { + + private static final String TAG = "TetherEnabler"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + public static final String SHARED_PREF = "tether_options"; + @VisibleForTesting - static final String WIFI_TETHER_KEY = "enable_wifi_tethering"; + static final String WIFI_TETHER_KEY = WifiTetherDisablePreferenceController.PREF_KEY; @VisibleForTesting - static final String USB_TETHER_KEY = "enable_usb_tethering"; + static final String USB_TETHER_KEY = UsbTetherPreferenceController.PREF_KEY; @VisibleForTesting - static final String BLUETOOTH_TETHER_KEY = "enable_bluetooth_tethering"; + static final String BLUETOOTH_TETHER_KEY = BluetoothTetherPreferenceController.PREF_KEY; private final SwitchWidgetController mSwitchWidgetController; private final WifiManager mWifiManager; @@ -76,7 +83,6 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang public void onTetheringFailed() { super.onTetheringFailed(); mSwitchWidgetController.setChecked(false); - setSwitchWidgetEnabled(true); } }; private final AtomicReference mBluetoothPan; @@ -84,12 +90,12 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang private boolean mBluetoothEnableForTether; private final BluetoothAdapter mBluetoothAdapter; - TetherEnabler(Context context, SwitchWidgetController switchWidgetController, + public TetherEnabler(Context context, SwitchWidgetController switchWidgetController, AtomicReference bluetoothPan) { mContext = context; mSwitchWidgetController = switchWidgetController; mDataSaverBackend = new DataSaverBackend(context); - mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); + mSharedPreferences = context.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE); mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -110,6 +116,16 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang setSwitchWidgetEnabled(true); } + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + public void onResume() { + mSharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + public void onPause() { + mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + } + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onStop() { mDataSaverBackend.remListener(this); @@ -148,19 +164,16 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang @VisibleForTesting void stopTether() { - setSwitchWidgetEnabled(false); - // Wi-Fi tether is selected by default + // Wi-Fi tether is selected by default. if (mSharedPreferences.getBoolean(WIFI_TETHER_KEY, true)) { mConnectivityManager.stopTethering(TETHERING_WIFI); } - // USB tether is not selected by default if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) { mConnectivityManager.stopTethering(TETHERING_USB); } - // Bluetooth tether is not selected by default if (mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)) { mConnectivityManager.stopTethering(TETHERING_BLUETOOTH); } @@ -168,19 +181,16 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang @VisibleForTesting void startTether() { - setSwitchWidgetEnabled(false); - // Wi-Fi tether is selected by default + // Wi-Fi tether is selected by default. if (mSharedPreferences.getBoolean(WIFI_TETHER_KEY, true)) { startTethering(TETHERING_WIFI); } - // USB tether is not selected by default if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) { startTethering(TETHERING_USB); } - // Bluetooth tether is not selected by default if (mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)) { startTethering(TETHERING_BLUETOOTH); } @@ -188,18 +198,24 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang @VisibleForTesting void startTethering(int choice) { + if (choice == TETHERING_WIFI && mWifiManager.isWifiApEnabled()) { + if (DEBUG) { + Log.d(TAG, "Wifi tether already active!"); + } + return; + } + if (choice == TETHERING_BLUETOOTH) { - // Turn on Bluetooth first. if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + if (DEBUG) { + Log.d(TAG, "Turn on bluetooth first."); + } mBluetoothEnableForTether = true; mBluetoothAdapter.enable(); return; } - } else if (choice == TETHERING_WIFI && mWifiManager.isWifiApEnabled()) { - return; } - mConnectivityManager.startTethering(choice, true /* showProvisioningUi */, mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); } @@ -213,24 +229,21 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang ConnectivityManager.EXTRA_ACTIVE_TETHER); mSwitchWidgetController.setChecked( isTethering(active.toArray(new String[active.size()]))); - setSwitchWidgetEnabled(true); } else if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, action)) { - if (mBluetoothEnableForTether) { - switch (intent - .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) { - case BluetoothAdapter.STATE_ON: + switch (intent + .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) { + case BluetoothAdapter.STATE_ON: + if (mBluetoothEnableForTether) { startTethering(TETHERING_BLUETOOTH); - mBluetoothEnableForTether = false; - break; - - case BluetoothAdapter.STATE_OFF: - case BluetoothAdapter.ERROR: - mBluetoothEnableForTether = false; - break; - - default: - // ignore transition states - } + } + // Fall through. + case BluetoothAdapter.STATE_OFF: + // Fall through. + case BluetoothAdapter.ERROR: + mBluetoothEnableForTether = false; + break; + default: + // ignore transition states } } } @@ -251,4 +264,30 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) { // we don't care, since we just want to read the value } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (!mSwitchWidgetController.isChecked()) { + return; + } + if (TextUtils.equals(WIFI_TETHER_KEY, key)) { + if (sharedPreferences.getBoolean(key, true)) { + startTethering(TETHERING_WIFI); + } else { + mConnectivityManager.stopTethering(TETHERING_WIFI); + } + } else if (TextUtils.equals(USB_TETHER_KEY, key)) { + if (sharedPreferences.getBoolean(key, false)) { + startTethering(TETHERING_USB); + } else { + mConnectivityManager.stopTethering(TETHERING_USB); + } + } else if (TextUtils.equals(BLUETOOTH_TETHER_KEY, key)) { + if (sharedPreferences.getBoolean(key, false)) { + startTethering(TETHERING_BLUETOOTH); + } else { + mConnectivityManager.stopTethering(TETHERING_BLUETOOTH); + } + } + } } diff --git a/src/com/android/settings/network/UsbTetherPreferenceController.java b/src/com/android/settings/network/UsbTetherPreferenceController.java new file mode 100644 index 00000000000..74e8be8abac --- /dev/null +++ b/src/com/android/settings/network/UsbTetherPreferenceController.java @@ -0,0 +1,144 @@ +/* + * 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.network; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.hardware.usb.UsbManager; +import android.net.ConnectivityManager; +import android.os.Environment; +import android.text.TextUtils; +import android.util.Log; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.Utils; +import com.android.settingslib.core.AbstractPreferenceController; + +/** + * This controller helps to manage the switch state and visibility of USB tether switch + * preference. It stores preference values when preference changed. + * TODO(b/147272749): Extend BasePreferenceController.java instead. + * + */ +public final class UsbTetherPreferenceController extends AbstractPreferenceController implements + LifecycleObserver, Preference.OnPreferenceChangeListener { + + private static final String TAG = "UsbTetherPrefController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + @VisibleForTesting + static final String PREF_KEY = "enable_usb_tethering"; + + private final ConnectivityManager mCm; + private boolean mUsbConnected; + private boolean mMassStorageActive; + private Preference mPreference; + private final SharedPreferences mSharedPreferences; + + public UsbTetherPreferenceController(Context context, Lifecycle lifecycle) { + super(context); + mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mSharedPreferences = + context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + public void onStart() { + mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); + IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE); + filter.addAction(Intent.ACTION_MEDIA_SHARED); + filter.addAction(Intent.ACTION_MEDIA_UNSHARED); + mContext.registerReceiver(mUsbChangeReceiver, filter); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + mContext.unregisterReceiver(mUsbChangeReceiver); + } + + @Override + public boolean isAvailable() { + String[] usbRegexs = mCm.getTetherableUsbRegexs(); + return usbRegexs != null && usbRegexs.length > 0 && !Utils.isMonkeyRunning(); + } + + @Override + public String getPreferenceKey() { + return PREF_KEY; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(PREF_KEY); + if (mPreference != null && mPreference instanceof SwitchPreference) { + ((SwitchPreference) mPreference) + .setChecked(mSharedPreferences.getBoolean(PREF_KEY, false)); + } + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (preference != null) { + if (mUsbConnected && !mMassStorageActive) { + preference.setEnabled(true); + } else { + preference.setEnabled(false); + } + } + } + + @VisibleForTesting + final BroadcastReceiver mUsbChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (TextUtils.equals(Intent.ACTION_MEDIA_SHARED, action)) { + mMassStorageActive = true; + } else if (TextUtils.equals(Intent.ACTION_MEDIA_UNSHARED, action)) { + mMassStorageActive = false; + } else if (TextUtils.equals(UsbManager.ACTION_USB_STATE, action)) { + mUsbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false); + } + updateState(mPreference); + } + }; + + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + if (DEBUG) { + Log.d(TAG, "preference changing to " + o); + } + final SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(PREF_KEY, (Boolean) o); + editor.apply(); + return true; + } +} diff --git a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java new file mode 100644 index 00000000000..bf0e2085f26 --- /dev/null +++ b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java @@ -0,0 +1,166 @@ +/* + * 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.network; + +import android.content.Context; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.text.TextUtils; +import android.util.Log; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.core.AbstractPreferenceController; + +/** + * This controller helps to manage the switch state and visibility of wifi tether disable switch + * preference. When the preference checked, wifi tether will be disabled. + * It stores preference value when preference changed and listens to usb tether and bluetooth tether + * preferences. + * + * @see BluetoothTetherPreferenceController + * @see UsbTetherPreferenceController + * TODO(b/147272749): Extend BasePreferenceController.java instead. + * + */ +public final class WifiTetherDisablePreferenceController extends AbstractPreferenceController + implements LifecycleObserver, Preference.OnPreferenceChangeListener, + SharedPreferences.OnSharedPreferenceChangeListener { + + private static final String TAG = "WifiTetherDisablePreferenceController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + @VisibleForTesting + static final String PREF_KEY = "enable_wifi_tethering"; + private final ConnectivityManager mCm; + private boolean mBluetoothTetherEnabled; + private boolean mUSBTetherEnabled; + private PreferenceScreen mScreen; + private Preference mPreference; + private final SharedPreferences mSharedPreferences; + + public WifiTetherDisablePreferenceController(Context context, Lifecycle lifecycle) { + super(context); + mSharedPreferences = + context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); + mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mUSBTetherEnabled = mSharedPreferences.getBoolean( + TetherEnabler.USB_TETHER_KEY, false); + mBluetoothTetherEnabled = mSharedPreferences.getBoolean( + TetherEnabler.BLUETOOTH_TETHER_KEY, false); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + public void onResume() { + mSharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + public void onPause() { + mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public boolean isAvailable() { + final String[] wifiRegexs = mCm.getTetherableWifiRegexs(); + return wifiRegexs != null && wifiRegexs.length > 0 && shouldShow(); + } + + @VisibleForTesting + boolean shouldShow() { + return mBluetoothTetherEnabled || mUSBTetherEnabled; + } + + @Override + public String getPreferenceKey() { + return PREF_KEY; + } + + @Override + public CharSequence getSummary() { + // TODO(b/146818850): Update summary accordingly. + return super.getSummary(); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mScreen = screen; + mPreference = screen.findPreference(PREF_KEY); + if (mPreference != null && mPreference instanceof SwitchPreference) { + ((SwitchPreference) mPreference) + .setChecked(!mSharedPreferences.getBoolean(PREF_KEY, true)); + mPreference.setOnPreferenceChangeListener(this); + } + updateState(mPreference); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + setVisible(mScreen, PREF_KEY, shouldShow()); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (TextUtils.equals(TetherEnabler.USB_TETHER_KEY, key)) { + mUSBTetherEnabled = sharedPreferences.getBoolean(key, false); + } else if (TextUtils.equals(TetherEnabler.BLUETOOTH_TETHER_KEY, key)) { + mBluetoothTetherEnabled = sharedPreferences.getBoolean(key, false); + } + + // Check if we are hiding this preference. If so, make sure the preference is set to + // unchecked to enable wifi tether. + if (mPreference != null && mPreference instanceof SwitchPreference && !shouldShow()) { + final SwitchPreference switchPreference = (SwitchPreference) mPreference; + if (switchPreference.isChecked()) { + if (DEBUG) { + Log.d(TAG, + "All other types are unchecked, wifi tether enabled automatically"); + } + // Need to call this method before internal state set. + if (switchPreference.callChangeListener(false)) { + switchPreference.setChecked(false); + } + } + } + + updateState(mPreference); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + // The shared preference's value is in the opposite of this preference's value. + final boolean enableWifi = !(boolean) o; + if (true) { + Log.d(TAG, "check state changing to " + o); + } + final SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(PREF_KEY, enableWifi); + editor.apply(); + return true; + } +} diff --git a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java new file mode 100644 index 00000000000..c76e23433c2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java @@ -0,0 +1,87 @@ +/* + * 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.network; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; + +import androidx.lifecycle.Lifecycle; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothTetherPreferenceControllerTest { + + @Mock + private ConnectivityManager mConnectivityManager; + + private BluetoothTetherPreferenceController mController; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( + mConnectivityManager); + when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); + mController = new BluetoothTetherPreferenceController(mContext, mock(Lifecycle.class)); + } + + @Test + public void lifecycle_shouldRegisterReceiverOnStart() { + mController.onStart(); + + verify(mContext).registerReceiver( + eq(mController.mBluetoothChangeReceiver), + any()); + } + + @Test + public void lifecycle_shouldUnregisterReceiverOnStop() { + mController.onStart(); + mController.onStop(); + + verify(mContext).unregisterReceiver( + eq(mController.mBluetoothChangeReceiver)); + } + + @Test + public void display_availableChangedCorrectly() { + when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); + assertThat(mController.isAvailable()).isTrue(); + + when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[0]); + assertThat(mController.isAvailable()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java index 06f3893602c..9dcfa8914d0 100644 --- a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java +++ b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -83,9 +82,22 @@ public class TetherEnablerTest { mNetworkPolicyManager); when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[0]); panReference.set(mBluetoothPan); + when(context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE)) + .thenReturn(mSharedPreferences); mEnabler = new TetherEnabler(context, new SwitchBarController(mSwitchBar), panReference); } + @Test + public void lifecycle_onPause_unRegisterSharedPreferenceListener() { + mEnabler.onResume(); + verify(mSharedPreferences).registerOnSharedPreferenceChangeListener( + eq(mEnabler)); + + mEnabler.onPause(); + verify(mSharedPreferences).unregisterOnSharedPreferenceChangeListener( + eq(mEnabler)); + } + @Test public void lifecycle_onStart_setCheckedCorrectly() { when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[]{""}); @@ -122,29 +134,27 @@ public class TetherEnablerTest { @Test public void onSwitchToggled_onlyStartsWifiTetherWhenNeeded() { + when(mSharedPreferences.getBoolean(TetherEnabler.WIFI_TETHER_KEY, true)).thenReturn(true); when(mWifiManager.isWifiApEnabled()).thenReturn(true); mEnabler.onSwitchToggled(true); - verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any()); doReturn(false).when(mWifiManager).isWifiApEnabled(); mEnabler.onSwitchToggled(true); - - verify(mConnectivityManager, times(1)) - .startTethering(anyInt(), anyBoolean(), any(), any()); + verify(mConnectivityManager).startTethering(anyInt(), anyBoolean(), any(), any()); } @Test public void onSwitchToggled_shouldStartUSBTetherWhenSelected() { SharedPreferences preference = mock(SharedPreferences.class); ReflectionHelpers.setField(mEnabler, "mSharedPreferences", preference); - when(preference.getBoolean(mEnabler.WIFI_TETHER_KEY, true)).thenReturn(false); - when(preference.getBoolean(mEnabler.USB_TETHER_KEY, false)).thenReturn(true); - when(preference.getBoolean(mEnabler.BLUETOOTH_TETHER_KEY, true)).thenReturn(false); + when(preference.getBoolean(TetherEnabler.WIFI_TETHER_KEY, true)).thenReturn(false); + when(preference.getBoolean(TetherEnabler.USB_TETHER_KEY, false)).thenReturn(true); + when(preference.getBoolean(TetherEnabler.BLUETOOTH_TETHER_KEY, true)).thenReturn(false); mEnabler.startTether(); - verify(mConnectivityManager, times(1)) - .startTethering(eq(ConnectivityManager.TETHERING_USB), anyBoolean(), any(), any()); + verify(mConnectivityManager).startTethering( + eq(ConnectivityManager.TETHERING_USB), anyBoolean(), any(), any()); verify(mConnectivityManager, never()) .startTethering(eq(ConnectivityManager.TETHERING_WIFI), anyBoolean(), any(), any()); verify(mConnectivityManager, never()).startTethering( @@ -158,11 +168,11 @@ public class TetherEnablerTest { when(adapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF); mEnabler.startTethering(ConnectivityManager.TETHERING_BLUETOOTH); - verify(adapter, times(1)).enable(); + verify(adapter).enable(); when(adapter.getState()).thenReturn(BluetoothAdapter.STATE_ON); mEnabler.startTethering(ConnectivityManager.TETHERING_BLUETOOTH); - verify(mConnectivityManager, times(1)).startTethering( + verify(mConnectivityManager).startTethering( eq(ConnectivityManager.TETHERING_BLUETOOTH), anyBoolean(), any(), any()); } } diff --git a/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java new file mode 100644 index 00000000000..9127e4bfd67 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java @@ -0,0 +1,84 @@ +/* + * 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.network; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; + +import androidx.lifecycle.Lifecycle; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class UsbTetherPreferenceControllerTest { + + @Mock + private ConnectivityManager mConnectivityManager; + + private Context mContext; + private UsbTetherPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( + mConnectivityManager); + when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[] {""}); + mController = new UsbTetherPreferenceController(mContext, mock(Lifecycle.class)); + } + + @Test + public void lifecycle_shouldRegisterReceiverOnStart() { + mController.onStart(); + + verify(mContext).registerReceiver(eq(mController.mUsbChangeReceiver), any()); + } + + @Test + public void lifecycle_shouldUnregisterReceiverOnStop() { + mController.onStart(); + mController.onStop(); + + verify(mContext).unregisterReceiver(eq(mController.mUsbChangeReceiver)); + } + + @Test + public void display_availableChangedCorrectly() { + when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[] {""}); + assertThat(mController.isAvailable()).isTrue(); + + when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[0]); + assertThat(mController.isAvailable()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java new file mode 100644 index 00000000000..e42c47716c0 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java @@ -0,0 +1,133 @@ +/* + * 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.network; + +import static com.android.settings.network.WifiTetherDisablePreferenceController.PREF_KEY; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; + +import androidx.lifecycle.Lifecycle; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +public class WifiTetherDisablePreferenceControllerTest { + + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private SharedPreferences mSharedPreferences; + @Mock + private PreferenceScreen mPreferenceScreen; + + private SwitchPreference mPreference; + private Context mContext; + private WifiTetherDisablePreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(ApplicationProvider.getApplicationContext()); + mPreference = spy(SwitchPreference.class); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( + mConnectivityManager); + when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{""}); + when(mContext.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE)) + .thenReturn(mSharedPreferences); + mController = new WifiTetherDisablePreferenceController(mContext, mock(Lifecycle.class)); + ReflectionHelpers.setField(mController, "mScreen", mPreferenceScreen); + ReflectionHelpers.setField(mController, "mPreference", mPreference); + when(mPreferenceScreen.findPreference(PREF_KEY)).thenReturn(mPreference); + } + + @Test + + public void lifecycle_shouldRegisterReceiverOnResume() { + mController.onResume(); + + verify(mSharedPreferences).registerOnSharedPreferenceChangeListener(eq(mController)); + } + + @Test + public void lifecycle_shouldUnregisterReceiverOnStop() { + mController.onResume(); + mController.onPause(); + + verify(mSharedPreferences).unregisterOnSharedPreferenceChangeListener(eq(mController)); + } + + @Test + public void display_availableChangedCorrectly() { + when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[0]); + assertThat(mController.isAvailable()).isFalse(); + + when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"test"}); + ReflectionHelpers.setField(mController, "mBluetoothTetherEnabled", false); + ReflectionHelpers.setField(mController, "mUSBTetherEnabled", false); + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void switch_shouldListenToUsbAndBluetooth() { + when(mSharedPreferences.getBoolean( + BluetoothTetherPreferenceController.PREF_KEY, false)).thenReturn(true); + mController.onSharedPreferenceChanged(mSharedPreferences, + BluetoothTetherPreferenceController.PREF_KEY); + verify(mPreference).setVisible(eq(true)); + + when(mSharedPreferences.getBoolean( + UsbTetherPreferenceController.PREF_KEY, false)).thenReturn(true); + mController.onSharedPreferenceChanged(mSharedPreferences, + UsbTetherPreferenceController.PREF_KEY); + assertThat(mController.shouldShow()).isTrue(); + + when(mSharedPreferences.getBoolean( + UsbTetherPreferenceController.PREF_KEY, false)).thenReturn(false); + mController.onSharedPreferenceChanged(mSharedPreferences, + UsbTetherPreferenceController.PREF_KEY); + assertThat(mController.shouldShow()).isTrue(); + + when(mSharedPreferences.getBoolean( + BluetoothTetherPreferenceController.PREF_KEY, false)).thenReturn(false); + when(mSharedPreferences.edit()).thenReturn(mock(SharedPreferences.Editor.class)); + when(mPreference.isChecked()).thenReturn(true); + mController.onSharedPreferenceChanged(mSharedPreferences, + BluetoothTetherPreferenceController.PREF_KEY); + verify(mPreference).setChecked(eq(false)); + verify(mPreference).setVisible(eq(false)); + } +}