Loading packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +9 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } } /** Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java +1 −0 Original line number Diff line number Diff line Loading @@ -30,5 +30,6 @@ public interface HotspotController extends CallbackController<Callback>, Dumpabl interface Callback { void onHotspotChanged(boolean enabled, int numDevices); default void onHotspotAvailabilityChanged(boolean available) {} } } packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +60 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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); } } Loading @@ -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 Loading @@ -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: Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java +50 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading @@ -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; Loading @@ -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)) Loading @@ -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 Loading Loading @@ -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); } } Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +9 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } } /** Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java +1 −0 Original line number Diff line number Diff line Loading @@ -30,5 +30,6 @@ public interface HotspotController extends CallbackController<Callback>, Dumpabl interface Callback { void onHotspotChanged(boolean enabled, int numDevices); default void onHotspotAvailabilityChanged(boolean available) {} } }
packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +60 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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); } } Loading @@ -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 Loading @@ -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: Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java +50 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading @@ -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; Loading @@ -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)) Loading @@ -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 Loading Loading @@ -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); } }