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

Commit 8351faa9 authored by Erik Kline's avatar Erik Kline
Browse files

Add local-only hotspot info into tether state change broadcast

Test: as follows
    - build
    - flashed
    - booted
    - "runtest frameworks-net" passes
    - manually starting tethering shows Settings and icon updates
Bug: 31466854
Bug: 32163131

Change-Id: I938074587dfeec221c5cdb43a392802ad3fc3589
parent fe86a197
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -301,7 +301,8 @@ public class ConnectivityManager {
    /**
     * Broadcast Action: A tetherable connection has come or gone.
     * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER},
     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and
     * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY},
     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and
     * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate
     * the current state of tethering.  Each include a list of
     * interface names in that state (may be empty).
@@ -318,12 +319,19 @@ public class ConnectivityManager {
     */
    public static final String EXTRA_AVAILABLE_TETHER = "availableArray";

    /**
     * @hide
     * gives a String[] listing all the interfaces currently in local-only
     * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
     */
    public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";

    /**
     * @hide
     * gives a String[] listing all the interfaces currently tethered
     * (ie, has dhcp support and packets potentially forwarded/NATed)
     * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
     */
    public static final String EXTRA_ACTIVE_TETHER = "activeArray";
    public static final String EXTRA_ACTIVE_TETHER = "tetherArray";

    /**
     * @hide
+24 −18
Original line number Diff line number Diff line
@@ -623,9 +623,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    private void sendTetherStateChangedBroadcast() {
        if (!getConnectivityManager().isTetheringSupported()) return;

        ArrayList<String> availableList = new ArrayList<String>();
        ArrayList<String> activeList = new ArrayList<String>();
        ArrayList<String> erroredList = new ArrayList<String>();
        final ArrayList<String> availableList = new ArrayList<>();
        final ArrayList<String> tetherList = new ArrayList<>();
        final ArrayList<String> localOnlyList = new ArrayList<>();
        final ArrayList<String> erroredList = new ArrayList<>();

        boolean wifiTethered = false;
        boolean usbTethered = false;
@@ -641,6 +642,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
                    erroredList.add(iface);
                } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
                    availableList.add(iface);
                } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_HOTSPOT) {
                    localOnlyList.add(iface);
                } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
                    if (cfg.isUsb(iface)) {
                        usbTethered = true;
@@ -649,25 +652,25 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
                    } else if (cfg.isBluetooth(iface)) {
                        bluetoothTethered = true;
                    }
                    activeList.add(iface);
                    tetherList.add(iface);
                }
            }
        }
        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
        final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
        bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
                availableList);
        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
                erroredList);
        mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList);
        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList);
        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList);
        mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
        if (DBG) {
            Log.d(TAG, String.format(
                    "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]",
                    TextUtils.join(",", availableList),
                    TextUtils.join(",", activeList),
                    TextUtils.join(",", erroredList)));
                    "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
                    "avail", TextUtils.join(",", availableList),
                    "local_only", TextUtils.join(",", localOnlyList),
                    "tether", TextUtils.join(",", tetherList),
                    "error", TextUtils.join(",", erroredList)));
        }

        if (usbTethered) {
@@ -1338,7 +1341,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
            mForwardedDownstreams.remove(who);
        }

        class InitialState extends TetherMasterUtilState {
        class InitialState extends State {
            @Override
            public boolean processMessage(Message message) {
                maybeLogMessage(this, message.what);
@@ -1516,7 +1519,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
        }

        class ErrorState extends State {
            int mErrorNotification;
            private int mErrorNotification;

            @Override
            public boolean processMessage(Message message) {
                boolean retValue = true;
@@ -1534,6 +1538,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
                }
                return retValue;
            }

            void notify(int msgType) {
                mErrorNotification = msgType;
                for (TetherInterfaceStateMachine sm : mNotifyList) {
@@ -1542,6 +1547,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
            }

        }

        class SetIpForwardingEnabledErrorState extends ErrorState {
            @Override
            public void enter() {
+47 −11
Original line number Diff line number Diff line
@@ -29,9 +29,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
@@ -53,12 +55,16 @@ import android.telephony.CarrierConfigManager;

import com.android.internal.util.test.BroadcastInterceptingContext;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Vector;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class TetheringTest {
@@ -81,7 +87,9 @@ public class TetheringTest {
    private final TestLooper mLooper = new TestLooper();
    private final String mTestIfname = "test_wlan0";

    private Vector<Intent> mIntents;
    private BroadcastInterceptingContext mServiceContext;
    private BroadcastReceiver mBroadcastReceiver;
    private Tethering mTethering;

    private class MockContext extends BroadcastInterceptingContext {
@@ -100,7 +108,8 @@ public class TetheringTest {
        }
    }

    @Before public void setUp() throws Exception {
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
                .thenReturn(new String[0]);
@@ -118,10 +127,24 @@ public class TetheringTest {
                .thenReturn(new InterfaceConfiguration());

        mServiceContext = new MockContext(mContext);
        mIntents = new Vector<>();
        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                mIntents.addElement(intent);
            }
        };
        mServiceContext.registerReceiver(mBroadcastReceiver,
                new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
        mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
                                   mLooper.getLooper(), mSystemProperties);
    }

    @After
    public void tearDown() {
        mServiceContext.unregisterReceiver(mBroadcastReceiver);
    }

    private void setupForRequiredProvisioning() {
        // Produce some acceptable looking provision app setting if requested.
        when(mResources.getStringArray(
@@ -180,6 +203,23 @@ public class TetheringTest {
        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }

    private void verifyInterfaceServingModeStarted() throws Exception {
        verify(mNMService, times(1)).listInterfaces();
        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
        verify(mNMService, times(1))
                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
        verify(mNMService, times(1)).tetherInterface(mTestIfname);
    }

    private void verifyTetheringBroadcast(String ifname, String whichExtra) {
        // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
        final Intent bcast = mIntents.get(0);
        assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
        final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
        assertTrue(ifnames.contains(ifname));
        mIntents.remove(bcast);
    }

    @Test
    public void workingLocalOnlyHotspot() throws Exception {
        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
@@ -193,14 +233,12 @@ public class TetheringTest {
        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
        mLooper.dispatchAll();

        verify(mNMService, times(1)).listInterfaces();
        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
        verify(mNMService, times(1))
                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
        verify(mNMService, times(1)).tetherInterface(mTestIfname);
        verifyInterfaceServingModeStarted();
        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
        verify(mNMService, times(1)).setIpForwardingEnabled(true);
        verify(mNMService, times(1)).startTethering(any(String[].class));
        verifyNoMoreInteractions(mNMService);
        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
        // UpstreamNetworkMonitor will be started, and will register two callbacks:
        // a "listen all" and a "track default".
        verify(mConnectivityManager, times(1)).registerNetworkCallback(
@@ -252,14 +290,12 @@ public class TetheringTest {
        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
        mLooper.dispatchAll();

        verify(mNMService, times(1)).listInterfaces();
        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
        verify(mNMService, times(1))
                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
        verify(mNMService, times(1)).tetherInterface(mTestIfname);
        verifyInterfaceServingModeStarted();
        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
        verify(mNMService, times(1)).setIpForwardingEnabled(true);
        verify(mNMService, times(1)).startTethering(any(String[].class));
        verifyNoMoreInteractions(mNMService);
        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
        // UpstreamNetworkMonitor will be started, and will register two callbacks:
        // a "listen all" and a "track default".
        verify(mConnectivityManager, times(1)).registerNetworkCallback(