1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.lights; 18 19 import static android.graphics.Color.BLUE; 20 import static android.graphics.Color.GREEN; 21 import static android.graphics.Color.TRANSPARENT; 22 import static android.graphics.Color.WHITE; 23 import static android.hardware.lights.LightsRequest.Builder; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import android.content.Context; 28 import android.hardware.light.HwLight; 29 import android.hardware.light.HwLightState; 30 import android.hardware.light.ILights; 31 import android.hardware.lights.Light; 32 import android.hardware.lights.LightState; 33 import android.hardware.lights.LightsManager; 34 import android.hardware.lights.SystemLightsManager; 35 import android.os.Looper; 36 37 import androidx.test.filters.SmallTest; 38 import androidx.test.runner.AndroidJUnit4; 39 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.mockito.Mock; 44 import org.mockito.MockitoAnnotations; 45 46 @RunWith(AndroidJUnit4.class) 47 @SmallTest 48 public class LightsServiceTest { 49 50 private static final int HIGH_PRIORITY = Integer.MAX_VALUE; 51 private static final int DEFAULT_PRIORITY = 0; 52 53 private final ILights mHal = new ILights.Stub() { 54 @Override 55 public void setLightState(int id, HwLightState state) { 56 return; 57 } 58 59 @Override 60 public HwLight[] getLights() { 61 return new HwLight[] { 62 fakeHwLight(101, 3, 1), 63 fakeHwLight(102, LightsManager.LIGHT_TYPE_MICROPHONE, 4), 64 fakeHwLight(103, LightsManager.LIGHT_TYPE_MICROPHONE, 3), 65 fakeHwLight(104, LightsManager.LIGHT_TYPE_MICROPHONE, 1), 66 fakeHwLight(105, LightsManager.LIGHT_TYPE_MICROPHONE, 2) 67 }; 68 } 69 70 @Override 71 public int getInterfaceVersion() { 72 return this.VERSION; 73 } 74 75 @Override 76 public String getInterfaceHash() { 77 return this.HASH; 78 } 79 }; 80 fakeHwLight(int id, int type, int ordinal)81 private static HwLight fakeHwLight(int id, int type, int ordinal) { 82 HwLight light = new HwLight(); 83 light.id = id; 84 light.type = (byte) type; 85 light.ordinal = ordinal; 86 return light; 87 } 88 89 @Mock 90 Context mContext; 91 92 @Before setUp()93 public void setUp() { 94 MockitoAnnotations.initMocks(this); 95 } 96 97 @Test testGetLights_filtersSystemLights()98 public void testGetLights_filtersSystemLights() { 99 LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); 100 LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); 101 102 // When lights are listed, only the 4 MICROPHONE lights should be visible. 103 assertThat(manager.getLights().size()).isEqualTo(4); 104 } 105 106 @Test testControlMultipleLights()107 public void testControlMultipleLights() { 108 LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); 109 LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); 110 111 // When the session requests to turn 3/4 lights on: 112 LightsManager.LightsSession session = manager.openSession(); 113 session.requestLights(new Builder() 114 .addLight(manager.getLights().get(0), new LightState(0xf1)) 115 .addLight(manager.getLights().get(1), new LightState(0xf2)) 116 .addLight(manager.getLights().get(2), new LightState(0xf3)) 117 .build()); 118 119 // Then all 3 should turn on. 120 assertThat(manager.getLightState(manager.getLights().get(0)).getColor()).isEqualTo(0xf1); 121 assertThat(manager.getLightState(manager.getLights().get(1)).getColor()).isEqualTo(0xf2); 122 assertThat(manager.getLightState(manager.getLights().get(2)).getColor()).isEqualTo(0xf3); 123 124 // And the 4th should remain off. 125 assertThat(manager.getLightState(manager.getLights().get(3)).getColor()).isEqualTo(0x00); 126 } 127 128 @Test testControlLights_onlyEffectiveForLifetimeOfClient()129 public void testControlLights_onlyEffectiveForLifetimeOfClient() throws Exception { 130 LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); 131 LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); 132 Light micLight = manager.getLights().get(0); 133 134 // The light should begin by being off. 135 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT); 136 137 // When a session commits changes: 138 LightsManager.LightsSession session = manager.openSession(); 139 session.requestLights(new Builder().addLight(micLight, new LightState(GREEN)).build()); 140 // Then the light should turn on. 141 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(GREEN); 142 143 // When the session goes away: 144 session.close(); 145 146 // Then the light should turn off. 147 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT); 148 } 149 150 @Test testControlLights_firstCallerWinsContention()151 public void testControlLights_firstCallerWinsContention() throws Exception { 152 LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); 153 LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); 154 Light micLight = manager.getLights().get(0); 155 156 LightsManager.LightsSession session1 = manager.openSession(); 157 LightsManager.LightsSession session2 = manager.openSession(); 158 159 // When session1 and session2 both request the same light: 160 session1.requestLights(new Builder().addLight(micLight, new LightState(BLUE)).build()); 161 session2.requestLights(new Builder().addLight(micLight, new LightState(WHITE)).build()); 162 // Then session1 should win because it was created first. 163 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE); 164 165 // When session1 goes away: 166 session1.close(); 167 168 // Then session2 should have its request go into effect. 169 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE); 170 171 // When session2 goes away: 172 session2.close(); 173 174 // Then the light should turn off because there are no more sessions. 175 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0); 176 } 177 178 @Test testClearLight()179 public void testClearLight() { 180 LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); 181 LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); 182 Light micLight = manager.getLights().get(0); 183 184 // When the session turns a light on: 185 LightsManager.LightsSession session = manager.openSession(); 186 session.requestLights(new Builder().addLight(micLight, new LightState(WHITE)).build()); 187 188 // And then the session clears it again: 189 session.requestLights(new Builder().clearLight(micLight).build()); 190 191 // Then the light should turn back off. 192 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0); 193 } 194 195 @Test testControlLights_higherPriorityCallerWinsContention()196 public void testControlLights_higherPriorityCallerWinsContention() throws Exception { 197 LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); 198 LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); 199 Light micLight = manager.getLights().get(0); 200 201 // The light should begin by being off. 202 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT); 203 204 try (LightsManager.LightsSession session1 = manager.openSession(DEFAULT_PRIORITY)) { 205 try (LightsManager.LightsSession session2 = manager.openSession(HIGH_PRIORITY)) { 206 // When session1 and session2 both request the same light: 207 session1.requestLights( 208 new Builder().addLight(micLight, new LightState(BLUE)).build()); 209 session2.requestLights( 210 new Builder().addLight(micLight, new LightState(WHITE)).build()); 211 // Then session2 should win because it has a higher priority. 212 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE); 213 } 214 // Then session1 should have its request go into effect. 215 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE); 216 } 217 // Then the light should turn off because there are no more sessions. 218 assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT); 219 } 220 } 221