1 /* 2 * Copyright (C) 2017 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 package com.android.cts.launchertests; 17 18 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.setDefaultLauncher; 19 20 import static junit.framework.Assert.assertFalse; 21 import static junit.framework.Assert.assertNotNull; 22 import static junit.framework.Assert.assertNull; 23 import static junit.framework.Assert.assertTrue; 24 import static junit.framework.Assert.fail; 25 26 import static org.testng.Assert.assertEquals; 27 import static org.testng.Assert.assertThrows; 28 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.os.Bundle; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.support.test.uiautomator.UiDevice; 37 import android.text.TextUtils; 38 39 import androidx.test.InstrumentationRegistry; 40 import androidx.test.runner.AndroidJUnit4; 41 42 import com.android.compatibility.common.util.BlockingBroadcastReceiver; 43 44 import org.junit.After; 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 49 import java.util.Arrays; 50 import java.util.Set; 51 import java.util.concurrent.LinkedBlockingQueue; 52 import java.util.concurrent.TimeUnit; 53 import java.util.regex.Matcher; 54 import java.util.regex.Pattern; 55 import java.util.stream.Collectors; 56 57 /** 58 * Test that runs {@link UserManager#trySetQuietModeEnabled(boolean, UserHandle)} API 59 * against valid target user. 60 */ 61 @RunWith(AndroidJUnit4.class) 62 public class QuietModeTest { 63 private static final String PARAM_TARGET_USER = "TARGET_USER"; 64 private static final String PARAM_ORIGINAL_DEFAULT_LAUNCHER = "ORIGINAL_DEFAULT_LAUNCHER"; 65 private static final ComponentName LAUNCHER_ACTIVITY = 66 new ComponentName( 67 "com.android.cts.launchertests.support", 68 "com.android.cts.launchertests.support.LauncherActivity"); 69 70 private static final ComponentName COMMAND_RECEIVER = 71 new ComponentName( 72 "com.android.cts.launchertests.support", 73 "com.android.cts.launchertests.support.QuietModeCommandReceiver"); 74 private static final String EXTRA_FLAGS = "quiet_mode_flags"; 75 76 private UserManager mUserManager; 77 private UserHandle mTargetUser; 78 private Context mContext; 79 private String mOriginalLauncher; 80 private UiDevice mUiDevice; 81 82 @Before setupUserManager()83 public void setupUserManager() throws Exception { 84 mContext = InstrumentationRegistry.getTargetContext(); 85 mUserManager = mContext.getSystemService(UserManager.class); 86 } 87 88 @Before readParams()89 public void readParams() { 90 Context context = InstrumentationRegistry.getContext(); 91 Bundle arguments = InstrumentationRegistry.getArguments(); 92 UserManager userManager = context.getSystemService(UserManager.class); 93 final int userSn = Integer.parseInt(arguments.getString(PARAM_TARGET_USER)); 94 mTargetUser = userManager.getUserForSerialNumber(userSn); 95 mOriginalLauncher = arguments.getString(PARAM_ORIGINAL_DEFAULT_LAUNCHER); 96 } 97 98 @Before wakeupDeviceAndUnlock()99 public void wakeupDeviceAndUnlock() throws Exception { 100 mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 101 mUiDevice.wakeUp(); 102 mUiDevice.pressMenu(); 103 } 104 105 @Before 106 @After revertToDefaultLauncher()107 public void revertToDefaultLauncher() throws Exception { 108 if (TextUtils.isEmpty(mOriginalLauncher)) { 109 return; 110 } 111 setDefaultLauncher(InstrumentationRegistry.getInstrumentation(), mOriginalLauncher); 112 } 113 114 @Test testTryEnableQuietMode_defaultForegroundLauncher()115 public void testTryEnableQuietMode_defaultForegroundLauncher() throws Exception { 116 setTestAppAsDefaultLauncher(); 117 startLauncherActivityInTestApp(); 118 119 Intent intent = trySetQuietModeEnabled(true); 120 assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_UNAVAILABLE broadcast", intent); 121 assertTrue(mUserManager.isQuietModeEnabled(mTargetUser)); 122 123 intent = trySetQuietModeEnabled(false); 124 assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_AVAILABLE broadcast", intent); 125 assertFalse(mUserManager.isQuietModeEnabled(mTargetUser)); 126 } 127 128 @Test testTryEnableQuietMode_notForegroundLauncher()129 public void testTryEnableQuietMode_notForegroundLauncher() throws InterruptedException { 130 setTestAppAsDefaultLauncher(); 131 132 assertThrows(SecurityException.class, () -> trySetQuietModeEnabled(true)); 133 assertFalse(mUserManager.isQuietModeEnabled(mTargetUser)); 134 } 135 136 @Test testTryEnableQuietMode_notDefaultLauncher()137 public void testTryEnableQuietMode_notDefaultLauncher() throws Exception { 138 startLauncherActivityInTestApp(); 139 140 assertThrows(SecurityException.class, () -> trySetQuietModeEnabled(true)); 141 assertFalse(mUserManager.isQuietModeEnabled(mTargetUser)); 142 } 143 144 @Test testTryEnableQuietMode_noCredentialRequest()145 public void testTryEnableQuietMode_noCredentialRequest() throws Exception { 146 setTestAppAsDefaultLauncher(); 147 startLauncherActivityInTestApp(); 148 149 Intent intent = trySetQuietModeEnabled(true, 150 UserManager.QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, true); 151 assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_UNAVAILABLE broadcast", intent); 152 assertTrue(mUserManager.isQuietModeEnabled(mTargetUser)); 153 154 waitForUserLocked(); 155 156 intent = trySetQuietModeEnabled(false, 157 UserManager.QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, false); 158 assertNull("Received ACTION_MANAGED_PROFILE_AVAILABLE broadcast", intent); 159 assertTrue(mUserManager.isQuietModeEnabled(mTargetUser)); 160 } 161 waitForUserLocked()162 private void waitForUserLocked() throws Exception { 163 // Should match a line in "dumpsys mount" output like this: 164 // Local unlocked users: [0, 10] 165 final Pattern p = Pattern.compile("Local unlocked users: \\[(.*)\\]"); 166 final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(60); 167 while (System.nanoTime() < deadline) { 168 final String output = mUiDevice.executeShellCommand("dumpsys mount"); 169 final Matcher matcher = p.matcher(output); 170 assertTrue("Unexpected dupmsys mount output: " + output, matcher.find()); 171 final Set<Integer> unlockedUsers = Arrays.stream(matcher.group(1).split(", ")) 172 .map(Integer::valueOf) 173 .collect(Collectors.toSet()); 174 if (!unlockedUsers.contains(mTargetUser.getIdentifier())) { 175 return; 176 } 177 Thread.sleep(500); 178 } 179 fail("Cannot get the profile locked"); 180 } 181 trySetQuietModeEnabled(boolean enabled, int flags, boolean expectsCredentialsNotNeeded)182 private Intent trySetQuietModeEnabled(boolean enabled, int flags, 183 boolean expectsCredentialsNotNeeded) throws Exception { 184 return trySetQuietModeEnabled(enabled, true, flags, expectsCredentialsNotNeeded); 185 } 186 187 @Test testTryEnableQuietMode()188 public void testTryEnableQuietMode() throws Exception { 189 setTestAppAsDefaultLauncher(); 190 startLauncherActivityInTestApp(); 191 192 Intent intent = trySetQuietModeEnabled(true); 193 assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_UNAVAILABLE broadcast", intent); 194 assertTrue(mUserManager.isQuietModeEnabled(mTargetUser)); 195 } 196 197 @Test testTryDisableQuietMode()198 public void testTryDisableQuietMode() throws Exception { 199 setTestAppAsDefaultLauncher(); 200 startLauncherActivityInTestApp(); 201 202 Intent intent = trySetQuietModeEnabled(false); 203 assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_AVAILABLE broadcast", intent); 204 assertFalse(mUserManager.isQuietModeEnabled(mTargetUser)); 205 } 206 trySetQuietModeEnabled(boolean enabled)207 private Intent trySetQuietModeEnabled(boolean enabled) throws Exception { 208 return trySetQuietModeEnabled(enabled, false, 0, true); 209 } 210 trySetQuietModeEnabled(boolean enabled, boolean hasFlags, int flags, boolean expectsCredentialsNotNeeded)211 private Intent trySetQuietModeEnabled(boolean enabled, boolean hasFlags, int flags, 212 boolean expectsCredentialsNotNeeded) throws Exception { 213 final String action = enabled 214 ? Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE 215 : Intent.ACTION_MANAGED_PROFILE_AVAILABLE; 216 217 BlockingBroadcastReceiver receiver = 218 new BlockingBroadcastReceiver(mContext, action); 219 try { 220 receiver.register(); 221 222 boolean credentialNotNeeded = askLauncherSupportAppToSetQuietMode(enabled, hasFlags, 223 flags); 224 assertEquals(credentialNotNeeded, expectsCredentialsNotNeeded); 225 return receiver.awaitForBroadcast(); 226 } finally { 227 receiver.unregisterQuietly(); 228 } 229 } 230 231 /** 232 * Ask launcher support test app to set quiet mode by sending broadcast. 233 * <p> 234 * We cannot simply make this package the launcher and call the API because instrumentation 235 * process would always considered to be in the foreground. The trick here is to send 236 * broadcast to another test app which is launcher itself and call the API through it. 237 * The receiver will then send back the result, and it should be either true, false or 238 * security-exception. 239 * <p> 240 * All the constants defined here should be aligned with 241 * com.android.cts.launchertests.support.QuietModeCommandReceiver. 242 */ askLauncherSupportAppToSetQuietMode(boolean enabled, boolean hasFlags, int flags)243 private boolean askLauncherSupportAppToSetQuietMode(boolean enabled, boolean hasFlags, int flags) throws Exception { 244 Intent intent = new Intent("toggle_quiet_mode"); 245 intent.setComponent(COMMAND_RECEIVER); 246 intent.putExtra("quiet_mode", enabled); 247 intent.putExtra(Intent.EXTRA_USER, mTargetUser); 248 if (hasFlags) { 249 intent.putExtra(EXTRA_FLAGS, flags); 250 } 251 252 // Ask launcher support app to set quiet mode by sending broadcast. 253 LinkedBlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>(); 254 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { 255 @Override 256 public void onReceive(Context context, Intent intent) { 257 blockingQueue.offer(getResultData()); 258 } 259 }, null, 0, "", null); 260 261 // Wait for the result. 262 String result = null; 263 for (int i = 0; i < 10; i++) { 264 // Broadcast won't be delivered when the device is sleeping, so wake up the device 265 // in between each attempt. 266 wakeupDeviceAndUnlock(); 267 result = blockingQueue.poll(10, TimeUnit.SECONDS); 268 if (!TextUtils.isEmpty(result)) { 269 break; 270 } 271 } 272 273 // Parse the result. 274 assertNotNull(result); 275 if ("true".equalsIgnoreCase(result)) { 276 return true; 277 } else if ("false".equalsIgnoreCase(result)) { 278 return false; 279 } else if ("security-exception".equals(result)) { 280 throw new SecurityException(); 281 } 282 throw new IllegalStateException("Unexpected result : " + result); 283 } 284 startActivitySync(String activity)285 private void startActivitySync(String activity) throws Exception { 286 mUiDevice.executeShellCommand("am start -W -n " + activity); 287 } 288 289 /** 290 * Start the launcher activity in the test app to make it foreground. 291 */ startLauncherActivityInTestApp()292 private void startLauncherActivityInTestApp() throws Exception { 293 startActivitySync(LAUNCHER_ACTIVITY.flattenToString()); 294 } 295 setTestAppAsDefaultLauncher()296 private void setTestAppAsDefaultLauncher() { 297 setDefaultLauncher(InstrumentationRegistry.getInstrumentation(), 298 LAUNCHER_ACTIVITY.getPackageName()); 299 } 300 } 301 302