Use TetherEnabler in AllInOneTetherSettings to manage master switch

In AllInOneTetherSettings, we use TetherEnabler to hanle all behavior
related to tethering switch on/off.
In TetherEnbler, add WifiManager.WIFI_AP_STATE_CHANGED_ACTION to cover
all possible tethering state change.
TetherEnablerTest is modified accordingly.

Bug: 147322704
Test: make RunSettingsRoboTests ROBOTEST_FILTER=CodeInspectionTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=TetherEnablerTest
Test: make RunSettingsRoboTests
ROBOTEST_FILTER=AllInOneTetherSettingsTest

Change-Id: I505b3825f79260983fff9d3935ba834ad8f9f690
This commit is contained in:
Zhen Zhang
2020-01-13 14:57:23 -08:00
parent 846f739465
commit 02dfed6846
5 changed files with 175 additions and 78 deletions

View File

@@ -20,21 +20,20 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION; import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
import static com.android.settings.network.WifiTetherDisablePreferenceController import static com.android.settings.network.WifiTetherDisablePreferenceController.KEY_ENABLE_WIFI_TETHERING;
.KEY_ENABLE_WIFI_TETHERING;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager; import android.os.UserManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@@ -47,6 +46,8 @@ import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.datausage.DataSaverBackend; import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.network.TetherEnabler; import com.android.settings.network.TetherEnabler;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.SwitchBarController;
import com.android.settings.wifi.tether.WifiTetherApBandPreferenceController; import com.android.settings.wifi.tether.WifiTetherApBandPreferenceController;
import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController; import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController;
import com.android.settings.wifi.tether.WifiTetherBasePreferenceController; import com.android.settings.wifi.tether.WifiTetherBasePreferenceController;
@@ -59,10 +60,10 @@ import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* Displays preferences for Tethering. * Displays preferences for all Tethering options.
* TODO(b/147322704): Use TetherEnabler in this fragment to manage tethering switch on/off.
* TODO(b/147323306): Add tether option preferences into this fragment after controllers created. * TODO(b/147323306): Add tether option preferences into this fragment after controllers created.
*/ */
@SearchIndexable @SearchIndexable
@@ -96,6 +97,7 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
private WifiManager mWifiManager; private WifiManager mWifiManager;
private boolean mRestartWifiApAfterConfigChange; private boolean mRestartWifiApAfterConfigChange;
private final AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<>();
private WifiTetherSSIDPreferenceController mSSIDPreferenceController; private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
private WifiTetherPasswordPreferenceController mPasswordPreferenceController; private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
@@ -103,8 +105,8 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
private WifiTetherSecurityPreferenceController mSecurityPreferenceController; private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
private PreferenceGroup mWifiTetherGroup; private PreferenceGroup mWifiTetherGroup;
private SharedPreferences mSharedPreferences; private SharedPreferences mSharedPreferences;
private ConnectivityManager mConnectivityManager;
private boolean mWifiTetherChosen; private boolean mWifiTetherChosen;
private TetherEnabler mTetherEnabler;
private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() {
@Override @Override
@@ -118,19 +120,30 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) { && mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false; mRestartWifiApAfterConfigChange = false;
startTether(); mTetherEnabler.startTethering(TETHERING_WIFI);
} }
} else if (TextUtils.equals(action, WIFI_AP_STATE_CHANGED_ACTION)) { } else if (TextUtils.equals(action, WIFI_AP_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0); int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
if (state == WifiManager.WIFI_AP_STATE_DISABLED if (state == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) { && mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false; mRestartWifiApAfterConfigChange = false;
startTether(); mTetherEnabler.startTethering(TETHERING_WIFI);
} }
} }
} }
}; };
private final BluetoothProfile.ServiceListener mProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
mBluetoothPan.set((BluetoothPan) proxy);
}
public void onServiceDisconnected(int profile) {
mBluetoothPan.set(null);
}
};
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
return SettingsEnums.TETHER; return SettingsEnums.TETHER;
@@ -144,8 +157,6 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mSharedPreferences = mSharedPreferences =
context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE);
@@ -181,6 +192,27 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
// TODO(b/147325229): Hide advanced settings like security and ap band. // TODO(b/147325229): Hide advanced settings like security and ap band.
} }
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mUnavailable) {
return;
}
// Assume we are in a SettingsActivity. This is only safe because we currently use
// SettingsActivity as base for all preference fragments.
final SettingsActivity activity = (SettingsActivity) getActivity();
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener,
BluetoothProfile.PAN);
}
final SwitchBar switchBar = activity.getSwitchBar();
mTetherEnabler = new TetherEnabler(activity,
new SwitchBarController(switchBar), mBluetoothPan);
getSettingsLifecycle().addObserver(mTetherEnabler);
switchBar.show();
}
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
@@ -297,8 +329,7 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
Log.d(TAG, "Wifi AP config changed while enabled, stop and restart"); Log.d(TAG, "Wifi AP config changed while enabled, stop and restart");
} }
mRestartWifiApAfterConfigChange = true; mRestartWifiApAfterConfigChange = true;
// TODO(b/147322704): Use TethetEnabler to stop tethering. mTetherEnabler.stopTethering(TETHERING_WIFI);
mConnectivityManager.stopTethering(TETHERING_WIFI);
} }
if (controller instanceof WifiTetherSecurityPreferenceController) { if (controller instanceof WifiTetherSecurityPreferenceController) {
@@ -335,23 +366,6 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
} }
} }
private void startTether() {
// TODO(b/147322704): Use TetherEnabler to start tethering.
if (mWifiManager.isWifiApEnabled()) {
return;
}
mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI,
true /*showProvisioningUi*/,
new ConnectivityManager.OnStartTetheringCallback() {
@Override
public void onTetheringFailed() {
super.onTetheringFailed();
// Do nothing. There is no UI to update at this point.
}
},
new Handler(Looper.getMainLooper()));
}
private void reConfigInitialExpandedChildCount() { private void reConfigInitialExpandedChildCount() {
getPreferenceScreen().setInitialExpandedChildrenCount(getInitialExpandedChildCount()); getPreferenceScreen().setInitialExpandedChildrenCount(getInitialExpandedChildCount());
} }

View File

@@ -47,8 +47,7 @@ public final class BluetoothTetherPreferenceController extends AbstractPreferenc
private static final String TAG = "BluetoothTetherPreferenceController"; private static final String TAG = "BluetoothTetherPreferenceController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@VisibleForTesting public static final String PREF_KEY = "enable_bluetooth_tethering";
static final String PREF_KEY = "enable_bluetooth_tethering";
private final ConnectivityManager mCm; private final ConnectivityManager mCm;
private int mBluetoothState; private int mBluetoothState;
private Preference mPreference; private Preference mPreference;

View File

@@ -42,6 +42,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.datausage.DataSaverBackend; import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.widget.SwitchWidgetController; import com.android.settings.widget.SwitchWidgetController;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@@ -78,14 +79,7 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
private final Context mContext; private final Context mContext;
@VisibleForTesting @VisibleForTesting
final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback = ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback;
new ConnectivityManager.OnStartTetheringCallback() {
@Override
public void onTetheringFailed() {
super.onTetheringFailed();
mSwitchWidgetController.setChecked(false);
}
};
private final AtomicReference<BluetoothPan> mBluetoothPan; private final AtomicReference<BluetoothPan> mBluetoothPan;
private final SharedPreferences mSharedPreferences; private final SharedPreferences mSharedPreferences;
private boolean mBluetoothEnableForTether; private boolean mBluetoothEnableForTether;
@@ -110,11 +104,15 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
mDataSaverBackend.addListener(this); mDataSaverBackend.addListener(this);
mSwitchWidgetController.setListener(this); mSwitchWidgetController.setListener(this);
mSwitchWidgetController.startListening(); mSwitchWidgetController.startListening();
IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
final IntentFilter filter = new IntentFilter(
ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
mContext.registerReceiver(mTetherChangeReceiver, filter); mContext.registerReceiver(mTetherChangeReceiver, filter);
mSwitchWidgetController.setChecked(isTethering());
setSwitchWidgetEnabled(true); mOnStartTetheringCallback = new OnStartTetheringCallback(this);
updateState();
} }
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
@@ -134,8 +132,14 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
mContext.unregisterReceiver(mTetherChangeReceiver); mContext.unregisterReceiver(mTetherChangeReceiver);
} }
private void setSwitchWidgetEnabled(boolean enabled) { private void updateState() {
mSwitchWidgetController.setEnabled(enabled && !mDataSaverEnabled); mSwitchWidgetController.setChecked(isTethering());
mSwitchWidgetController.setEnabled(!mDataSaverEnabled);
}
private void updateState(String[] tethered) {
mSwitchWidgetController.setChecked(isTethering(tethered));
mSwitchWidgetController.setEnabled(!mDataSaverEnabled);
} }
private boolean isTethering() { private boolean isTethering() {
@@ -148,6 +152,10 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
return true; return true;
} }
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
return true;
}
final BluetoothPan pan = mBluetoothPan.get(); final BluetoothPan pan = mBluetoothPan.get();
return pan != null && pan.isTetheringOn(); return pan != null && pan.isTetheringOn();
@@ -155,31 +163,41 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
@Override @Override
public boolean onSwitchToggled(boolean isChecked) { public boolean onSwitchToggled(boolean isChecked) {
if (isChecked) { if (isChecked && !isTethering()) {
startTether(); startTether();
} else { }
if (!isChecked && isTethering()) {
stopTether(); stopTether();
} }
return true; return true;
} }
@VisibleForTesting private void stopTether() {
void stopTether() {
// Wi-Fi tether is selected by default. // Wi-Fi tether is selected by default.
if (mSharedPreferences.getBoolean(WIFI_TETHER_KEY, true)) { if (mSharedPreferences.getBoolean(WIFI_TETHER_KEY, true)) {
mConnectivityManager.stopTethering(TETHERING_WIFI); stopTethering(TETHERING_WIFI);
} }
if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) { if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) {
mConnectivityManager.stopTethering(TETHERING_USB); stopTethering(TETHERING_USB);
} }
if (mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)) { if (mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)) {
mConnectivityManager.stopTethering(TETHERING_BLUETOOTH); stopTethering(TETHERING_BLUETOOTH);
} }
} }
/**
* Use this method to stop a single choice of tethering.
*
* @param choice The choice of tethering to stop.
*/
public void stopTethering(int choice) {
mConnectivityManager.stopTethering(choice);
}
@VisibleForTesting @VisibleForTesting
void startTether() { void startTether() {
@@ -197,8 +215,16 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
} }
} }
@VisibleForTesting /**
void startTethering(int choice) { * Use this method to start a single choice of tethering.
* For bluetooth tethering, it will first turn on bluetooth if bluetooth is off.
* For Wi-Fi tethering, it will be no-op if Wi-Fi tethering already active.
*
* @param choice The choice of tethering to start.
*/
public void startTethering(int choice) {
mSwitchWidgetController.setEnabled(false);
if (choice == TETHERING_WIFI && mWifiManager.isWifiApEnabled()) { if (choice == TETHERING_WIFI && mWifiManager.isWifiApEnabled()) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Wifi tether already active!"); Log.d(TAG, "Wifi tether already active!");
@@ -224,36 +250,67 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); final String action = intent.getAction();
ArrayList<String> active = null;
boolean shouldUpdateState = false;
if (TextUtils.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, action)) { if (TextUtils.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, action)) {
ArrayList<String> active = intent.getStringArrayListExtra( active = intent.getStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER);
ConnectivityManager.EXTRA_ACTIVE_TETHER); shouldUpdateState = true;
mSwitchWidgetController.setChecked( } else if (TextUtils.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION, action)) {
isTethering(active.toArray(new String[active.size()]))); shouldUpdateState = handleWifiApStateChanged(intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED));
} else if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, action)) { } else if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, action)) {
switch (intent shouldUpdateState = handleBluetoothStateChanged(intent
.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) { .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
case BluetoothAdapter.STATE_ON: }
if (mBluetoothEnableForTether) {
startTethering(TETHERING_BLUETOOTH); if (shouldUpdateState) {
} if (active != null) {
// Fall through. updateState(active.toArray(new String[0]));
case BluetoothAdapter.STATE_OFF: } else {
// Fall through. updateState();
case BluetoothAdapter.ERROR:
mBluetoothEnableForTether = false;
break;
default:
// ignore transition states
} }
} }
} }
}; };
private boolean handleBluetoothStateChanged(int state) {
switch (state) {
case BluetoothAdapter.STATE_ON:
if (mBluetoothEnableForTether) {
startTethering(TETHERING_BLUETOOTH);
}
// Fall through.
case BluetoothAdapter.STATE_OFF:
// Fall through.
case BluetoothAdapter.ERROR:
mBluetoothEnableForTether = false;
return true;
default:
// Return false for transition states.
return false;
}
}
private boolean handleWifiApStateChanged(int state) {
switch (state) {
case WifiManager.WIFI_AP_STATE_FAILED:
Log.e(TAG, "Wifi AP is failed!");
// fall through
case WifiManager.WIFI_AP_STATE_ENABLED:
// fall through
case WifiManager.WIFI_AP_STATE_DISABLED:
return true;
default:
// return false for transition state
return false;
}
}
@Override @Override
public void onDataSaverChanged(boolean isDataSaving) { public void onDataSaverChanged(boolean isDataSaving) {
mDataSaverEnabled = isDataSaving; mDataSaverEnabled = isDataSaving;
setSwitchWidgetEnabled(!isDataSaving); mSwitchWidgetController.setEnabled(!isDataSaving);
} }
@Override @Override
@@ -291,4 +348,30 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
} }
} }
} }
private static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
final WeakReference<TetherEnabler> mTetherEnabler;
OnStartTetheringCallback(TetherEnabler enabler) {
mTetherEnabler = new WeakReference<>(enabler);
}
@Override
public void onTetheringStarted() {
update();
}
@Override
public void onTetheringFailed() {
update();
}
private void update() {
TetherEnabler enabler = mTetherEnabler.get();
if (enabler != null) {
enabler.updateState();
}
}
}
} }

View File

@@ -49,8 +49,7 @@ public final class UsbTetherPreferenceController extends AbstractPreferenceContr
private static final String TAG = "UsbTetherPrefController"; private static final String TAG = "UsbTetherPrefController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@VisibleForTesting public static final String PREF_KEY = "enable_usb_tethering";
static final String PREF_KEY = "enable_usb_tethering";
private final ConnectivityManager mCm; private final ConnectivityManager mCm;
private boolean mUsbConnected; private boolean mUsbConnected;

View File

@@ -109,8 +109,10 @@ public class TetherEnablerTest {
@Test @Test
public void startTether_fail_resetSwitchBar() { public void startTether_fail_resetSwitchBar() {
when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false); when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false);
mEnabler.onStart();
mEnabler.startTether(); mEnabler.startTether();
when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[0]);
mEnabler.mOnStartTetheringCallback.onTetheringFailed(); mEnabler.mOnStartTetheringCallback.onTetheringFailed();
assertThat(mSwitchBar.isChecked()).isFalse(); assertThat(mSwitchBar.isChecked()).isFalse();