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

Commit 460ce85b authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Make HotspotControllerImpl async"

parents ec574d18 ff410597
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.os.UserManager;
import android.service.quicksettings.Tile;
import android.util.Log;
import android.widget.Switch;

import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -200,6 +201,14 @@ public class HotspotTile extends QSTileImpl<BooleanState> {
            mCallbackInfo.numConnectedDevices = numDevices;
            refreshState(mCallbackInfo);
        }

        @Override
        public void onHotspotAvailabilityChanged(boolean available) {
            if (!available) {
                Log.d(TAG, "Tile removed. Hotspot no longer available");
                mHost.removeTile(getTileSpec());
            }
        }
    }

    /**
+1 −0
Original line number Diff line number Diff line
@@ -30,5 +30,6 @@ public interface HotspotController extends CallbackController<Callback>, Dumpabl

    interface Callback {
        void onHotspotChanged(boolean enabled, int numDevices);
        default void onHotspotAvailabilityChanged(boolean available) {}
    }
}
+60 −14
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.TetheringManager;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiManager;
import android.os.Handler;
@@ -26,6 +27,8 @@ import android.os.HandlerExecutor;
import android.os.UserManager;
import android.util.Log;

import com.android.internal.util.ConcurrentUtils;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;

import java.io.FileDescriptor;
@@ -46,36 +49,63 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
    private final ConnectivityManager mConnectivityManager;
    private final TetheringManager mTetheringManager;
    private final WifiManager mWifiManager;
    private final Handler mMainHandler;
    private final Context mContext;

    private int mHotspotState;
    private volatile int mNumConnectedDevices;
    private volatile boolean mIsTetheringSupported;
    private volatile boolean mHasTetherableWifiRegexs;
    private boolean mWaitingForTerminalState;

    private TetheringManager.TetheringEventCallback mTetheringCallback =
            new TetheringManager.TetheringEventCallback() {
                @Override
                public void onTetheringSupported(boolean supported) {
                    super.onTetheringSupported(supported);
                    if (mIsTetheringSupported != supported) {
                        mIsTetheringSupported = supported;
                        fireHotspotAvailabilityChanged();
                    }
                }

                @Override
                public void onTetherableInterfaceRegexpsChanged(
                        TetheringManager.TetheringInterfaceRegexps reg) {
                    super.onTetherableInterfaceRegexpsChanged(reg);
                    final boolean newValue = reg.getTetherableWifiRegexs().size() != 0;
                    if (mHasTetherableWifiRegexs != newValue) {
                        mHasTetherableWifiRegexs = newValue;
                        fireHotspotAvailabilityChanged();
                    }
                }
            };

    /**
     * Controller used to retrieve information related to a hotspot.
     */
    @Inject
    public HotspotControllerImpl(Context context, @Main Handler mainHandler) {
    public HotspotControllerImpl(Context context, @Main Handler mainHandler,
            @Background Handler backgroundHandler) {
        mContext = context;
        mConnectivityManager =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        mTetheringManager = context.getSystemService(TetheringManager.class);
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mMainHandler = mainHandler;
        mTetheringManager.registerTetheringEventCallback(
                new HandlerExecutor(backgroundHandler), mTetheringCallback);
    }

    @Override
    public boolean isHotspotSupported() {
        return mConnectivityManager.isTetheringSupported()
                && mConnectivityManager.getTetherableWifiRegexs().length != 0
        return mIsTetheringSupported && mHasTetherableWifiRegexs
                && UserManager.get(mContext).isUserAdmin(ActivityManager.getCurrentUser());
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("HotspotController state:");
        pw.print("  available="); pw.println(isHotspotSupported());
        pw.print("  mHotspotState="); pw.println(stateToString(mHotspotState));
        pw.print("  mNumConnectedDevices="); pw.println(mNumConnectedDevices);
        pw.print("  mWaitingForTerminalState="); pw.println(mWaitingForTerminalState);
@@ -152,17 +182,18 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
        if (enabled) {
            mWaitingForTerminalState = true;
            if (DEBUG) Log.d(TAG, "Starting tethering");
            mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false,
                    new ConnectivityManager.OnStartTetheringCallback() {
            mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI,
                    ConcurrentUtils.DIRECT_EXECUTOR,
                    new TetheringManager.StartTetheringCallback() {
                        @Override
                        public void onTetheringFailed() {
                        public void onTetheringFailed(final int result) {
                            if (DEBUG) Log.d(TAG, "onTetheringFailed");
                            maybeResetSoftApState();
                            fireHotspotChangedCallback();
                        }
                    });
        } else {
            mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
            mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
        }
    }

@@ -177,11 +208,26 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
     * (as it can be blocked).
     */
    private void fireHotspotChangedCallback() {
        List<Callback> list;
        synchronized (mCallbacks) {
            for (Callback callback : mCallbacks) {
            list = new ArrayList<>(mCallbacks);
        }
        for (Callback callback : list) {
            callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices);
        }
    }

    /**
     * Sends a hotspot available changed callback.
     */
    private void fireHotspotAvailabilityChanged() {
        List<Callback> list;
        synchronized (mCallbacks) {
            list = new ArrayList<>(mCallbacks);
        }
        for (Callback callback : list) {
            callback.onHotspotAvailabilityChanged(isHotspotSupported());
        }
    }

    @Override
@@ -206,7 +252,7 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
        switch (mHotspotState) {
            case WifiManager.WIFI_AP_STATE_FAILED:
                // TODO(b/110697252): must be called to reset soft ap state after failure
                mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
                mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
                // Fall through
            case WifiManager.WIFI_AP_STATE_ENABLED:
            case WifiManager.WIFI_AP_STATE_DISABLED:
+50 −4
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.statusbar.policy;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -24,10 +26,12 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.net.ConnectivityManager;
import android.net.TetheringManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

@@ -38,11 +42,14 @@ import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;

import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Executor;

@SmallTest
@@ -51,13 +58,19 @@ import java.util.concurrent.Executor;
public class HotspotControllerImplTest extends SysuiTestCase {

    @Mock
    private ConnectivityManager mConnectivityManager;
    private TetheringManager mTetheringManager;
    @Mock
    private WifiManager mWifiManager;
    @Mock
    private UserManager mUserManager;
    @Mock
    private HotspotController.Callback mCallback1;
    @Mock
    private HotspotController.Callback mCallback2;
    @Mock
    private TetheringManager.TetheringInterfaceRegexps mTetheringInterfaceRegexps;
    @Captor
    private ArgumentCaptor<TetheringManager.TetheringEventCallback> mTetheringCallbackCaptor;
    private HotspotControllerImpl mController;
    private TestableLooper mLooper;

@@ -66,8 +79,13 @@ public class HotspotControllerImplTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        mLooper = TestableLooper.get(this);

        mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager);
        mContext.addMockSystemService(WifiManager.class, mWifiManager);
        mContext.addMockSystemService(TetheringManager.class, mTetheringManager);
        mContext.addMockSystemService(UserManager.class, mUserManager);

        when(mUserManager.isUserAdmin(anyInt())).thenReturn(true);
        when(mTetheringInterfaceRegexps.getTetherableWifiRegexs()).thenReturn(
                Collections.singletonList("test"));

        doAnswer((InvocationOnMock invocation) -> {
            ((WifiManager.SoftApCallback) invocation.getArgument(1))
@@ -76,7 +94,11 @@ public class HotspotControllerImplTest extends SysuiTestCase {
        }).when(mWifiManager).registerSoftApCallback(any(Executor.class),
                any(WifiManager.SoftApCallback.class));

        mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
        Handler handler = new Handler(mLooper.getLooper());

        mController = new HotspotControllerImpl(mContext, handler, handler);
        verify(mTetheringManager)
                .registerTetheringEventCallback(any(), mTetheringCallbackCaptor.capture());
    }

    @Test
@@ -117,4 +139,28 @@ public class HotspotControllerImplTest extends SysuiTestCase {
        verify(mWifiManager, never()).unregisterSoftApCallback(any());
    }

    @Test
    public void testDefault_hotspotNotSupported() {
        assertFalse(mController.isHotspotSupported());
    }

    @Test
    public void testHotspotSupported_rightConditions() {
        mTetheringCallbackCaptor.getValue().onTetheringSupported(true);
        mTetheringCallbackCaptor.getValue()
                .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps);

        assertTrue(mController.isHotspotSupported());
    }

    @Test
    public void testHotspotSupported_callbackCalledOnChange() {
        mController.addCallback(mCallback1);
        mTetheringCallbackCaptor.getValue().onTetheringSupported(true);
        mTetheringCallbackCaptor.getValue()
                .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps);

        verify(mCallback1).onHotspotAvailabilityChanged(true);
    }

}