changes the API setChannelMaxPowers from hide API to system API
This CL changes the hiden API `setChannelMaxPowers` to system API to allow the privilege app to set the max power of each Thread channel. Bug: b/346686506 Test: atest CtsThreadNetworkTestCases Change-Id: I1089a4a315971c3bca8ec688a02143ddec93d039
This commit is contained in:
parent
da723a059e
commit
5bbfd91b04
9 changed files with 105 additions and 207 deletions
|
|
@ -15,4 +15,12 @@ flag {
|
|||
namespace: "thread_network"
|
||||
description: "Controls whether the Android Thread configuration is enabled"
|
||||
bug: "342519412"
|
||||
}
|
||||
}
|
||||
|
||||
flag {
|
||||
name: "channel_max_powers_enabled"
|
||||
is_exported: true
|
||||
namespace: "thread_network"
|
||||
description: "Controls whether the Android Thread setting max power of channel feature is enabled"
|
||||
bug: "346686506"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -516,6 +516,7 @@ package android.net.thread {
|
|||
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_NETWORK_STATE, "android.permission.THREAD_NETWORK_PRIVILEGED"}) public void registerOperationalDatasetCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.thread.ThreadNetworkController.OperationalDatasetCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.thread.ThreadNetworkController.StateCallback);
|
||||
method @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void scheduleMigration(@NonNull android.net.thread.PendingOperationalDataset, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.net.thread.ThreadNetworkException>);
|
||||
method @FlaggedApi("com.android.net.thread.flags.channel_max_powers_enabled") @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void setChannelMaxPowers(@NonNull @Size(min=1) android.util.SparseIntArray, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.net.thread.ThreadNetworkException>);
|
||||
method @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void setEnabled(boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.net.thread.ThreadNetworkException>);
|
||||
method @FlaggedApi("com.android.net.thread.flags.configuration_enabled") @RequiresPermission(android.Manifest.permission.THREAD_NETWORK_PRIVILEGED) public void unregisterConfigurationCallback(@NonNull java.util.function.Consumer<android.net.thread.ThreadConfiguration>);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_NETWORK_STATE, "android.permission.THREAD_NETWORK_PRIVILEGED"}) public void unregisterOperationalDatasetCallback(@NonNull android.net.thread.ThreadNetworkController.OperationalDatasetCallback);
|
||||
|
|
@ -525,6 +526,7 @@ package android.net.thread {
|
|||
field public static final int DEVICE_ROLE_LEADER = 4; // 0x4
|
||||
field public static final int DEVICE_ROLE_ROUTER = 3; // 0x3
|
||||
field public static final int DEVICE_ROLE_STOPPED = 0; // 0x0
|
||||
field public static final int MAX_POWER_CHANNEL_DISABLED = -2147483648; // 0x80000000
|
||||
field public static final int STATE_DISABLED = 0; // 0x0
|
||||
field public static final int STATE_DISABLING = 2; // 0x2
|
||||
field public static final int STATE_ENABLED = 1; // 0x1
|
||||
|
|
@ -557,6 +559,7 @@ package android.net.thread {
|
|||
field public static final int ERROR_UNAVAILABLE = 4; // 0x4
|
||||
field public static final int ERROR_UNKNOWN = 11; // 0xb
|
||||
field public static final int ERROR_UNSUPPORTED_CHANNEL = 7; // 0x7
|
||||
field public static final int ERROR_UNSUPPORTED_FEATURE = 13; // 0xd
|
||||
}
|
||||
|
||||
@FlaggedApi("com.android.net.thread.flags.thread_enabled") public final class ThreadNetworkManager {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import android.annotation.NonNull;
|
|||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.Size;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Binder;
|
||||
import android.os.OutcomeReceiver;
|
||||
|
|
@ -102,11 +103,12 @@ public final class ThreadNetworkController {
|
|||
/** Thread standard version 1.3. */
|
||||
public static final int THREAD_VERSION_1_3 = 4;
|
||||
|
||||
/** Minimum value of max power in unit of 0.01dBm. @hide */
|
||||
private static final int POWER_LIMITATION_MIN = -32768;
|
||||
|
||||
/** Maximum value of max power in unit of 0.01dBm. @hide */
|
||||
private static final int POWER_LIMITATION_MAX = 32767;
|
||||
/** The value of max power to disable the Thread channel. */
|
||||
// This constant can never change. It has "max" in the name not because it indicates
|
||||
// maximum power, but because it's passed to an API that sets the maximum power to
|
||||
// disabled the Thread channel.
|
||||
@SuppressLint("MinMaxConstant")
|
||||
public static final int MAX_POWER_CHANNEL_DISABLED = Integer.MIN_VALUE;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
|
@ -704,6 +706,10 @@ public final class ThreadNetworkController {
|
|||
/**
|
||||
* Sets max power of each channel.
|
||||
*
|
||||
* <p>This method sets the max power for the given channel. The platform sets the actual
|
||||
* output power to be less than or equal to the {@code channelMaxPowers} and as close as
|
||||
* possible to the {@code channelMaxPowers}.
|
||||
*
|
||||
* <p>If not set, the default max power is set by the Thread HAL service or the Thread radio
|
||||
* chip firmware.
|
||||
*
|
||||
|
|
@ -712,22 +718,27 @@ public final class ThreadNetworkController {
|
|||
* OutcomeReceiver#onError} will be called with a specific error:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link ThreadNetworkException#ERROR_UNSUPPORTED_OPERATION} the operation is no
|
||||
* supported by the platform.
|
||||
* <li>{@link ThreadNetworkException#ERROR_UNSUPPORTED_FEATURE} the feature is not supported
|
||||
* by the platform.
|
||||
* </ul>
|
||||
*
|
||||
* @param channelMaxPowers SparseIntArray (key: channel, value: max power) consists of channel
|
||||
* and corresponding max power. Valid channel values should be between {@link
|
||||
* ActiveOperationalDataset#CHANNEL_MIN_24_GHZ} and {@link
|
||||
* ActiveOperationalDataset#CHANNEL_MAX_24_GHZ}. The unit of the max power is 0.01dBm. Max
|
||||
* power values should be between INT16_MIN (-32768) and INT16_MAX (32767). If the max power
|
||||
* is set to INT16_MAX, the corresponding channel is not supported.
|
||||
* ActiveOperationalDataset#CHANNEL_MAX_24_GHZ}. The unit of the max power is 0.01dBm. For
|
||||
* example, 1000 means 0.01W and 2000 means 0.1W. If the power value of
|
||||
* {@code channelMaxPowers} is lower than the minimum output power supported by the
|
||||
* platform, the output power will be set to the minimum output power supported by the
|
||||
* platform. If the power value of {@code channelMaxPowers} is higher than the maximum
|
||||
* output power supported by the platform, the output power will be set to the maximum
|
||||
* output power supported by the platform. If the power value of {@code channelMaxPowers}
|
||||
* is set to {@link #MAX_POWER_CHANNEL_DISABLED}, the corresponding channel is disabled.
|
||||
* @param executor the executor to execute {@code receiver}.
|
||||
* @param receiver the receiver to receive the result of this operation.
|
||||
* @throws IllegalArgumentException if the size of {@code channelMaxPowers} is smaller than 1,
|
||||
* or invalid channel or max power is configured.
|
||||
* @hide
|
||||
*/
|
||||
@FlaggedApi(Flags.FLAG_CHANNEL_MAX_POWERS_ENABLED)
|
||||
@RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED")
|
||||
public final void setChannelMaxPowers(
|
||||
@NonNull @Size(min = 1) SparseIntArray channelMaxPowers,
|
||||
|
|
@ -756,19 +767,6 @@ public final class ThreadNetworkController {
|
|||
+ ActiveOperationalDataset.CHANNEL_MAX_24_GHZ
|
||||
+ "]");
|
||||
}
|
||||
|
||||
if ((maxPower < POWER_LIMITATION_MIN) || (maxPower > POWER_LIMITATION_MAX)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Channel power ({channel: "
|
||||
+ channel
|
||||
+ ", maxPower: "
|
||||
+ maxPower
|
||||
+ "}) exceeds allowed range ["
|
||||
+ POWER_LIMITATION_MIN
|
||||
+ ", "
|
||||
+ POWER_LIMITATION_MAX
|
||||
+ "]");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -141,16 +141,14 @@ public class ThreadNetworkException extends Exception {
|
|||
public static final int ERROR_THREAD_DISABLED = 12;
|
||||
|
||||
/**
|
||||
* The operation failed because it is not supported by the platform. For example, some platforms
|
||||
* may not support setting the target power of each channel. The caller should not retry and may
|
||||
* return an error to the user.
|
||||
*
|
||||
* @hide
|
||||
* The operation failed because the feature is not supported by the platform. For example, some
|
||||
* platforms may not support setting the target power of each channel. The caller should not
|
||||
* retry and may return an error to the user.
|
||||
*/
|
||||
public static final int ERROR_UNSUPPORTED_OPERATION = 13;
|
||||
public static final int ERROR_UNSUPPORTED_FEATURE = 13;
|
||||
|
||||
private static final int ERROR_MIN = ERROR_INTERNAL_ERROR;
|
||||
private static final int ERROR_MAX = ERROR_UNSUPPORTED_OPERATION;
|
||||
private static final int ERROR_MAX = ERROR_UNSUPPORTED_FEATURE;
|
||||
|
||||
private final int mErrorCode;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import static android.net.thread.ThreadNetworkException.ERROR_RESPONSE_BAD_FORMA
|
|||
import static android.net.thread.ThreadNetworkException.ERROR_THREAD_DISABLED;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_TIMEOUT;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_CHANNEL;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_OPERATION;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_FEATURE;
|
||||
import static android.net.thread.ThreadNetworkManager.DISALLOW_THREAD_NETWORK;
|
||||
import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
|
||||
|
||||
|
|
@ -1055,7 +1055,7 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
|
|||
case OT_ERROR_BUSY:
|
||||
return ERROR_BUSY;
|
||||
case OT_ERROR_NOT_IMPLEMENTED:
|
||||
return ERROR_UNSUPPORTED_OPERATION;
|
||||
return ERROR_UNSUPPORTED_FEATURE;
|
||||
case OT_ERROR_NO_BUFS:
|
||||
return ERROR_RESOURCE_EXHAUSTED;
|
||||
case OT_ERROR_PARSE:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ android_test {
|
|||
static_libs: [
|
||||
"androidx.test.ext.junit",
|
||||
"compatibility-device-util-axt",
|
||||
"com.android.net.thread.flags-aconfig-java",
|
||||
"ctstestrunner-axt",
|
||||
"guava",
|
||||
"guava-android-testlib",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import static android.net.thread.ThreadNetworkException.ERROR_ABORTED;
|
|||
import static android.net.thread.ThreadNetworkException.ERROR_FAILED_PRECONDITION;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_REJECTED_BY_PEER;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_THREAD_DISABLED;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_FEATURE;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
|
|
@ -70,12 +71,15 @@ import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
|
|||
import android.os.Build;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.platform.test.annotations.RequiresFlagsEnabled;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.filters.LargeTest;
|
||||
|
||||
import com.android.net.module.util.ArrayTrackRecord;
|
||||
import com.android.net.thread.flags.Flags;
|
||||
import com.android.testutils.FunctionalUtils.ThrowingRunnable;
|
||||
|
||||
import org.junit.After;
|
||||
|
|
@ -116,11 +120,20 @@ public class ThreadNetworkControllerTest {
|
|||
private static final int SET_CONFIGURATION_TIMEOUT_MILLIS = 1_000;
|
||||
private static final int SERVICE_DISCOVERY_TIMEOUT_MILLIS = 30_000;
|
||||
private static final int SERVICE_LOST_TIMEOUT_MILLIS = 20_000;
|
||||
private static final int VALID_POWER = 32_767;
|
||||
private static final int VALID_CHANNEL = 20;
|
||||
private static final int INVALID_CHANNEL = 10;
|
||||
private static final String MESHCOP_SERVICE_TYPE = "_meshcop._udp";
|
||||
private static final String THREAD_NETWORK_PRIVILEGED =
|
||||
"android.permission.THREAD_NETWORK_PRIVILEGED";
|
||||
private static final ThreadConfiguration DEFAULT_CONFIG =
|
||||
new ThreadConfiguration.Builder().build();
|
||||
private static final SparseIntArray CHANNEL_MAX_POWERS =
|
||||
new SparseIntArray() {
|
||||
{
|
||||
put(VALID_CHANNEL, VALID_POWER);
|
||||
}
|
||||
};
|
||||
|
||||
@Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
|
||||
|
||||
|
|
@ -1460,4 +1473,52 @@ public class ThreadNetworkControllerTest {
|
|||
@Override
|
||||
public void onServiceInfoCallbackUnregistered() {}
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled({Flags.FLAG_CHANNEL_MAX_POWERS_ENABLED})
|
||||
public void setChannelMaxPowers_withPrivilegedPermission_success() throws Exception {
|
||||
CompletableFuture<Void> powerFuture = new CompletableFuture<>();
|
||||
|
||||
runAsShell(
|
||||
THREAD_NETWORK_PRIVILEGED,
|
||||
() ->
|
||||
mController.setChannelMaxPowers(
|
||||
CHANNEL_MAX_POWERS, mExecutor, newOutcomeReceiver(powerFuture)));
|
||||
|
||||
try {
|
||||
assertThat(powerFuture.get()).isNull();
|
||||
} catch (ExecutionException exception) {
|
||||
ThreadNetworkException thrown = (ThreadNetworkException) exception.getCause();
|
||||
assertThat(thrown.getErrorCode()).isEqualTo(ERROR_UNSUPPORTED_FEATURE);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled({Flags.FLAG_CHANNEL_MAX_POWERS_ENABLED})
|
||||
public void setChannelMaxPowers_withoutPrivilegedPermission_throwsSecurityException()
|
||||
throws Exception {
|
||||
dropAllPermissions();
|
||||
|
||||
assertThrows(
|
||||
SecurityException.class,
|
||||
() -> mController.setChannelMaxPowers(CHANNEL_MAX_POWERS, mExecutor, v -> {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresFlagsEnabled({Flags.FLAG_CHANNEL_MAX_POWERS_ENABLED})
|
||||
public void setChannelMaxPowers_invalidChannel_throwsIllegalArgumentException() {
|
||||
final SparseIntArray INVALID_CHANNEL_ARRAY =
|
||||
new SparseIntArray() {
|
||||
{
|
||||
put(INVALID_CHANNEL, VALID_POWER);
|
||||
}
|
||||
};
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> mController.setChannelMaxPowers(new SparseIntArray(), mExecutor, v -> {}));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> mController.setChannelMaxPowers(INVALID_CHANNEL_ARRAY, mExecutor, v -> {}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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.thread;
|
||||
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_OPERATION;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.testutils.TestPermissionUtil.runAsShell;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/** Tests for hide methods of {@link ThreadNetworkController}. */
|
||||
@LargeTest
|
||||
@RequiresThreadFeature
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ThreadNetworkControllerTest {
|
||||
private static final int VALID_POWER = 32_767;
|
||||
private static final int INVALID_POWER = 32_768;
|
||||
private static final int VALID_CHANNEL = 20;
|
||||
private static final int INVALID_CHANNEL = 10;
|
||||
private static final String THREAD_NETWORK_PRIVILEGED =
|
||||
"android.permission.THREAD_NETWORK_PRIVILEGED";
|
||||
|
||||
private static final SparseIntArray CHANNEL_MAX_POWERS =
|
||||
new SparseIntArray() {
|
||||
{
|
||||
put(20, 32767);
|
||||
}
|
||||
};
|
||||
|
||||
@Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private ExecutorService mExecutor;
|
||||
private ThreadNetworkController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mController =
|
||||
mContext.getSystemService(ThreadNetworkManager.class)
|
||||
.getAllThreadNetworkControllers()
|
||||
.get(0);
|
||||
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
dropAllPermissions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChannelMaxPowers_withPrivilegedPermission_success() throws Exception {
|
||||
CompletableFuture<Void> powerFuture = new CompletableFuture<>();
|
||||
|
||||
runAsShell(
|
||||
THREAD_NETWORK_PRIVILEGED,
|
||||
() ->
|
||||
mController.setChannelMaxPowers(
|
||||
CHANNEL_MAX_POWERS, mExecutor, newOutcomeReceiver(powerFuture)));
|
||||
|
||||
try {
|
||||
assertThat(powerFuture.get()).isNull();
|
||||
} catch (ExecutionException exception) {
|
||||
ThreadNetworkException thrown = (ThreadNetworkException) exception.getCause();
|
||||
assertThat(thrown.getErrorCode()).isEqualTo(ERROR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChannelMaxPowers_withoutPrivilegedPermission_throwsSecurityException()
|
||||
throws Exception {
|
||||
dropAllPermissions();
|
||||
|
||||
assertThrows(
|
||||
SecurityException.class,
|
||||
() -> mController.setChannelMaxPowers(CHANNEL_MAX_POWERS, mExecutor, v -> {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChannelMaxPowers_emptyChannelMaxPower_throwsIllegalArgumentException() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> mController.setChannelMaxPowers(new SparseIntArray(), mExecutor, v -> {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChannelMaxPowers_invalidChannel_throwsIllegalArgumentException() {
|
||||
final SparseIntArray INVALID_CHANNEL_ARRAY =
|
||||
new SparseIntArray() {
|
||||
{
|
||||
put(INVALID_CHANNEL, VALID_POWER);
|
||||
}
|
||||
};
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> mController.setChannelMaxPowers(INVALID_CHANNEL_ARRAY, mExecutor, v -> {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChannelMaxPowers_invalidPower_throwsIllegalArgumentException() {
|
||||
final SparseIntArray INVALID_POWER_ARRAY =
|
||||
new SparseIntArray() {
|
||||
{
|
||||
put(VALID_CHANNEL, INVALID_POWER);
|
||||
}
|
||||
};
|
||||
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> mController.setChannelMaxPowers(INVALID_POWER_ARRAY, mExecutor, v -> {}));
|
||||
}
|
||||
|
||||
private static void dropAllPermissions() {
|
||||
getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
|
||||
}
|
||||
|
||||
private static <V> OutcomeReceiver<V, ThreadNetworkException> newOutcomeReceiver(
|
||||
CompletableFuture<V> future) {
|
||||
return new OutcomeReceiver<V, ThreadNetworkException>() {
|
||||
@Override
|
||||
public void onResult(V result) {
|
||||
future.complete(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ThreadNetworkException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ package android.net.thread;
|
|||
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_CHILD;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNAVAILABLE;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_CHANNEL;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_OPERATION;
|
||||
import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_FEATURE;
|
||||
import static android.os.Process.SYSTEM_UID;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
|
|
@ -394,7 +394,7 @@ public final class ThreadNetworkControllerTest {
|
|||
doAnswer(
|
||||
invoke -> {
|
||||
getSetChannelMaxPowersReceiver(invoke)
|
||||
.onError(ERROR_UNSUPPORTED_OPERATION, "");
|
||||
.onError(ERROR_UNSUPPORTED_FEATURE, "");
|
||||
return null;
|
||||
})
|
||||
.when(mMockService)
|
||||
|
|
|
|||
Loading…
Reference in a new issue