Support for hotspot client visibility.

Adding support for visibility into clients that connect to an active hotspot.

Bug: 137309578
Test: atest FrameworksNetTests:com.android.server.connectivity.TetheringTest
atest FrameworksWifiApiTests:android.net.wifi.WifiManagerTest
atest FrameworksWifiApiTests:android.net.wifi.WifiClientTest
Tested manually on Pixel 3.

Change-Id: I1caeb10bc50202873e760a76b346bccd941e2574
Merged-In: I1caeb10bc50202873e760a76b346bccd941e2574
This commit is contained in:
James Mattis
2019-10-04 17:46:12 -07:00
parent f9cb43d6eb
commit 201a319860
10 changed files with 249 additions and 55 deletions

View File

@@ -4657,6 +4657,13 @@ package android.net.wifi {
field @Deprecated public byte id;
}
public final class WifiClient implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.net.MacAddress getMacAddress();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiClient> CREATOR;
}
@Deprecated public class WifiConfiguration implements android.os.Parcelable {
method @Deprecated public boolean hasNoInternetAccess();
method @Deprecated public boolean isEphemeral();

View File

@@ -21,6 +21,7 @@ import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.UserManager;
@@ -29,12 +30,14 @@ import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
/**
* Controller used to retrieve information related to a hotspot.
*/
@Singleton
public class HotspotControllerImpl implements HotspotController, WifiManager.SoftApCallback {
@@ -49,10 +52,11 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
private final Context mContext;
private int mHotspotState;
private int mNumConnectedDevices;
private volatile int mNumConnectedDevices;
private boolean mWaitingForTerminalState;
/**
* Controller used to retrieve information related to a hotspot.
*/
@Inject
public HotspotControllerImpl(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
@@ -96,7 +100,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
/**
* Adds {@code callback} to the controller. The controller will update the callback on state
* changes. It will immediately trigger the callback added to notify current state.
* @param callback
*/
@Override
public void addCallback(Callback callback) {
@@ -108,11 +111,13 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
if (mCallbacks.size() == 1) {
mWifiManager.registerSoftApCallback(this, mMainHandler);
} else {
// mWifiManager#registerSoftApCallback triggers a call to onNumClientsChanged
// on the Main Handler. In order to always update the callback on added, we
// make this call when adding callbacks after the first.
// mWifiManager#registerSoftApCallback triggers a call to
// onConnectedClientsChanged on the Main Handler. In order to always update
// the callback on added, we make this call when adding callbacks after the
// first.
mMainHandler.post(() ->
callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices));
callback.onHotspotChanged(isHotspotEnabled(),
mNumConnectedDevices));
}
}
}
@@ -217,8 +222,8 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
}
@Override
public void onNumClientsChanged(int numConnectedDevices) {
mNumConnectedDevices = numConnectedDevices;
public void onConnectedClientsChanged(List<WifiClient> clients) {
mNumConnectedDevices = clients.size();
fireHotspotChangedCallback();
}
}

View File

@@ -42,6 +42,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import java.util.ArrayList;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -67,7 +69,8 @@ public class HotspotControllerImplTest extends SysuiTestCase {
mContext.addMockSystemService(WifiManager.class, mWifiManager);
doAnswer((InvocationOnMock invocation) -> {
((WifiManager.SoftApCallback) invocation.getArgument(0)).onNumClientsChanged(1);
((WifiManager.SoftApCallback) invocation.getArgument(0))
.onConnectedClientsChanged(new ArrayList<>());
return null;
}).when(mWifiManager).registerSoftApCallback(any(WifiManager.SoftApCallback.class),
any(Handler.class));

View File

@@ -16,6 +16,8 @@
package android.net.wifi;
import android.net.wifi.WifiClient;
/**
* Interface for Soft AP callback.
*
@@ -36,9 +38,9 @@ oneway interface ISoftApCallback
void onStateChanged(int state, int failureReason);
/**
* Service to manager callback providing number of connected clients.
* Service to manager callback providing connected client's information.
*
* @param numClients number of connected clients
* @param clients the currently connected clients
*/
void onNumClientsChanged(int numClients);
void onConnectedClientsChanged(in List<WifiClient> clients);
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.wifi;
@JavaOnlyStableParcelable parcelable WifiClient;

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.wifi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.net.MacAddress;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
import java.util.Objects;
/** @hide */
@SystemApi
public final class WifiClient implements Parcelable {
private final MacAddress mMacAddress;
/**
* The mac address of this client.
*/
@NonNull
public MacAddress getMacAddress() {
return mMacAddress;
}
private WifiClient(Parcel in) {
mMacAddress = in.readParcelable(null);
}
/** @hide */
public WifiClient(@NonNull MacAddress macAddress) {
Preconditions.checkNotNull(macAddress, "mMacAddress must not be null.");
this.mMacAddress = macAddress;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelable(mMacAddress, flags);
}
@NonNull
public static final Creator<WifiClient> CREATOR = new Creator<WifiClient>() {
public WifiClient createFromParcel(Parcel in) {
return new WifiClient(in);
}
public WifiClient[] newArray(int size) {
return new WifiClient[size];
}
};
@NonNull
@Override
public String toString() {
return "WifiClient{"
+ "mMacAddress=" + mMacAddress
+ '}';
}
@Override
public boolean equals(@NonNull Object o) {
if (this == o) return true;
if (!(o instanceof WifiClient)) return false;
WifiClient client = (WifiClient) o;
return mMacAddress.equals(client.mMacAddress);
}
@Override
public int hashCode() {
return Objects.hash(mMacAddress);
}
}

View File

@@ -3125,21 +3125,22 @@ public class WifiManager {
/**
* Called when soft AP state changes.
*
* @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
* @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
* @param failureReason reason when in failed state. One of
* {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL}
* {@link #SAP_START_FAILURE_GENERAL},
* {@link #SAP_START_FAILURE_NO_CHANNEL}
*/
public abstract void onStateChanged(@WifiApState int state,
void onStateChanged(@WifiApState int state,
@SapStartFailure int failureReason);
/**
* Called when number of connected clients to soft AP changes.
* Called when the connected clients to soft AP changes.
*
* @param numClients number of connected clients
* @param clients the currently connected clients
*/
public abstract void onNumClientsChanged(int numClients);
void onConnectedClientsChanged(@NonNull List<WifiClient> clients);
}
/**
@@ -3162,18 +3163,21 @@ public class WifiManager {
Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state
+ ", failureReason=" + failureReason);
}
mHandler.post(() -> {
mCallback.onStateChanged(state, failureReason);
});
}
@Override
public void onNumClientsChanged(int numClients) {
public void onConnectedClientsChanged(List<WifiClient> clients) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "SoftApCallbackProxy: onNumClientsChanged: numClients=" + numClients);
Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsChanged: clients="
+ clients.size() + " clients");
}
mHandler.post(() -> {
mCallback.onNumClientsChanged(numClients);
mCallback.onConnectedClientsChanged(clients);
});
}
}

View File

@@ -49,6 +49,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
core-test-rules \
guava \
mockito-target-minus-junit4 \
net-tests-utils \
frameworks-base-testutils \
truth-prebuilt \

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.wifi;
import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import android.net.MacAddress;
import androidx.test.filters.SmallTest;
import org.junit.Test;
/**
* Unit tests for {@link android.net.wifi.WifiClient}.
*/
@SmallTest
public class WifiClientTest {
private static final String INTERFACE_NAME = "wlan0";
private static final String MAC_ADDRESS_STRING = "00:0a:95:9d:68:16";
private static final MacAddress MAC_ADDRESS = MacAddress.fromString(MAC_ADDRESS_STRING);
/**
* Verify parcel write/read with WifiClient.
*/
@Test
public void testWifiClientParcelWriteRead() throws Exception {
WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
assertParcelSane(writeWifiClient, 1);
}
/**
* Verify equals with WifiClient.
*/
@Test
public void testWifiClientEquals() throws Exception {
WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
WifiClient writeWifiClientEquals = new WifiClient(MAC_ADDRESS);
assertEquals(writeWifiClient, writeWifiClientEquals);
assertEquals(writeWifiClient.hashCode(), writeWifiClientEquals.hashCode());
assertFieldCountEquals(1, WifiClient.class);
}
/**
* Verify not-equals with WifiClient.
*/
@Test
public void testWifiClientNotEquals() throws Exception {
final MacAddress macAddressNotEquals = MacAddress.fromString("00:00:00:00:00:00");
WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
WifiClient writeWifiClientNotEquals = new WifiClient(macAddressNotEquals);
assertNotEquals(writeWifiClient, writeWifiClientNotEquals);
assertNotEquals(writeWifiClient.hashCode(), writeWifiClientNotEquals.hashCode());
}
}

View File

@@ -101,8 +101,7 @@ public class WifiManagerTest {
private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
@Mock Context mContext;
@Mock
android.net.wifi.IWifiManager mWifiService;
@Mock android.net.wifi.IWifiManager mWifiService;
@Mock ApplicationInfo mApplicationInfo;
@Mock WifiConfiguration mApConfig;
@Mock IBinder mAppBinder;
@@ -118,7 +117,8 @@ public class WifiManagerTest {
private Messenger mWifiServiceMessenger;
final ArgumentCaptor<Messenger> mMessengerCaptor = ArgumentCaptor.forClass(Messenger.class);
@Before public void setUp() throws Exception {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
mHandler = spy(new Handler(mLooper.getLooper()));
@@ -214,7 +214,7 @@ public class WifiManagerTest {
@Test
public void testCreationOfLocalOnlyHotspotSubscription() throws Exception {
try (WifiManager.LocalOnlyHotspotSubscription sub =
mWifiManager.new LocalOnlyHotspotSubscription()) {
mWifiManager.new LocalOnlyHotspotSubscription()) {
sub.close();
}
}
@@ -757,17 +757,17 @@ public class WifiManagerTest {
* Verify client-provided callback is being called through callback proxy
*/
@Test
public void softApCallbackProxyCallsOnNumClientsChanged() throws Exception {
public void softApCallbackProxyCallsOnConnectedClientsChanged() throws Exception {
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
final int testNumClients = 3;
callbackCaptor.getValue().onNumClientsChanged(testNumClients);
final List<WifiClient> testClients = new ArrayList();
callbackCaptor.getValue().onConnectedClientsChanged(testClients);
mLooper.dispatchAll();
verify(mSoftApCallback).onNumClientsChanged(testNumClients);
verify(mSoftApCallback).onConnectedClientsChanged(testClients);
}
/*
@@ -781,14 +781,14 @@ public class WifiManagerTest {
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
final int testNumClients = 5;
final List<WifiClient> testClients = new ArrayList();
callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0);
callbackCaptor.getValue().onNumClientsChanged(testNumClients);
callbackCaptor.getValue().onConnectedClientsChanged(testClients);
callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
mLooper.dispatchAll();
verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0);
verify(mSoftApCallback).onNumClientsChanged(testNumClients);
verify(mSoftApCallback).onConnectedClientsChanged(testClients);
verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
}
@@ -1047,8 +1047,8 @@ public class WifiManagerTest {
verifyNoMoreInteractions(mWifiService);
}
/**
i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Verify that a call to cancel WPS immediately returns a failure.
*/
@Test
public void testCancelWpsImmediatelyFailsWithCallback() {
@@ -1343,7 +1343,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Verify getting the factory MAC address.
* @throws Exception
*/
@Test
public void testGetFactoryMacAddress() throws Exception {
@@ -1390,7 +1389,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of isEnhancedOpenSupported
* @throws Exception
*/
@Test
public void testIsEnhancedOpenSupported() throws Exception {
@@ -1404,7 +1402,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of isWpa3SaeSupported
* @throws Exception
*/
@Test
public void testIsWpa3SaeSupported() throws Exception {
@@ -1418,7 +1415,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of isWpa3SuiteBSupported
* @throws Exception
*/
@Test
public void testIsWpa3SuiteBSupported() throws Exception {
@@ -1432,7 +1428,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of isEasyConnectSupported
* @throws Exception
*/
@Test
public void testIsEasyConnectSupported() throws Exception {
@@ -1446,7 +1441,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#addNetwork(WifiConfiguration)}
* @throws Exception
*/
@Test
public void testAddNetwork() throws Exception {
@@ -1463,7 +1457,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#addNetwork(WifiConfiguration)}
* @throws Exception
*/
@Test
public void testUpdateNetwork() throws Exception {
@@ -1485,7 +1478,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#enableNetwork(int, boolean)}
* @throws Exception
*/
@Test
public void testEnableNetwork() throws Exception {
@@ -1497,7 +1489,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#disableNetwork(int)}
* @throws Exception
*/
@Test
public void testDisableNetwork() throws Exception {
@@ -1509,7 +1500,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#disconnect()}
* @throws Exception
*/
@Test
public void testDisconnect() throws Exception {
@@ -1520,7 +1510,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#reconnect()}
* @throws Exception
*/
@Test
public void testReconnect() throws Exception {
@@ -1531,7 +1520,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#reassociate()}
* @throws Exception
*/
@Test
public void testReassociate() throws Exception {
@@ -1542,7 +1530,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#getSupportedFeatures()}
* @throws Exception
*/
@Test
public void testGetSupportedFeatures() throws Exception {
@@ -1569,7 +1556,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()}
* @throws Exception
*/
@Test
public void testGetControllerActivityEnergyInfo() throws Exception {
@@ -1582,7 +1568,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#getConnectionInfo()}
* @throws Exception
*/
@Test
public void testGetConnectionInfo() throws Exception {
@@ -1594,7 +1579,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#isDualModeSupported()} ()}
* @throws Exception
*/
@Test
public void testIsDualModeSupported() throws Exception {
@@ -1605,7 +1589,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#isDualBandSupported()}
* @throws Exception
*/
@Test
public void testIsDualBandSupported() throws Exception {
@@ -1616,7 +1599,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#getDhcpInfo()}
* @throws Exception
*/
@Test
public void testGetDhcpInfo() throws Exception {
@@ -1629,7 +1611,6 @@ i * Verify that a call to cancel WPS immediately returns a failure.
/**
* Test behavior of {@link WifiManager#setWifiEnabled(boolean)}
* @throws Exception
*/
@Test
public void testSetWifiEnabled() throws Exception {