Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02dfed68 authored by Zhen Zhang's avatar Zhen Zhang
Browse files

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
parent 846f7394
Loading
Loading
Loading
Loading
+45 −31
Original line number Diff line number Diff line
@@ -20,21 +20,20 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;

import static com.android.settings.network.WifiTetherDisablePreferenceController
        .KEY_ENABLE_WIFI_TETHERING;
import static com.android.settings.network.WifiTetherDisablePreferenceController.KEY_ENABLE_WIFI_TETHERING;

import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
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.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
@@ -47,6 +46,8 @@ import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.network.TetherEnabler;
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.WifiTetherAutoOffPreferenceController;
import com.android.settings.wifi.tether.WifiTetherBasePreferenceController;
@@ -59,10 +60,10 @@ import com.android.settingslib.search.SearchIndexable;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Displays preferences for Tethering.
 * TODO(b/147322704): Use TetherEnabler in this fragment to manage tethering switch on/off.
 * Displays preferences for all Tethering options.
 * TODO(b/147323306): Add tether option preferences into this fragment after controllers created.
 */
@SearchIndexable
@@ -96,6 +97,7 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment

    private WifiManager mWifiManager;
    private boolean mRestartWifiApAfterConfigChange;
    private final AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<>();

    private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
    private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
@@ -103,8 +105,8 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
    private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
    private PreferenceGroup mWifiTetherGroup;
    private SharedPreferences mSharedPreferences;
    private ConnectivityManager mConnectivityManager;
    private boolean mWifiTetherChosen;
    private TetherEnabler mTetherEnabler;

    private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() {
        @Override
@@ -118,19 +120,30 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
                if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
                        && mRestartWifiApAfterConfigChange) {
                    mRestartWifiApAfterConfigChange = false;
                    startTether();
                    mTetherEnabler.startTethering(TETHERING_WIFI);
                }
            } else if (TextUtils.equals(action, WIFI_AP_STATE_CHANGED_ACTION)) {
                int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
                if (state == WifiManager.WIFI_AP_STATE_DISABLED
                        && mRestartWifiApAfterConfigChange) {
                    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
    public int getMetricsCategory() {
        return SettingsEnums.TETHER;
@@ -144,8 +157,6 @@ public final class AllInOneTetherSettings extends RestrictedDashboardFragment
    public void onAttach(Context context) {
        super.onAttach(context);
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mConnectivityManager =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        mSharedPreferences =
                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.
    }

    @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
    public void 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");
            }
            mRestartWifiApAfterConfigChange = true;
            // TODO(b/147322704): Use TethetEnabler to stop tethering.
            mConnectivityManager.stopTethering(TETHERING_WIFI);
            mTetherEnabler.stopTethering(TETHERING_WIFI);
        }

        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() {
        getPreferenceScreen().setInitialExpandedChildrenCount(getInitialExpandedChildCount());
    }
+1 −2
Original line number Diff line number Diff line
@@ -47,8 +47,7 @@ public final class BluetoothTetherPreferenceController extends AbstractPreferenc

    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";
    public static final String PREF_KEY = "enable_bluetooth_tethering";
    private final ConnectivityManager mCm;
    private int mBluetoothState;
    private Preference mPreference;
+125 −42
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.widget.SwitchWidgetController;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference;

@@ -78,14 +79,7 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
    private final Context mContext;

    @VisibleForTesting
    final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback =
            new ConnectivityManager.OnStartTetheringCallback() {
                @Override
                public void onTetheringFailed() {
                    super.onTetheringFailed();
                    mSwitchWidgetController.setChecked(false);
                }
            };
    ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback;
    private final AtomicReference<BluetoothPan> mBluetoothPan;
    private final SharedPreferences mSharedPreferences;
    private boolean mBluetoothEnableForTether;
@@ -110,11 +104,15 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
        mDataSaverBackend.addListener(this);
        mSwitchWidgetController.setListener(this);
        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);
        mContext.registerReceiver(mTetherChangeReceiver, filter);
        mSwitchWidgetController.setChecked(isTethering());
        setSwitchWidgetEnabled(true);

        mOnStartTetheringCallback = new OnStartTetheringCallback(this);
        updateState();
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
@@ -134,8 +132,14 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
        mContext.unregisterReceiver(mTetherChangeReceiver);
    }

    private void setSwitchWidgetEnabled(boolean enabled) {
        mSwitchWidgetController.setEnabled(enabled && !mDataSaverEnabled);
    private void updateState() {
        mSwitchWidgetController.setChecked(isTethering());
        mSwitchWidgetController.setEnabled(!mDataSaverEnabled);
    }

    private void updateState(String[] tethered) {
        mSwitchWidgetController.setChecked(isTethering(tethered));
        mSwitchWidgetController.setEnabled(!mDataSaverEnabled);
    }

    private boolean isTethering() {
@@ -148,6 +152,10 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
            return true;
        }

        if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
            return true;
        }

        final BluetoothPan pan = mBluetoothPan.get();

        return pan != null && pan.isTetheringOn();
@@ -155,29 +163,39 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang

    @Override
    public boolean onSwitchToggled(boolean isChecked) {
        if (isChecked) {
        if (isChecked && !isTethering()) {
            startTether();
        } else {
        }

        if (!isChecked && isTethering()) {
            stopTether();
        }
        return true;
    }

    @VisibleForTesting
    void stopTether() {
    private void stopTether() {

        // Wi-Fi tether is selected by default.
        if (mSharedPreferences.getBoolean(WIFI_TETHER_KEY, true)) {
            mConnectivityManager.stopTethering(TETHERING_WIFI);
            stopTethering(TETHERING_WIFI);
        }

        if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) {
            mConnectivityManager.stopTethering(TETHERING_USB);
            stopTethering(TETHERING_USB);
        }

        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
@@ -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 (DEBUG) {
                Log.d(TAG, "Wifi tether already active!");
@@ -224,15 +250,32 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
    private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() {
        @Override
        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)) {
                ArrayList<String> active = intent.getStringArrayListExtra(
                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
                mSwitchWidgetController.setChecked(
                        isTethering(active.toArray(new String[active.size()])));
                active = intent.getStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER);
                shouldUpdateState = true;
            } else if (TextUtils.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION, action)) {
                shouldUpdateState = handleWifiApStateChanged(intent.getIntExtra(
                        WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED));
            } else if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, action)) {
                switch (intent
                        .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
                shouldUpdateState = handleBluetoothStateChanged(intent
                        .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
            }

            if (shouldUpdateState) {
                if (active != null) {
                    updateState(active.toArray(new String[0]));
                } else {
                    updateState();
                }
            }
        }
    };

    private boolean handleBluetoothStateChanged(int state) {
        switch (state) {
            case BluetoothAdapter.STATE_ON:
                if (mBluetoothEnableForTether) {
                    startTethering(TETHERING_BLUETOOTH);
@@ -242,18 +285,32 @@ public final class TetherEnabler implements SwitchWidgetController.OnSwitchChang
                // Fall through.
            case BluetoothAdapter.ERROR:
                mBluetoothEnableForTether = false;
                        break;
                return true;
            default:
                        // ignore transition states
                // 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
    public void onDataSaverChanged(boolean isDataSaving) {
        mDataSaverEnabled = isDataSaving;
        setSwitchWidgetEnabled(!isDataSaving);
        mSwitchWidgetController.setEnabled(!isDataSaving);
    }

    @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();
            }
        }
    }
}
+1 −2
Original line number Diff line number Diff line
@@ -49,8 +49,7 @@ public final class UsbTetherPreferenceController extends AbstractPreferenceContr

    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";
    public static final String PREF_KEY = "enable_usb_tethering";

    private final ConnectivityManager mCm;
    private boolean mUsbConnected;
+3 −1
Original line number Diff line number Diff line
@@ -109,8 +109,10 @@ public class TetherEnablerTest {
    @Test
    public void startTether_fail_resetSwitchBar() {
        when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false);

        mEnabler.onStart();
        mEnabler.startTether();

        when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[0]);
        mEnabler.mOnStartTetheringCallback.onTetheringFailed();

        assertThat(mSwitchBar.isChecked()).isFalse();