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 17 package android.server.am; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 26 import static android.server.am.ActivityManagerState.STATE_RESUMED; 27 import static android.server.am.ComponentNameUtils.getActivityName; 28 import static android.server.am.Components.ANIMATION_TEST_ACTIVITY; 29 import static android.server.am.Components.ASSISTANT_ACTIVITY; 30 import static android.server.am.Components.ASSISTANT_VOICE_INTERACTION_SERVICE; 31 import static android.server.am.Components.AssistantActivity.EXTRA_ASSISTANT_DISPLAY_ID; 32 import static android.server.am.Components.AssistantActivity.EXTRA_ASSISTANT_ENTER_PIP; 33 import static android.server.am.Components.AssistantActivity.EXTRA_ASSISTANT_FINISH_SELF; 34 import static android.server.am.Components.AssistantActivity.EXTRA_ASSISTANT_LAUNCH_NEW_TASK; 35 import static android.server.am.Components.DOCKED_ACTIVITY; 36 import static android.server.am.Components.LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION; 37 import static android.server.am.Components.LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK; 38 import static android.server.am.Components.LaunchAssistantActivityIntoAssistantStack 39 .EXTRA_ASSISTANT_IS_TRANSLUCENT; 40 import static android.server.am.Components.PIP_ACTIVITY; 41 import static android.server.am.Components.PipActivity.EXTRA_ENTER_PIP; 42 import static android.server.am.Components.TEST_ACTIVITY; 43 import static android.server.am.Components.TRANSLUCENT_ASSISTANT_ACTIVITY; 44 import static android.server.am.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF; 45 import static android.server.am.UiDeviceUtils.pressBackButton; 46 import static android.view.Display.DEFAULT_DISPLAY; 47 48 import static org.hamcrest.Matchers.hasSize; 49 import static org.junit.Assert.assertEquals; 50 import static org.junit.Assert.assertThat; 51 import static org.junit.Assert.assertTrue; 52 import static org.junit.Assume.assumeTrue; 53 54 import android.content.ComponentName; 55 import android.platform.test.annotations.Presubmit; 56 import android.provider.Settings; 57 import android.server.am.settings.SettingsSession; 58 import android.support.test.filters.FlakyTest; 59 60 import org.junit.Ignore; 61 import org.junit.Test; 62 63 /** 64 * Build/Install/Run: 65 * atest CtsActivityManagerDeviceTestCases:ActivityManagerAssistantStackTests 66 */ 67 //@Presubmit b/67706642 68 @FlakyTest(bugId = 71875631) 69 public class ActivityManagerAssistantStackTests extends ActivityManagerTestBase { 70 71 private int mAssistantDisplayId = DEFAULT_DISPLAY; 72 setUp()73 public void setUp() throws Exception { 74 super.setUp(); 75 try (final AssistantSession assistantSession = new AssistantSession()) { 76 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 77 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK); 78 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 79 ActivityManagerState.ActivityStack assistantStack = 80 mAmWmState.getAmState().getStackByActivityType(ACTIVITY_TYPE_ASSISTANT); 81 mAssistantDisplayId = assistantStack.mDisplayId; 82 } 83 } 84 85 @Test 86 @Presubmit testLaunchingAssistantActivityIntoAssistantStack()87 public void testLaunchingAssistantActivityIntoAssistantStack() throws Exception { 88 // Enable the assistant and launch an assistant activity 89 try (final AssistantSession assistantSession = new AssistantSession()) { 90 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 91 92 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION); 93 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 94 95 // Ensure that the activity launched in the fullscreen assistant stack 96 assertAssistantStackExists(); 97 assertTrue("Expected assistant stack to be fullscreen", 98 mAmWmState.getAmState().getStackByActivityType( 99 ACTIVITY_TYPE_ASSISTANT).isFullscreen()); 100 } 101 } 102 103 @FlakyTest(bugId = 69573940) 104 @Presubmit 105 @Test testAssistantStackZOrder()106 public void testAssistantStackZOrder() throws Exception { 107 assumeTrue(assistantRunsOnPrimaryDisplay()); 108 assumeTrue(supportsPip()); 109 assumeTrue(supportsSplitScreenMultiWindow()); 110 111 // Launch a pinned stack task 112 launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"); 113 waitForValidStateWithActivityTypeAndWindowingMode( 114 PIP_ACTIVITY, ACTIVITY_TYPE_STANDARD, WINDOWING_MODE_PINNED); 115 mAmWmState.assertContainsStack("Must contain pinned stack.", 116 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); 117 118 // Dock a task 119 launchActivitiesInSplitScreen( 120 getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), 121 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 122 mAmWmState.assertContainsStack("Must contain fullscreen stack.", 123 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD); 124 mAmWmState.assertContainsStack("Must contain docked stack.", 125 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD); 126 127 // Enable the assistant and launch an assistant activity, ensure it is on top 128 try (final AssistantSession assistantSession = new AssistantSession()) { 129 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 130 131 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION); 132 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 133 assertAssistantStackExists(); 134 135 mAmWmState.assertFrontStack("Pinned stack should be on top.", 136 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); 137 mAmWmState.assertFocusedStack("Assistant stack should be focused.", 138 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 139 } 140 } 141 142 @Test 143 @Presubmit testAssistantStackLaunchNewTask()144 public void testAssistantStackLaunchNewTask() throws Exception { 145 assertAssistantStackCanLaunchAndReturnFromNewTask(WINDOWING_MODE_FULLSCREEN); 146 } 147 148 @Test 149 @Presubmit 150 @Ignore("b/77272253#comment10") testAssistantStackLaunchNewTaskWithDockedStack()151 public void testAssistantStackLaunchNewTaskWithDockedStack() throws Exception { 152 assumeTrue(assistantRunsOnPrimaryDisplay()); 153 assumeTrue(supportsSplitScreenMultiWindow()); 154 155 // Dock a task 156 launchActivitiesInSplitScreen( 157 getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), 158 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 159 mAmWmState.assertContainsStack("Must contain fullscreen stack.", 160 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD); 161 mAmWmState.assertContainsStack("Must contain docked stack.", 162 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD); 163 164 assertAssistantStackCanLaunchAndReturnFromNewTask(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); 165 } 166 assertAssistantStackCanLaunchAndReturnFromNewTask(int expectedWindowingMode)167 private void assertAssistantStackCanLaunchAndReturnFromNewTask(int expectedWindowingMode) 168 throws Exception { 169 // Enable the assistant and launch an assistant activity which will launch a new task 170 try (final AssistantSession assistantSession = new AssistantSession()) { 171 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 172 173 launchActivityOnDisplayNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, mAssistantDisplayId, 174 EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY), 175 EXTRA_ASSISTANT_DISPLAY_ID, Integer.toString(mAssistantDisplayId)); 176 // Ensure that the fullscreen stack is on top and the test activity is now visible 177 waitForValidStateWithActivityTypeAndWindowingMode( 178 TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, expectedWindowingMode); 179 } 180 181 mAmWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY); 182 mAmWmState.assertFrontStack("Fullscreen stack should be on top.", 183 expectedWindowingMode, ACTIVITY_TYPE_STANDARD); 184 mAmWmState.assertFocusedStack("Fullscreen stack should be focused.", 185 expectedWindowingMode, ACTIVITY_TYPE_STANDARD); 186 187 // Now, tell it to finish itself and ensure that the assistant stack is brought back forward 188 executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH_SELF); 189 mAmWmState.waitForFocusedStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 190 mAmWmState.assertFrontStackActivityType( 191 "Assistant stack should be on top.", ACTIVITY_TYPE_ASSISTANT); 192 mAmWmState.assertFocusedStack("Assistant stack should be focused.", 193 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 194 } 195 196 @Test 197 @Presubmit 198 @FlakyTest(bugId = 71875631) testAssistantStackFinishToPreviousApp()199 public void testAssistantStackFinishToPreviousApp() throws Exception { 200 // Launch an assistant activity on top of an existing fullscreen activity, and ensure that 201 // the fullscreen activity is still visible and on top after the assistant activity finishes 202 launchActivityOnDisplay(TEST_ACTIVITY, mAssistantDisplayId); 203 try (final AssistantSession assistantSession = new AssistantSession()) { 204 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 205 206 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 207 EXTRA_ASSISTANT_FINISH_SELF, "true"); 208 mAmWmState.waitFor((amState, wmState) -> !amState.containsActivity(ASSISTANT_ACTIVITY), 209 "Waiting for " + getActivityName(ASSISTANT_ACTIVITY) + " finished"); 210 } 211 waitForValidStateWithActivityTypeAndWindowingMode( 212 TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, WINDOWING_MODE_FULLSCREEN); 213 mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED); 214 mAmWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY); 215 mAmWmState.assertFrontStack("Fullscreen stack should be on top.", 216 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 217 mAmWmState.assertFocusedStack("Fullscreen stack should be focused.", 218 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 219 } 220 221 @Test 222 @Presubmit 223 @FlakyTest(bugId = 71875631) testDisallowEnterPiPFromAssistantStack()224 public void testDisallowEnterPiPFromAssistantStack() throws Exception { 225 try (final AssistantSession assistantSession = new AssistantSession()) { 226 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 227 228 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 229 EXTRA_ASSISTANT_ENTER_PIP, "true"); 230 } 231 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 232 mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", 233 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); 234 } 235 236 @FlakyTest(bugId = 69573940) 237 @Presubmit 238 @Test testTranslucentAssistantActivityStackVisibility()239 public void testTranslucentAssistantActivityStackVisibility() throws Exception { 240 try (final AssistantSession assistantSession = new AssistantSession()) { 241 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 242 243 // Go home, launch the assistant and check to see that home is visible 244 removeStacksInWindowingModes(WINDOWING_MODE_FULLSCREEN, 245 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); 246 launchHomeActivity(); 247 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 248 EXTRA_ASSISTANT_IS_TRANSLUCENT, "true"); 249 waitForValidStateWithActivityType( 250 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 251 assertAssistantStackExists(); 252 mAmWmState.waitForHomeActivityVisible(); 253 if (hasHomeScreen()) { 254 mAmWmState.assertHomeActivityVisible(true); 255 } 256 257 // Launch a fullscreen app and then launch the assistant and check to see that it is 258 // also visible 259 removeStacksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 260 launchActivityOnDisplay(TEST_ACTIVITY, mAssistantDisplayId); 261 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 262 EXTRA_ASSISTANT_IS_TRANSLUCENT, "true"); 263 waitForValidStateWithActivityType( 264 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 265 assertAssistantStackExists(); 266 mAmWmState.assertVisibility(TEST_ACTIVITY, true); 267 268 // Go home, launch assistant, launch app into fullscreen with activity present, and go 269 // back.Ensure home is visible. 270 removeStacksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 271 launchHomeActivity(); 272 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 273 EXTRA_ASSISTANT_IS_TRANSLUCENT, "true", 274 EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY)); 275 waitForValidStateWithActivityTypeAndWindowingMode( 276 TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, WINDOWING_MODE_FULLSCREEN); 277 boolean isTranslucent = mAmWmState.getAmState().isActivityTranslucent(TEST_ACTIVITY); 278 // Home should be visible if the occluding activity is translucent, else home shouldn't 279 // be visible. 280 mAmWmState.assertHomeActivityVisible(isTranslucent); 281 pressBackButton(); 282 mAmWmState.waitForFocusedStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 283 assertAssistantStackExists(); 284 mAmWmState.waitForHomeActivityVisible(); 285 if (hasHomeScreen()) { 286 mAmWmState.assertHomeActivityVisible(true); 287 } 288 289 // Launch a fullscreen and docked app and then launch the assistant and check to see 290 // that it 291 // is also visible 292 if (supportsSplitScreenMultiWindow() && assistantRunsOnPrimaryDisplay()) { 293 removeStacksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 294 launchActivitiesInSplitScreen( 295 getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), 296 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 297 mAmWmState.assertContainsStack("Must contain docked stack.", 298 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD); 299 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 300 EXTRA_ASSISTANT_IS_TRANSLUCENT, "true"); 301 waitForValidStateWithActivityType( 302 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 303 assertAssistantStackExists(); 304 mAmWmState.assertVisibility(DOCKED_ACTIVITY, true); 305 mAmWmState.assertVisibility(TEST_ACTIVITY, true); 306 } 307 } 308 } 309 310 @FlakyTest(bugId = 69229402) 311 @Test 312 @Presubmit testLaunchIntoSameTask()313 public void testLaunchIntoSameTask() throws Exception { 314 try (final AssistantSession assistantSession = new AssistantSession()) { 315 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 316 317 // Launch the assistant 318 launchActivityOnDisplayNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION, 319 mAssistantDisplayId); 320 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 321 assertAssistantStackExists(); 322 mAmWmState.assertVisibility(ASSISTANT_ACTIVITY, true); 323 mAmWmState.assertFocusedStack("Expected assistant stack focused", 324 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 325 final ActivityManagerState amState = mAmWmState.getAmState(); 326 assertThat(amState.getStackByActivityType(ACTIVITY_TYPE_ASSISTANT).getTasks(), 327 hasSize(1)); 328 final int taskId = mAmWmState.getAmState().getTaskByActivity(ASSISTANT_ACTIVITY) 329 .mTaskId; 330 331 // Launch a new fullscreen activity 332 // Using Animation Test Activity because it is opaque on all devices. 333 launchActivityOnDisplay(ANIMATION_TEST_ACTIVITY, mAssistantDisplayId); 334 // Wait for animation finished. 335 mAmWmState.waitForActivityState(ANIMATION_TEST_ACTIVITY, STATE_RESUMED); 336 mAmWmState.assertVisibility(ASSISTANT_ACTIVITY, false); 337 338 // Launch the assistant again and ensure that it goes into the same task 339 launchActivityOnDisplayNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION, 340 mAssistantDisplayId); 341 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 342 assertAssistantStackExists(); 343 mAmWmState.assertVisibility(ASSISTANT_ACTIVITY, true); 344 mAmWmState.assertFocusedStack("Expected assistant stack focused", 345 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 346 assertThat(amState.getStackByActivityType(ACTIVITY_TYPE_ASSISTANT).getTasks(), 347 hasSize(1)); 348 assertEquals(taskId, 349 mAmWmState.getAmState().getTaskByActivity(ASSISTANT_ACTIVITY).mTaskId); 350 351 } 352 } 353 354 @Test testPinnedStackWithAssistant()355 public void testPinnedStackWithAssistant() throws Exception { 356 assumeTrue(supportsPip()); 357 assumeTrue(supportsSplitScreenMultiWindow()); 358 359 try (final AssistantSession assistantSession = new AssistantSession()) { 360 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 361 362 // Launch a fullscreen activity and a PIP activity, then launch the assistant, and 363 // ensure that the test activity is still visible 364 launchActivity(TEST_ACTIVITY); 365 launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"); 366 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 367 EXTRA_ASSISTANT_IS_TRANSLUCENT, String.valueOf(true)); 368 waitForValidStateWithActivityType( 369 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 370 assertAssistantStackExists(); 371 mAmWmState.assertVisibility(TRANSLUCENT_ASSISTANT_ACTIVITY, true); 372 mAmWmState.assertVisibility(PIP_ACTIVITY, true); 373 mAmWmState.assertVisibility(TEST_ACTIVITY, true); 374 375 } 376 } 377 waitForValidStateWithActivityType(ComponentName activityName, int activityType)378 private void waitForValidStateWithActivityType(ComponentName activityName, int activityType) 379 throws Exception { 380 mAmWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName) 381 .setActivityType(activityType) 382 .build()); 383 } 384 waitForValidStateWithActivityTypeAndWindowingMode(ComponentName activityName, int activityType, int windowingMode)385 private void waitForValidStateWithActivityTypeAndWindowingMode(ComponentName activityName, 386 int activityType, int windowingMode) throws Exception { 387 mAmWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName) 388 .setActivityType(activityType) 389 .setWindowingMode(windowingMode) 390 .build()); 391 } 392 393 /** 394 * Asserts that the assistant stack exists. 395 */ assertAssistantStackExists()396 private void assertAssistantStackExists() throws Exception { 397 mAmWmState.assertContainsStack("Must contain assistant stack.", 398 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 399 } 400 401 // Any 2D Activity in VR mode is run on a special VR virtual display, so check if the Assistant 402 // is going to run on the same display as other tasks. assistantRunsOnPrimaryDisplay()403 protected boolean assistantRunsOnPrimaryDisplay() { 404 return mAssistantDisplayId == DEFAULT_DISPLAY; 405 } 406 407 /** Helper class to save, set, and restore 408 * {@link Settings.Secure#VOICE_INTERACTION_SERVICE} system preference. 409 */ 410 private static class AssistantSession extends SettingsSession<String> { AssistantSession()411 AssistantSession() { 412 super(Settings.Secure.getUriFor(Settings.Secure.VOICE_INTERACTION_SERVICE), 413 Settings.Secure::getString, Settings.Secure::putString); 414 } 415 setVoiceInteractionService(ComponentName assistantName)416 void setVoiceInteractionService(ComponentName assistantName) throws Exception { 417 super.set(getActivityName(assistantName)); 418 } 419 } 420 } 421