1 /*
2  * Copyright (C) 2015 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.app.usage.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotEquals;
22 import static org.junit.Assume.assumeTrue;
23 
24 import com.android.tradefed.device.DeviceNotAvailableException;
25 import com.android.tradefed.device.ITestDevice;
26 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
27 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
28 
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 
33 @RunWith(DeviceJUnit4ClassRunner.class)
34 public class AppIdleHostTest extends BaseHostJUnit4Test {
35     private static final String SETTINGS_APP_IDLE_CONSTANTS = "app_idle_constants";
36 
37     private static final String TEST_APP_PACKAGE = "android.app.usage.app";
38     private static final String TEST_APP_CLASS = "TestActivity";
39     private static final String TEST_APP_PACKAGE2 = "android.app.usage.apptoo";
40 
41     private static final long ACTIVITY_LAUNCH_WAIT_MILLIS = 500;
42 
43     private static final int SB_ACTIVE = 10;
44     private static final int SB_WORKING_SET = 20;
45     private static final int SB_FREQUENT = 30;
46 
47     /**
48      * A reference to the device under test.
49      */
50     private ITestDevice mDevice;
51 
52     @Before
setUp()53     public void setUp() {
54         // Get the device, this gives a handle to run commands and install APKs.
55         mDevice = getDevice();
56     }
57 
58     /**
59      * Checks whether an package is idle.
60      * @param appPackage The package to check for idleness.
61      * @return true if the package is idle
62      * @throws DeviceNotAvailableException
63      */
isAppIdle(String appPackage)64     private boolean isAppIdle(String appPackage) throws DeviceNotAvailableException {
65         String result = mDevice.executeShellCommand(String.format("am get-inactive %s", appPackage));
66         return result.contains("Idle=true");
67     }
68 
69     /**
70      * Set the app idle settings.
71      * @param settingsStr The settings string, a comma separated key=value list.
72      * @throws DeviceNotAvailableException
73      */
setAppIdleSettings(String settingsStr)74     private void setAppIdleSettings(String settingsStr) throws DeviceNotAvailableException {
75         mDevice.executeShellCommand(String.format("settings put global %s \"%s\"",
76                 SETTINGS_APP_IDLE_CONSTANTS, settingsStr));
77     }
78 
79     /**
80      * Get the current app idle settings.
81      * @throws DeviceNotAvailableException
82      */
getAppIdleSettings()83     private String getAppIdleSettings() throws DeviceNotAvailableException {
84         String result = mDevice.executeShellCommand(String.format("settings get global %s",
85                 SETTINGS_APP_IDLE_CONSTANTS));
86         return result.trim();
87     }
88 
89     /**
90      * Launch the test app for a few hundred milliseconds then launch home.
91      * @throws DeviceNotAvailableException
92      */
startAndStopTestApp()93     private void startAndStopTestApp() throws DeviceNotAvailableException {
94         // Launch the app.
95         mDevice.executeShellCommand(
96                 String.format("am start -W -a android.intent.action.MAIN -n %s/%s.%s",
97                         TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_APP_CLASS));
98 
99         // Wait for some time.
100         sleepUninterrupted(ACTIVITY_LAUNCH_WAIT_MILLIS);
101 
102         // Launch home.
103         mDevice.executeShellCommand(
104                 "am start -W -a android.intent.action.MAIN -c android.intent.category.HOME");
105     }
106 
107     /**
108      * Tests that the app is not idle right after it is launched.
109      */
110     @Test
testAppIsNotIdleAfterBeingLaunched()111     public void testAppIsNotIdleAfterBeingLaunched() throws Exception {
112         final String previousState = getAppIdleSettings();
113         try {
114             // Set the app idle time to something large.
115             setAppIdleSettings("idle_duration=10000,wallclock_threshold=10000");
116             startAndStopTestApp();
117             assertFalse(isAppIdle(TEST_APP_PACKAGE));
118         } finally {
119             setAppIdleSettings(previousState);
120         }
121     }
122 
setAppStandbyBucket(String packageName, int bucket)123     private void setAppStandbyBucket(String packageName, int bucket) throws Exception {
124         mDevice.executeShellCommand(
125                 String.format("am set-standby-bucket %s %s", packageName, bucket));
126     }
127 
isAppStandbyEnabled()128     private boolean isAppStandbyEnabled() throws DeviceNotAvailableException {
129         final String result = mDevice.executeShellCommand(
130                 "dumpsys usagestats is-app-standby-enabled").trim();
131         return Boolean.parseBoolean(result);
132     }
133 
getAppStandbyBucket(String packageName)134     private int getAppStandbyBucket(String packageName) throws Exception {
135         String bucketString = mDevice.executeShellCommand(
136                 String.format("am get-standby-bucket %s", packageName));
137         try {
138             return Integer.parseInt(bucketString.trim());
139         } catch (NumberFormatException nfe) {
140         }
141         return -1;
142     }
143 
144     @Test
testSetAppStandbyBucket()145     public void testSetAppStandbyBucket() throws Exception {
146         assumeTrue("App standby not enabled on device", isAppStandbyEnabled());
147         // Set to ACTIVE
148         setAppStandbyBucket(TEST_APP_PACKAGE, SB_ACTIVE);
149         assertEquals(SB_ACTIVE, getAppStandbyBucket(TEST_APP_PACKAGE));
150         // set to WORKING_SET
151         setAppStandbyBucket(TEST_APP_PACKAGE, 20);
152         assertEquals(20, getAppStandbyBucket(TEST_APP_PACKAGE));
153     }
154 
155     @Test
testSetAppStandbyBuckets()156     public void testSetAppStandbyBuckets() throws Exception {
157         assumeTrue("App standby not enabled on device", isAppStandbyEnabled());
158         // Set multiple packages states
159         String command = String.format("am set-standby-bucket %s %d %s %d",
160                 TEST_APP_PACKAGE, SB_FREQUENT, TEST_APP_PACKAGE2, SB_WORKING_SET);
161         mDevice.executeShellCommand(command);
162         assertEquals(SB_FREQUENT, getAppStandbyBucket(TEST_APP_PACKAGE));
163         assertEquals(SB_WORKING_SET, getAppStandbyBucket(TEST_APP_PACKAGE2));
164     }
165 
166     @Test
testCantSetOwnStandbyBucket()167     public void testCantSetOwnStandbyBucket() throws Exception {
168         assumeTrue("App standby not enabled on device", isAppStandbyEnabled());
169         setAppStandbyBucket("com.android.shell", 40);
170         assertNotEquals(40, getAppStandbyBucket("com.android.shell"));
171     }
172 
173     @Test
testOutOfBoundsStandbyBucket()174     public void testOutOfBoundsStandbyBucket() throws Exception {
175         assumeTrue("App standby not enabled on device", isAppStandbyEnabled());
176         setAppStandbyBucket(TEST_APP_PACKAGE, SB_ACTIVE);
177         assertEquals(SB_ACTIVE, getAppStandbyBucket(TEST_APP_PACKAGE));
178         // Try lower than min
179         setAppStandbyBucket(TEST_APP_PACKAGE, SB_ACTIVE - 1);
180         assertEquals(SB_ACTIVE, getAppStandbyBucket(TEST_APP_PACKAGE));
181         // Try higher than max
182         setAppStandbyBucket(TEST_APP_PACKAGE, 50 + 1);
183         assertEquals(SB_ACTIVE, getAppStandbyBucket(TEST_APP_PACKAGE));
184     }
185 
sleepUninterrupted(long timeMillis)186     private static void sleepUninterrupted(long timeMillis) {
187         boolean interrupted;
188         do {
189             try {
190                 Thread.sleep(timeMillis);
191                 interrupted = false;
192             } catch (InterruptedException e) {
193                 interrupted = true;
194             }
195         } while (interrupted);
196     }
197 }
198