1 /*
2  * Copyright (C) 2019 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.telecom.tests;
18 
19 import static junit.framework.Assert.assertEquals;
20 import static junit.framework.Assert.assertFalse;
21 import static junit.framework.Assert.assertTrue;
22 import static junit.framework.TestCase.assertNull;
23 
24 import android.app.UiModeManager;
25 
26 import com.android.server.telecom.CarModeTracker;
27 
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.junit.runners.JUnit4;
33 
34 @RunWith(JUnit4.class)
35 public class CarModeTrackerTest extends TelecomTestCase {
36     private static final String CAR_MODE_APP1_PACKAGE_NAME = "com.android.carmode1";
37     private static final String CAR_MODE_APP2_PACKAGE_NAME = "com.android.carmode2";
38     private static final String CAR_MODE_APP3_PACKAGE_NAME = "com.android.carmode3";
39     private static final String CAR_MODE_APP4_PACKAGE_NAME = "com.android.carmode4";
40 
41     private CarModeTracker mCarModeTracker;
42 
43     @Override
44     @Before
setUp()45     public void setUp() throws Exception {
46         super.setUp();
47 
48         mCarModeTracker = new CarModeTracker();
49     }
50 
51     @Override
52     @After
tearDown()53     public void tearDown() throws Exception {
54         super.tearDown();
55     }
56 
57     /**
58      * Basic test; see if we can enter car mode.
59      */
60     @Test
testEnterCarModeBasic()61     public void testEnterCarModeBasic() {
62         // At start, no car mode apps.
63         assertNull(mCarModeTracker.getCurrentCarModePackage());
64         assertEquals(0, mCarModeTracker.getCarModeApps().size());
65 
66         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
67 
68         // We should be tracking our car mode app.
69         assertEquals(1, mCarModeTracker.getCarModeApps().size());
70         assertTrue(mCarModeTracker.isInCarMode());
71     }
72 
73     /**
74      * Ensure when we enter car mode with a package which has already entered car mode, the extra
75      * request is ignored.
76      */
77     @Test
testEnterCarModeAlreadyInCarMode()78     public void testEnterCarModeAlreadyInCarMode() {
79         testEnterCarModeBasic();
80 
81         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
82         // Still should just be one.
83         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
84         assertEquals(1, mCarModeTracker.getCarModeApps().size());
85     }
86 
87     /**
88      * Ensure when we enter car mode with a package which has already entered car mode, the extra
89      * request is ignored.
90      */
91     @Test
testEnterCarModePriorityInUse()92     public void testEnterCarModePriorityInUse() {
93         testEnterCarModeBasic();
94 
95         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP2_PACKAGE_NAME);
96 
97         // We should be tracking car mode with the first package; the 2nd should have been ignored.
98         assertEquals(1, mCarModeTracker.getCarModeApps().size());
99         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
100         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCarModeApps().get(0));
101     }
102 
103     /**
104      * Ensure that we don't keep a package around after it's been removed from the device
105      */
106     @Test
testForceExitCarMode()107     public void testForceExitCarMode() {
108         testEnterCarModeBasic();
109         mCarModeTracker.forceRemove(CAR_MODE_APP1_PACKAGE_NAME);
110         assertFalse(mCarModeTracker.isInCarMode());
111         assertNull(mCarModeTracker.getCurrentCarModePackage());
112     }
113 
114     /**
115      * Verifies only the first app at the default priority gets tracked.
116      */
117     @Test
testEnterCarModeDefaultPriority()118     public void testEnterCarModeDefaultPriority() {
119         assertEquals(0, mCarModeTracker.getCarModeApps().size());
120 
121         mCarModeTracker.handleEnterCarMode(UiModeManager.DEFAULT_PRIORITY,
122                 CAR_MODE_APP1_PACKAGE_NAME);
123         assertEquals(1, mCarModeTracker.getCarModeApps().size());
124         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
125 
126         mCarModeTracker.handleEnterCarMode(UiModeManager.DEFAULT_PRIORITY,
127                 CAR_MODE_APP2_PACKAGE_NAME);
128         assertEquals(1, mCarModeTracker.getCarModeApps().size());
129         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
130     }
131 
132     /**
133      * Verifies that multiple apps can enter car mode at the default priority and a higher priority.
134      * Verifies that the priority ordering is retained as expected.
135      */
136     @Test
testEnterCarModeDefaultAndHigherPriority()137     public void testEnterCarModeDefaultAndHigherPriority() {
138         testEnterCarModeDefaultPriority();
139 
140         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP3_PACKAGE_NAME);
141         assertEquals(2, mCarModeTracker.getCarModeApps().size());
142         assertEquals(CAR_MODE_APP3_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
143         assertEquals(CAR_MODE_APP3_PACKAGE_NAME, mCarModeTracker.getCarModeApps().get(0));
144         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCarModeApps().get(1));
145 
146         mCarModeTracker.handleEnterCarMode(50, CAR_MODE_APP4_PACKAGE_NAME);
147         assertEquals(3, mCarModeTracker.getCarModeApps().size());
148         assertEquals(CAR_MODE_APP3_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
149         assertEquals(CAR_MODE_APP3_PACKAGE_NAME, mCarModeTracker.getCarModeApps().get(0));
150         assertEquals(CAR_MODE_APP4_PACKAGE_NAME, mCarModeTracker.getCarModeApps().get(1));
151         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCarModeApps().get(2));
152     }
153 
154     /**
155      * Verifies entering and exiting car mode at default priority.
156      */
157     @Test
testEnterExitCarModeDefaultPriority()158     public void testEnterExitCarModeDefaultPriority() {
159         mCarModeTracker.handleEnterCarMode(UiModeManager.DEFAULT_PRIORITY,
160                 CAR_MODE_APP1_PACKAGE_NAME);
161         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
162         mCarModeTracker.handleExitCarMode(UiModeManager.DEFAULT_PRIORITY,
163                 CAR_MODE_APP1_PACKAGE_NAME);
164         assertNull(mCarModeTracker.getCurrentCarModePackage());
165     }
166 
167     /**
168      * Verifies entering and exiting car mode at default priority.
169      * Ensures a different app can exit car mode at the default priority than the one which
170      * entered car mode at that priority.
171      */
172     @Test
testEnterExitCarModeDefaultPriorityDifferentApp()173     public void testEnterExitCarModeDefaultPriorityDifferentApp() {
174         mCarModeTracker.handleEnterCarMode(UiModeManager.DEFAULT_PRIORITY,
175                 CAR_MODE_APP1_PACKAGE_NAME);
176         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
177         mCarModeTracker.handleExitCarMode(UiModeManager.DEFAULT_PRIORITY,
178                 CAR_MODE_APP2_PACKAGE_NAME);
179         assertNull(mCarModeTracker.getCurrentCarModePackage());
180     }
181 
182     /**
183      * Verifies entering and exiting car mode at higher priority.
184      */
185     @Test
testEnterExitCarModeHigherPriority()186     public void testEnterExitCarModeHigherPriority() {
187         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
188         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
189         mCarModeTracker.handleExitCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
190         assertNull(mCarModeTracker.getCurrentCarModePackage());
191     }
192 
193     /**
194      * Verifies entering and exiting car mode at higher priority, except the exiting app differs.
195      */
196     @Test
testEnterExitCarModeHigherPriorityDifferentApp()197     public void testEnterExitCarModeHigherPriorityDifferentApp() {
198         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
199         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
200         mCarModeTracker.handleExitCarMode(100, CAR_MODE_APP2_PACKAGE_NAME);
201         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
202     }
203 
204     /**
205      * Verifies entering and exiting car mode at a bunch of priorities with a bunch of apps.
206      */
207     @Test
testEnterExitCarModeMultiple()208     public void testEnterExitCarModeMultiple() {
209         mCarModeTracker.handleEnterCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
210         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
211         mCarModeTracker.handleEnterCarMode(50, CAR_MODE_APP2_PACKAGE_NAME);
212         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
213         mCarModeTracker.handleEnterCarMode(UiModeManager.DEFAULT_PRIORITY,
214                 CAR_MODE_APP3_PACKAGE_NAME);
215         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
216 
217         mCarModeTracker.handleExitCarMode(100, CAR_MODE_APP1_PACKAGE_NAME);
218         assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
219         mCarModeTracker.handleExitCarMode(50, CAR_MODE_APP2_PACKAGE_NAME);
220         assertEquals(CAR_MODE_APP3_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
221         mCarModeTracker.handleExitCarMode(UiModeManager.DEFAULT_PRIORITY,
222                 CAR_MODE_APP3_PACKAGE_NAME);
223         assertNull(mCarModeTracker.getCurrentCarModePackage());
224     }
225 
226     /**
227      * Verifies that setting automotive projection by itself works.
228      */
229     @Test
testSetAutomotiveProjectionBasic()230     public void testSetAutomotiveProjectionBasic() {
231         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
232         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
233         // We should be tracking our car mode app.
234         assertEquals(1, mCarModeTracker.getCarModeApps().size());
235         assertTrue(mCarModeTracker.isInCarMode());
236     }
237 
238     /**
239      * Verifies that setting automotive projection overrides entering car mode with the highest
240      * priority of 0. Also ensures exiting car mode doesn't interfere with the automotive
241      * projection being set.
242      */
243     @Test
testInterleaveCarModeAndProjectionMode()244     public void testInterleaveCarModeAndProjectionMode() {
245         mCarModeTracker.handleEnterCarMode(0, CAR_MODE_APP1_PACKAGE_NAME);
246         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
247         assertTrue(mCarModeTracker.isInCarMode());
248 
249         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP2_PACKAGE_NAME);
250         assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
251         assertTrue(mCarModeTracker.isInCarMode());
252 
253         mCarModeTracker.handleExitCarMode(0, CAR_MODE_APP1_PACKAGE_NAME);
254         assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
255         assertTrue(mCarModeTracker.isInCarMode());
256 
257         mCarModeTracker.handleReleaseAutomotiveProjection();
258     }
259 
260     /**
261      * Verifies that if we set automotive projection more than once with the same package, nothing
262      * changes.
263      */
264     @Test
testSetAutomotiveProjectionMultipleTimes()265     public void testSetAutomotiveProjectionMultipleTimes() {
266         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
267         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
268         // Should still only have one app.
269         assertEquals(1, mCarModeTracker.getCarModeApps().size());
270         assertTrue(mCarModeTracker.isInCarMode());
271         // It should be the same one.
272         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
273     }
274 
275     /**
276      * Verifies that if we set automotive projection more than once, the new package overrides.
277      */
278     @Test
testSetAutomotiveProjectionMultipleTimesDifferentPackages()279     public void testSetAutomotiveProjectionMultipleTimesDifferentPackages() {
280         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
281         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP2_PACKAGE_NAME);
282         // Should still only have one app.
283         assertEquals(1, mCarModeTracker.getCarModeApps().size());
284         assertTrue(mCarModeTracker.isInCarMode());
285         // It should be the newer one.
286         assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
287     }
288 
289     /**
290      * Verifies that releasing automotive projection works as expected.
291      */
292     @Test
testReleaseAutomotiveProjectionBasic()293     public void testReleaseAutomotiveProjectionBasic() {
294         // Releasing before something's set shouldn't break anything.
295         mCarModeTracker.handleReleaseAutomotiveProjection();
296         assertEquals(0, mCarModeTracker.getCarModeApps().size());
297         assertFalse(mCarModeTracker.isInCarMode());
298 
299         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
300         mCarModeTracker.handleReleaseAutomotiveProjection();
301         // Should be gone now.
302         assertEquals(0, mCarModeTracker.getCarModeApps().size());
303         assertFalse(mCarModeTracker.isInCarMode());
304     }
305 
306     /**
307      * Verifies that setting automotive projection overrides but doesn't overwrite car mode apps.
308      */
309     @Test
testAutomotiveProjectionOverridesCarMode()310     public void testAutomotiveProjectionOverridesCarMode() {
311         mCarModeTracker.handleEnterCarMode(50, CAR_MODE_APP1_PACKAGE_NAME);
312         mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP4_PACKAGE_NAME);
313 
314         // Should have two apps now, the car mode and the automotive projection one.
315         assertEquals(2, mCarModeTracker.getCarModeApps().size());
316         assertTrue(mCarModeTracker.isInCarMode());
317 
318         // Automotive projection takes priority.
319         assertEquals(CAR_MODE_APP4_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
320 
321         // If we add another car mode app, automotive projection still has priority.
322         mCarModeTracker.handleEnterCarMode(Integer.MAX_VALUE, CAR_MODE_APP2_PACKAGE_NAME);
323         assertEquals(3, mCarModeTracker.getCarModeApps().size());
324         assertTrue(mCarModeTracker.isInCarMode());
325         assertEquals(CAR_MODE_APP4_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
326 
327         // If we release automotive projection, we go back to the prioritized list of plain car
328         // mode apps.
329         mCarModeTracker.handleReleaseAutomotiveProjection();
330         assertEquals(2, mCarModeTracker.getCarModeApps().size());
331         assertTrue(mCarModeTracker.isInCarMode());
332         assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
333 
334         // Make sure we didn't mess with the first app that was added.
335         mCarModeTracker.handleExitCarMode(Integer.MAX_VALUE, CAR_MODE_APP2_PACKAGE_NAME);
336         assertEquals(1, mCarModeTracker.getCarModeApps().size());
337         assertTrue(mCarModeTracker.isInCarMode());
338         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
339     }
340 
341     /**
342      * Verifies that releasing automotive projection doesn't interfere with plain car mode apps.
343      */
344     @Test
testReleaseAutomotiveProjectionNoopForCarModeApps()345     public void testReleaseAutomotiveProjectionNoopForCarModeApps() {
346         mCarModeTracker.handleEnterCarMode(50, CAR_MODE_APP1_PACKAGE_NAME);
347         mCarModeTracker.handleReleaseAutomotiveProjection();
348         assertEquals(1, mCarModeTracker.getCarModeApps().size());
349         assertTrue(mCarModeTracker.isInCarMode());
350         assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
351     }
352 }
353