• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.host.systemui;
18 
19 import static android.host.systemui.TileServiceTest.START_ACTIVITY_AND_COLLAPSE;
20 
21 import android.compat.cts.CompatChangeGatingTestCase;
22 
23 import com.android.compatibility.common.util.ApiTest;
24 import com.android.tradefed.device.DeviceNotAvailableException;
25 import com.android.tradefed.util.RunUtil;
26 
27 import java.util.Set;
28 
29 public class CompatChangesTileServiceTest extends CompatChangeGatingTestCase {
30 
31     // Constants for generating commands below.
32     private static final String PACKAGE = "android.systemui.cts";
33 
34     // Commands used on the device.
35     private static final String ADD_TILE = "cmd statusbar add-tile ";
36     private static final String REM_TILE = "cmd statusbar remove-tile ";
37     private static final String OPEN_SETTINGS = "cmd statusbar expand-settings";
38 
39     public static final String REQUEST_SUPPORTED = "cmd statusbar check-support";
40     public static final String TEST_PREFIX = "TileTest_";
41 
42     // Time between checks for logs we expect.
43     private static final long CHECK_DELAY = 500;
44     // Number of times to check before failing.
45     private static final long CHECK_RETRIES = 30;
46 
47     private final String mService = "TestTileService";
48     private final String mComponent = PACKAGE + "/." + mService;
49 
50     private static final long START_ACTIVITY_NEEDS_PENDING_INTENT = 241766793L;
51 
52     @Override
setUp()53     protected void setUp() throws Exception {
54         super.setUp();
55 
56         clearLogcat();
57     }
58 
59     @Override
tearDown()60     protected void tearDown() throws Exception {
61         super.tearDown();
62 
63         remTile();
64         // Try to wait for a onTileRemoved.
65         waitFor("onTileRemoved");
66 
67         resetCompatChanges(Set.of(START_ACTIVITY_NEEDS_PENDING_INTENT), PACKAGE);
68         RunUtil.getDefault().sleep(100);
69     }
70 
71     @ApiTest(apis = {"android.service.quicksettings.TileService#startActivityAndCollapse(Intent)"})
testStartActivityWithIntent_requiresPendingIntent_ThrowsException()72     public void testStartActivityWithIntent_requiresPendingIntent_ThrowsException()
73             throws Exception {
74         if (!supported()) return;
75         Set<Long> enabledSet = Set.of(START_ACTIVITY_NEEDS_PENDING_INTENT);
76         Set<Long> disabledSet = Set.of();
77 
78         setCompatConfig(enabledSet, disabledSet, PACKAGE);
79         addTile();
80         // Wait for the tile to be added.
81         assertTrue(waitFor("onTileAdded"));
82 
83         // Open the quick settings and make sure the tile gets a chance to listen.
84         openSettings();
85         assertTrue(waitFor("onStartListening"));
86 
87         // Trigger the startActivityAndCollapse call and verify calling the method throws
88         // an UnsupportedOperationException.
89         getDevice().executeShellCommand(START_ACTIVITY_AND_COLLAPSE);
90         assertTrue(waitFor("handleStartActivity"));
91         assertTrue(waitFor("UnsupportedOperationException"));
92 
93         // Verify that the activity is not launched
94         assertFalse((waitFor("TestActivity#onResume")));
95     }
96 
97     @ApiTest(apis = {"android.service.quicksettings.TileService#startActivityAndCollapse(Intent)"})
testStartActivityWithIntent_doesNotRequirePendingIntent_lauchesSuccessfully()98     public void testStartActivityWithIntent_doesNotRequirePendingIntent_lauchesSuccessfully()
99             throws Exception {
100         if (!supported()) return;
101         Set<Long> enabledSet = Set.of();
102         Set<Long> disabledSet = Set.of(START_ACTIVITY_NEEDS_PENDING_INTENT);
103 
104         setCompatConfig(enabledSet, disabledSet, PACKAGE);
105         addTile();
106         // Wait for the tile to be added.
107         assertTrue(waitFor("onTileAdded"));
108 
109         // Open the quick settings and make sure the tile gets a chance to listen.
110         openSettings();
111         assertTrue(waitFor("onStartListening"));
112 
113         // Trigger the startActivityAndCollapse call and verify calling the method does not throw
114         // an UnsupportedOperationException.
115         getDevice().executeShellCommand(START_ACTIVITY_AND_COLLAPSE);
116         assertTrue(waitFor("handleStartActivity"));
117 
118         // Verify that the activity is launched
119         assertTrue((waitFor("TestActivity#onResume")));
120     }
121 
addTile()122     private void addTile() throws Exception {
123         execute(ADD_TILE + mComponent);
124     }
125 
remTile()126     private void remTile() throws Exception {
127         execute(REM_TILE + mComponent);
128     }
129 
openSettings()130     protected void openSettings() throws Exception {
131         execute(OPEN_SETTINGS);
132     }
133 
execute(String cmd)134     private void execute(String cmd) throws Exception {
135         getDevice().executeShellCommand(cmd);
136         // All of the status bar commands tend to have animations associated
137         // everything seems to be happier if you give them time to finish.
138         RunUtil.getDefault().sleep(100);
139     }
140 
waitFor(String str)141     protected boolean waitFor(String str) throws DeviceNotAvailableException, InterruptedException {
142         final String searchStr = TEST_PREFIX + str;
143         int ct = 0;
144         while (!hasLog(searchStr) && (ct++ < CHECK_RETRIES)) {
145             RunUtil.getDefault().sleep(CHECK_DELAY);
146         }
147         return hasLog(searchStr);
148     }
149 
hasLog(String str)150     protected boolean hasLog(String str) throws DeviceNotAvailableException {
151         String logs = getDevice().executeAdbCommand("logcat", "-v", "brief", "-d", mService + ":I",
152                 "*:S");
153         return logs.contains(str);
154     }
155 
clearLogcat()156     private void clearLogcat() throws DeviceNotAvailableException {
157         getDevice().executeAdbCommand("logcat", "-c");
158     }
159 
supported()160     protected boolean supported() throws DeviceNotAvailableException {
161         return supportedHardware() && supportedSoftware();
162     }
163 
supportedSoftware()164     private boolean supportedSoftware() throws DeviceNotAvailableException {
165         String supported = getDevice().executeShellCommand(REQUEST_SUPPORTED);
166         return Boolean.parseBoolean(supported.trim());
167     }
168 
supportedHardware()169     private boolean supportedHardware() throws DeviceNotAvailableException {
170         String features = getDevice().executeShellCommand("pm list features");
171         return !features.contains("android.hardware.type.television")
172                 && !features.contains("android.hardware.type.watch");
173     }
174 }
175