Merge "[DPP R2] Added support for DPP R2 events"

This commit is contained in:
Hai Shalom
2019-12-20 19:25:15 +00:00
committed by Android (Google) Code Review
6 changed files with 320 additions and 23 deletions

View File

@@ -5392,11 +5392,15 @@ package android.net.wifi {
ctor public EasyConnectStatusCallback();
method public abstract void onConfiguratorSuccess(int);
method public abstract void onEnrolleeSuccess(int);
method public abstract void onFailure(int);
method public void onFailure(int);
method public void onFailure(int, @Nullable String, @NonNull android.util.SparseArray<int[]>, @NonNull int[]);
method public abstract void onProgress(int);
field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
field public static final int EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK = -10; // 0xfffffff6
field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
field public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION = -11; // 0xfffffff5
field public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12; // 0xfffffff4
field public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7; // 0xfffffff9
field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
@@ -5404,7 +5408,10 @@ package android.net.wifi {
field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3; // 0x3
field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2; // 0x2
field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1; // 0x1
field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
}

View File

@@ -17,32 +17,46 @@
package android.net.wifi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Handler;
import android.util.SparseArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
/**
* Easy Connect (DPP) Status Callback. Use this callback to get status updates (success, failure,
* progress) from the Easy Connect operation started with
* {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String,
* int, int, Handler, EasyConnectStatusCallback)} or
* {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
* Handler, EasyConnectStatusCallback)}
* {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Executor,
* EasyConnectStatusCallback)} or {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
* Executor, EasyConnectStatusCallback)}
*
* @hide
*/
@SystemApi
public abstract class EasyConnectStatusCallback {
/**
* Easy Connect Success event: Configuration sent (Configurator mode).
* Easy Connect R1 Success event: Configuration sent (Configurator mode). This is the last
* and final Easy Connect event when either the local device or remote device implement R1.
* If both devices implement R2, this event will never be received, and the
* {@link EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED} will be received.
*/
public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
/**
* East Connect R2 Success event: Configuration applied by Enrollee (Configurator mode).
* This is the last and final Easy Connect event when both the local device and remote device
* implement R2. If either the local device or remote device implement R1, this event will never
* be received, and the {@link EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT} will be received.
*/
public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1;
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_SUCCESS_"}, value = {
EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectSuccessStatusCode {
@@ -58,10 +72,22 @@ public abstract class EasyConnectStatusCallback {
*/
public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1;
/**
* Easy Connect R2 Progress event: Configuration sent to Enrollee, waiting for response
*/
public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2;
/**
* Easy Connect R2 Progress event: Configuration accepted by Enrollee, waiting for response
*/
public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3;
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_PROGRESS_"}, value = {
EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING,
EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE,
EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectProgressStatusCode {
@@ -114,6 +140,20 @@ public abstract class EasyConnectStatusCallback {
*/
public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9;
/**
* Easy Connect R2 Failure event: Enrollee cannot find the network.
*/
public static final int EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK = -10;
/**
* Easy Connect R2 Failure event: Enrollee failed to authenticate with the network.
*/
public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION = -11;
/**
* Easy Connect R2 Failure event: Enrollee rejected the configuration.
*/
public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12;
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
@@ -126,6 +166,9 @@ public abstract class EasyConnectStatusCallback {
EASY_CONNECT_EVENT_FAILURE_GENERIC,
EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectFailureStatusCode {
@@ -138,9 +181,8 @@ public abstract class EasyConnectStatusCallback {
* current Easy Connect
* session, and no further callbacks will be called. This callback is the successful outcome
* of a Easy Connect flow starting with
* {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
* Handler,
* EasyConnectStatusCallback)}.
* {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String, Executor,
* EasyConnectStatusCallback)} .
*
* @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
*/
@@ -148,13 +190,11 @@ public abstract class EasyConnectStatusCallback {
/**
* Called when a Easy Connect success event takes place, except for when configuration is
* received from
* an external Configurator. The callback onSuccessConfigReceived will be used in this case.
* This callback marks the successful end of the current Easy Connect session, and no further
* callbacks will be called. This callback is the successful outcome of a Easy Connect flow
* starting with
* {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Handler,
* EasyConnectStatusCallback)}.
* received from an external Configurator. The callback onSuccessConfigReceived will be used in
* this case. This callback marks the successful end of the current Easy Connect session, and no
* further callbacks will be called. This callback is the successful outcome of a Easy Connect
* flow starting with {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int,
* int, Executor,EasyConnectStatusCallback)}.
*
* @param code Easy Connect success status code.
*/
@@ -162,12 +202,36 @@ public abstract class EasyConnectStatusCallback {
/**
* Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
* end of the
* current Easy Connect session, and no further callbacks will be called.
* end of the current Easy Connect session, and no further callbacks will be called.
*
* @param code Easy Connect failure status code.
*/
public abstract void onFailure(@EasyConnectFailureStatusCode int code);
public void onFailure(@EasyConnectFailureStatusCode int code) {}
/**
* Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
* end of the current Easy Connect session, and no further callbacks will be called.
*
* Note: Easy Connect (DPP) R2, provides additional details for the Configurator when the
* remote Enrollee is unable to connect to a network. The ssid, channelList and bandList
* inputs are initialized only for the EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK failure
* code, and the ssid and bandList are initialized for the
* EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION failure code.
*
* @param code Easy Connect failure status code.
* @param ssid SSID of the network the Enrollee tried to connect to.
* @param channelListArray List of Global Operating classes and channel sets the Enrollee used
* to scan to find the network, see the "DPP Connection Status Object"
* section in the specification for the format, and Table E-4 in
* IEEE Std 802.11-2016 - Global operating classes for more details.
* @param operatingClassArray Array of bands the Enrollee supports as expressed as the Global
* Operating Class, see Table E-4 in IEEE Std 802.11-2016 - Global
* operating classes.
*/
public void onFailure(@EasyConnectFailureStatusCode int code, @Nullable String ssid,
@NonNull SparseArray<int[]> channelListArray, @NonNull int[] operatingClassArray) {
onFailure(code);
}
/**
* Called when Easy Connect events that indicate progress take place. Can be used by UI elements

View File

@@ -38,7 +38,7 @@ oneway interface IDppCallback
/**
* Called when DPP Failure events take place.
*/
void onFailure(int status);
void onFailure(int status, String ssid, String channelList, in int[] bandArray);
/**
* Called when DPP events that indicate progress take place. Can be used by UI elements

View File

@@ -54,6 +54,7 @@ import android.text.TextUtils;
import android.util.CloseGuard;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -70,6 +71,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Executor;
/**
@@ -5177,6 +5179,7 @@ public class WifiManager {
@Override
public void onSuccessConfigReceived(int newNetworkId) {
Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
});
@@ -5185,22 +5188,28 @@ public class WifiManager {
@Override
public void onSuccess(int status) {
Log.d(TAG, "Easy Connect onSuccess callback");
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onConfiguratorSuccess(status);
});
}
@Override
public void onFailure(int status) {
public void onFailure(int status, String ssid, String channelList,
int[] operatingClassArray) {
Log.d(TAG, "Easy Connect onFailure callback");
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onFailure(status);
SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
operatingClassArray);
});
}
@Override
public void onProgress(int status) {
Log.d(TAG, "Easy Connect onProgress callback");
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onProgress(status);
});
@@ -5532,4 +5541,77 @@ public class WifiManager {
throw e.rethrowFromSystemServer();
}
}
/**
* Parse the list of channels the DPP enrollee reports when it fails to find an AP.
*
* @param channelList List of channels in the format defined in the DPP specification.
* @return A parsed sparse array, where the operating class is the key.
* @hide
*/
@VisibleForTesting
public static SparseArray<int[]> parseDppChannelList(String channelList) {
SparseArray<int[]> channelListArray = new SparseArray<>();
if (TextUtils.isEmpty(channelList)) {
return channelListArray;
}
StringTokenizer str = new StringTokenizer(channelList, ",");
String classStr = null;
List<Integer> channelsInClass = new ArrayList<>();
try {
while (str.hasMoreElements()) {
String cur = str.nextToken();
/**
* Example for a channel list:
*
* 81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48,118/52,56,60,64,121/100,104,108,112,
* 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
*
* Detect operating class by the delimiter of '/' and use a string tokenizer with
* ',' as a delimiter.
*/
int classDelim = cur.indexOf('/');
if (classDelim != -1) {
if (classStr != null) {
// Store the last channel array in the sparse array, where the operating
// class is the key (as an integer).
int[] channelsArray = new int[channelsInClass.size()];
for (int i = 0; i < channelsInClass.size(); i++) {
channelsArray[i] = channelsInClass.get(i);
}
channelListArray.append(Integer.parseInt(classStr), channelsArray);
channelsInClass = new ArrayList<>();
}
// Init a new operating class and store the first channel
classStr = cur.substring(0, classDelim);
String channelStr = cur.substring(classDelim + 1);
channelsInClass.add(Integer.parseInt(channelStr));
} else {
if (classStr == null) {
// Invalid format
Log.e(TAG, "Cannot parse DPP channel list");
return new SparseArray<>();
}
channelsInClass.add(Integer.parseInt(cur));
}
}
// Store the last array
if (classStr != null) {
int[] channelsArray = new int[channelsInClass.size()];
for (int i = 0; i < channelsInClass.size(); i++) {
channelsArray[i] = channelsInClass.get(i);
}
channelListArray.append(Integer.parseInt(classStr), channelsArray);
}
return channelListArray;
} catch (NumberFormatException e) {
Log.e(TAG, "Cannot parse DPP channel list");
return new SparseArray<>();
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
/**
* Unit tests for {@link android.net.wifi.EasyConnectStatusCallbackTest}.
*/
@SmallTest
public class EasyConnectStatusCallbackTest {
private EasyConnectStatusCallback mEasyConnectStatusCallback = new EasyConnectStatusCallback() {
@Override
public void onEnrolleeSuccess(int newNetworkId) {
}
@Override
public void onConfiguratorSuccess(int code) {
}
@Override
public void onProgress(int code) {
}
@Override
public void onFailure(int code) {
mOnFailureR1EventReceived = true;
mLastCode = code;
}
};
private boolean mOnFailureR1EventReceived;
private int mLastCode;
@Before
public void setUp() {
mOnFailureR1EventReceived = false;
mLastCode = 0;
}
/**
* Test that the legacy R1 onFailure is called by default if the R2 onFailure is not overridden
* by the app.
*/
@Test
public void testR1OnFailureCalled() {
SparseArray<int[]> channelList = new SparseArray<>();
int[] channelArray = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
channelList.append(81, channelArray);
mEasyConnectStatusCallback.onFailure(
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
"SomeSSID", channelList, new int[] {81});
assertTrue(mOnFailureR1EventReceived);
assertEquals(mLastCode,
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK);
}
}

View File

@@ -89,6 +89,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.connectivity.WifiActivityEnergyInfo;
import android.os.test.TestLooper;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -2089,4 +2090,63 @@ public class WifiManagerTest {
.thenReturn(new Long(~WifiManager.WIFI_FEATURE_WAPI));
assertFalse(mWifiManager.isWapiSupported());
}
/*
* Test that DPP channel list is parsed correctly
*/
@Test
public void testparseDppChannelList() throws Exception {
String channelList = "81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48";
SparseArray<int[]> expectedResult = new SparseArray<>();
expectedResult.append(81, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11});
expectedResult.append(115, new int[]{36, 40, 44, 48});
SparseArray<int[]> result = WifiManager.parseDppChannelList(channelList);
assertEquals(expectedResult.size(), result.size());
int index = 0;
int key;
// Compare the two primitive int arrays
do {
try {
key = result.keyAt(index);
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
break;
}
int[] expected = expectedResult.get(key);
int[] output = result.get(key);
assertEquals(expected.length, output.length);
for (int i = 0; i < output.length; i++) {
assertEquals(expected[i], output[i]);
}
index++;
} while (true);
}
/*
* Test that DPP channel list parser gracefully fails for invalid input
*/
@Test
public void testparseDppChannelListWithInvalidFormats() throws Exception {
String channelList = "1,2,3,4,5,6,7,8,9,10,11,36,40,44,48";
SparseArray<int[]> result = WifiManager.parseDppChannelList(channelList);
assertEquals(result.size(), 0);
channelList = "ajgalskgjalskjg3-09683dh";
result = WifiManager.parseDppChannelList(channelList);
assertEquals(result.size(), 0);
channelList = "13/abc,46////";
result = WifiManager.parseDppChannelList(channelList);
assertEquals(result.size(), 0);
channelList = "11/4,5,13/";
result = WifiManager.parseDppChannelList(channelList);
assertEquals(result.size(), 0);
channelList = "/24,6";
result = WifiManager.parseDppChannelList(channelList);
assertEquals(result.size(), 0);
}
}