blob: 7d5fb2a41a7130ae0f7a1d075a31cae0ec02b2cc [file] [log] [blame]
/*
* Copyright (C) 2020 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.controls.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.service.controls.Control;
import android.service.controls.ControlsProviderService;
import android.service.controls.actions.BooleanAction;
import android.service.controls.actions.CommandAction;
import android.service.controls.actions.ControlAction;
import android.service.controls.actions.FloatAction;
import android.service.controls.actions.ModeAction;
import android.service.controls.templates.ControlTemplate;
import android.service.controls.templates.RangeTemplate;
import android.service.controls.templates.TemperatureControlTemplate;
import android.service.controls.templates.ToggleRangeTemplate;
import android.service.controls.templates.ToggleTemplate;
import android.test.mock.MockContext;
import androidx.test.runner.AndroidJUnit4;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Flow.Publisher;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.function.Consumer;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class CtsControlsServiceTest {
private static final String ACTION_ADD_CONTROL = "android.service.controls.action.ADD_CONTROL";
private static final String EXTRA_CONTROL = "android.service.controls.extra.CONTROL";
private CtsControlsService mControlsService;
@Before
public void setUp() {
mControlsService = new CtsControlsService();
}
@Test
public void testLoadAllAvailable() {
Publisher<Control> publisher = mControlsService.createPublisherForAllAvailable();
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildLight(false, 0.0f)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildLock(false)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildRoutine()).build());
expectedControls.add(new Control.StatelessBuilder(mControlsService.buildThermostat(
TemperatureControlTemplate.MODE_OFF)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildMower(false)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildSwitch(false)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildGate(false)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildCamera(true)).build());
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testLoadSuggested() {
Publisher<Control> publisher = mControlsService.createPublisherForSuggested();
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 3, loadedControls);
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildLight(false, 0.0f)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildLock(false)).build());
expectedControls.add(new Control.StatelessBuilder(
mControlsService.buildRoutine()).build());
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testPublisherForSingleControl() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("mower");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildMower(false));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testPublisherForMultipleControls() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("lock");
idsToLoad.add("light");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildLock(false));
expectedControls.add(mControlsService.buildLight(false, 0.0f));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testBooleanAction() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("switch");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
BooleanAction action = new BooleanAction("action", true);
assertEquals(action.getActionType(), ControlAction.TYPE_BOOLEAN);
mControlsService.performControlAction("switch", action,
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildSwitch(false));
expectedControls.add(mControlsService.buildSwitch(true));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testFloatAction() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("light");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
mControlsService.performControlAction("light", new BooleanAction("action", true),
assertConsumer(ControlAction.RESPONSE_OK));
FloatAction action = new FloatAction("action", 80.0f);
assertEquals(action.getActionType(), ControlAction.TYPE_FLOAT);
mControlsService.performControlAction("light", action,
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildLight(false, 0.0f));
expectedControls.add(mControlsService.buildLight(true, 50.0f));
expectedControls.add(mControlsService.buildLight(true, 80.0f));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testCommandAction() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("routine");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
CommandAction action = new CommandAction("action");
assertEquals(action.getActionType(), ControlAction.TYPE_COMMAND);
mControlsService.performControlAction("routine", action,
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildRoutine());
expectedControls.add(mControlsService.buildRoutine());
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testBooleanActionWithPinChallenge() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("lock");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
mControlsService.performControlAction("lock", new BooleanAction("action", true),
assertConsumer(ControlAction.RESPONSE_CHALLENGE_PIN));
mControlsService.performControlAction("lock", new BooleanAction("action", true, "1234"),
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildLock(false));
expectedControls.add(mControlsService.buildLock(true));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testBooleanActionWithPassphraseChallenge() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("gate");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
mControlsService.performControlAction("gate", new BooleanAction("action", true),
assertConsumer(ControlAction.RESPONSE_CHALLENGE_PASSPHRASE));
mControlsService.performControlAction("gate", new BooleanAction("action", true, "abc123"),
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildGate(false));
expectedControls.add(mControlsService.buildGate(true));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testBooleanActionWithAckChallenge() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("mower");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
mControlsService.performControlAction("mower", new BooleanAction("action", true),
assertConsumer(ControlAction.RESPONSE_CHALLENGE_ACK));
mControlsService.performControlAction("mower", new BooleanAction("action", true, "true"),
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildMower(false));
expectedControls.add(mControlsService.buildMower(true));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testModeAction() {
List<String> idsToLoad = new ArrayList<>();
idsToLoad.add("thermostat");
Publisher<Control> publisher = mControlsService.createPublisherFor(idsToLoad);
List<Control> loadedControls = new ArrayList<>();
subscribe(publisher, 10, loadedControls);
ModeAction action = new ModeAction("action", TemperatureControlTemplate.MODE_COOL);
assertEquals(action.getActionType(), ControlAction.TYPE_MODE);
mControlsService.performControlAction("thermostat", action,
assertConsumer(ControlAction.RESPONSE_OK));
List<Control> expectedControls = new ArrayList<>();
expectedControls.add(mControlsService.buildThermostat(TemperatureControlTemplate.MODE_OFF));
expectedControls.add(mControlsService.buildThermostat(
TemperatureControlTemplate.MODE_COOL));
assertControlsList(loadedControls, expectedControls);
}
@Test
public void testRequestAddControl() {
Resources res = mock(Resources.class);
when(res.getString(anyInt())).thenReturn("");
final ComponentName testComponent = new ComponentName("TestPkg", "TestClass");
final Control control = new Control.StatelessBuilder(mControlsService.buildMower(false))
.build();
Context context = new MockContext() {
public Resources getResources() {
return res;
}
public void sendBroadcast(Intent intent, String receiverPermission) {
assertEquals(intent.getAction(), ACTION_ADD_CONTROL);
assertEquals((ComponentName) intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME),
testComponent);
assertEquals((Control) intent.getParcelableExtra(EXTRA_CONTROL), control);
assertEquals(receiverPermission, "android.permission.BIND_CONTROLS");
}
};
ControlsProviderService.requestAddControl(context, testComponent, control);
}
private Consumer<Integer> assertConsumer(int expectedStatus) {
return (status) -> {
ControlAction.isValidResponse(status);
assertEquals((int) status, expectedStatus);
};
}
private void subscribe(Publisher<Control> publisher, final int request,
final List<Control> addToList) {
publisher.subscribe(new Subscriber<Control>() {
public void onSubscribe(Subscription s) {
s.request(request);
}
public void onNext(Control c) {
addToList.add(c);
}
public void onError(Throwable t) {
throw new IllegalStateException("onError should not be called here");
}
public void onComplete() {
}
});
}
private void assertControlsList(List<Control> actualControls, List<Control> expectedControls) {
assertEquals(actualControls.size(), expectedControls.size());
for (int i = 0; i < actualControls.size(); i++) {
assertControlEquals(actualControls.get(i), expectedControls.get(i));
}
}
private void assertControlEquals(Control c1, Control c2) {
assertEquals(c1.getTitle(), c2.getTitle());
assertEquals(c1.getSubtitle(), c2.getSubtitle());
assertEquals(c1.getStructure(), c2.getStructure());
assertEquals(c1.getZone(), c2.getZone());
assertEquals(c1.getDeviceType(), c2.getDeviceType());
assertEquals(c1.getStatus(), c2.getStatus());
assertEquals(c1.getControlId(), c2.getControlId());
assertEquals(c1.getCustomIcon(), c2.getCustomIcon());
assertEquals(c1.getCustomColor(), c2.getCustomColor());
assertEquals(c1.isAuthRequired(), c2.isAuthRequired());
assertTemplateEquals(c1.getControlTemplate(), c2.getControlTemplate());
}
private void assertTemplateEquals(ControlTemplate ct1, ControlTemplate ct2) {
if (ct1 == null) {
assertNull(ct2);
return;
} else {
assertNotNull(ct2);
}
assertNotEquals(ct1, ControlTemplate.getErrorTemplate());
assertNotEquals(ct2, ControlTemplate.getErrorTemplate());
assertEquals(ct1.getTemplateType(), ct2.getTemplateType());
assertEquals(ct1.getTemplateId(), ct2.getTemplateId());
switch (ct1.getTemplateType()) {
case ControlTemplate.TYPE_TOGGLE:
assertToggleTemplate((ToggleTemplate) ct1, (ToggleTemplate) ct2);
break;
case ControlTemplate.TYPE_RANGE:
assertRangeTemplate((RangeTemplate) ct1, (RangeTemplate) ct2);
break;
case ControlTemplate.TYPE_TEMPERATURE:
assertTemperatureControlTemplate((TemperatureControlTemplate) ct1,
(TemperatureControlTemplate) ct2);
break;
case ControlTemplate.TYPE_TOGGLE_RANGE:
assertToggleRangeTemplate((ToggleRangeTemplate) ct1, (ToggleRangeTemplate) ct2);
break;
}
}
private void assertToggleTemplate(ToggleTemplate t1, ToggleTemplate t2) {
assertEquals(t1.isChecked(), t2.isChecked());
assertEquals(t1.getContentDescription(), t2.getContentDescription());
}
private void assertRangeTemplate(RangeTemplate t1, RangeTemplate t2) {
assertEquals(t1.getMinValue(), t2.getMinValue(), 0.0f);
assertEquals(t1.getMaxValue(), t2.getMaxValue(), 0.0f);
assertEquals(t1.getCurrentValue(), t2.getCurrentValue(), 0.0f);
assertEquals(t1.getStepValue(), t2.getStepValue(), 0.0f);
assertEquals(t1.getFormatString(), t2.getFormatString());
}
private void assertTemperatureControlTemplate(TemperatureControlTemplate t1,
TemperatureControlTemplate t2) {
assertEquals(t1.getCurrentMode(), t2.getCurrentMode());
assertEquals(t1.getCurrentActiveMode(), t2.getCurrentActiveMode());
assertEquals(t1.getModes(), t2.getModes());
assertTemplateEquals(t1.getTemplate(), t2.getTemplate());
}
private void assertToggleRangeTemplate(ToggleRangeTemplate t1, ToggleRangeTemplate t2) {
assertEquals(t1.isChecked(), t2.isChecked());
assertEquals(t1.getActionDescription(), t2.getActionDescription());
assertRangeTemplate(t1.getRange(), t2.getRange());
}
}