1 /* 2 * Copyright (C) 2021 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.translation.cts; 18 19 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE; 20 import static android.content.Context.TRANSLATION_MANAGER_SERVICE; 21 import static android.provider.Settings.Global.ANIMATOR_DURATION_SCALE; 22 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_FINISH; 23 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_PAUSE; 24 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_RESUME; 25 import static android.translation.cts.Helper.ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_START; 26 import static android.translation.cts.Helper.ACTION_REGISTER_UI_TRANSLATION_CALLBACK; 27 import static android.translation.cts.Helper.ACTION_UNREGISTER_UI_TRANSLATION_CALLBACK; 28 import static android.translation.cts.Helper.EXTRA_CALL_COUNT; 29 import static android.translation.cts.Helper.EXTRA_FINISH_COMMAND; 30 import static android.translation.cts.Helper.EXTRA_PACKAGE_NAME; 31 import static android.translation.cts.Helper.EXTRA_SOURCE_LOCALE; 32 import static android.translation.cts.Helper.EXTRA_TARGET_LOCALE; 33 import static android.view.translation.TranslationResponseValue.STATUS_SUCCESS; 34 35 import static com.android.compatibility.common.util.ShellUtils.runShellCommand; 36 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 37 38 import static com.google.common.truth.Truth.assertThat; 39 40 import static org.mockito.ArgumentMatchers.any; 41 import static org.mockito.ArgumentMatchers.eq; 42 43 import android.app.PendingIntent; 44 import android.content.ComponentName; 45 import android.content.ContentResolver; 46 import android.content.Context; 47 import android.content.Intent; 48 import android.icu.util.ULocale; 49 import android.os.SystemClock; 50 import android.platform.test.annotations.AppModeFull; 51 import android.provider.Settings; 52 import android.service.contentcapture.ContentCaptureService; 53 import android.service.translation.TranslationService; 54 import android.translation.cts.views.CustomTextView; 55 import android.translation.cts.views.ResponseNotSetTextView; 56 import android.translation.cts.views.VirtualContainerView; 57 import android.util.Log; 58 import android.util.LongSparseArray; 59 import android.util.Pair; 60 import android.view.View; 61 import android.view.autofill.AutofillId; 62 import android.view.contentcapture.ContentCaptureContext; 63 import android.view.inputmethod.InputMethodManager; 64 import android.view.translation.TranslationContext; 65 import android.view.translation.TranslationRequest; 66 import android.view.translation.TranslationResponse; 67 import android.view.translation.TranslationResponseValue; 68 import android.view.translation.TranslationSpec; 69 import android.view.translation.UiTranslationManager; 70 import android.view.translation.UiTranslationSpec; 71 import android.view.translation.UiTranslationStateCallback; 72 import android.view.translation.ViewTranslationCallback; 73 import android.view.translation.ViewTranslationRequest; 74 import android.view.translation.ViewTranslationResponse; 75 import android.widget.TextView; 76 77 import androidx.lifecycle.Lifecycle; 78 import androidx.test.core.app.ActivityScenario; 79 import androidx.test.core.app.ApplicationProvider; 80 import androidx.test.filters.FlakyTest; 81 import androidx.test.runner.AndroidJUnit4; 82 83 import com.android.compatibility.common.util.ApiTest; 84 import com.android.compatibility.common.util.BlockingBroadcastReceiver; 85 import com.android.compatibility.common.util.PollingCheck; 86 import com.android.compatibility.common.util.RequiredServiceRule; 87 import com.android.compatibility.common.util.SystemUtil; 88 import com.android.compatibility.common.util.TestNameUtils; 89 90 import org.junit.After; 91 import org.junit.AfterClass; 92 import org.junit.Before; 93 import org.junit.BeforeClass; 94 import org.junit.Rule; 95 import org.junit.Test; 96 import org.junit.runner.RunWith; 97 import org.mockito.ArgumentCaptor; 98 import org.mockito.Mockito; 99 100 import java.util.List; 101 import java.util.concurrent.Executor; 102 import java.util.concurrent.Executors; 103 import java.util.concurrent.atomic.AtomicReference; 104 105 106 /** 107 * Tests for {@link UiTranslationManager} related APIs. 108 * 109 * <p> 110 * {@link UiTranslationManager} needs a token that reports by {@link ContentCaptureService}. We use 111 * a non pre-configured {@link ContentCaptureService} and a {@link TranslationService} temporary 112 * service for CTS tests that is set via shell command. The test will get the token from the 113 * {@link ContentCaptureService} then uses this token in {@link UiTranslationManager} APIs.</p> 114 */ 115 116 @FlakyTest(bugId = 285979174) 117 @AppModeFull(reason = "TODO(b/182330968): disable instant mode. Re-enable after we decouple the " 118 + "service from the test package.") 119 @RunWith(AndroidJUnit4.class) 120 public class UiTranslationManagerTest { 121 122 private static final String TAG = "UiTranslationManagerTest"; 123 124 private static final long UI_WAIT_TIMEOUT = 2500; 125 126 // TODO: Use fw definition when it becomes public or testapi 127 private static final String ID_CONTENT_DESCRIPTION = "android:content_description"; 128 129 // TODO(b/225466478): This should have a different package from CtsTestIme 130 // Should be whatever package this class is in 131 private static final String CTS_TESTS_PACKAGE = "android.translation.cts"; 132 133 private static Context sContext; 134 private static CtsTranslationService.TranslationReplier sTranslationReplier; 135 136 private CtsContentCaptureService.ServiceWatcher mContentCaptureServiceWatcher; 137 private CtsTranslationService.ServiceWatcher mTranslationServiceServiceWatcher; 138 private ActivityScenario<SimpleActivity> mActivityScenario; 139 private ActivityScenario<VirtualContainerViewActivity> mVirtualContainerViewActivityScenario; 140 private ActivityScenario<CustomTextViewActivity> mCustomTextViewActivityScenario; 141 142 private VirtualContainerView mVirtualContainerView; 143 private ResponseNotSetTextView mResponseNotSetTextView; 144 private CustomTextView mCustomTextView; 145 private SimpleActivity mSimpleActivity; 146 private TextView mTextView; 147 private static String sOriginalLogTag; 148 149 @Rule 150 public final RequiredServiceRule mContentCaptureServiceRule = 151 new RequiredServiceRule(CONTENT_CAPTURE_MANAGER_SERVICE); 152 153 @Rule 154 public final RequiredServiceRule mTranslationServiceRule = 155 new RequiredServiceRule(TRANSLATION_MANAGER_SERVICE); 156 157 @Rule 158 public final TranslationTestWatcher mTranslationTestWatcher = new TranslationTestWatcher(); 159 160 @BeforeClass oneTimeSetup()161 public static void oneTimeSetup() { 162 sContext = ApplicationProvider.getApplicationContext(); 163 sTranslationReplier = CtsTranslationService.getTranslationReplier(); 164 sOriginalLogTag = Helper.enableDebugLog(); 165 166 Helper.allowSelfForContentCapture(sContext); 167 Helper.setDefaultContentCaptureServiceEnabled(/* enabled= */ false); 168 } 169 170 @AfterClass oneTimeReset()171 public static void oneTimeReset() { 172 Helper.unAllowSelfForContentCapture(sContext); 173 Helper.setDefaultContentCaptureServiceEnabled(/* enabled= */ true); 174 Helper.disableDebugLog(sOriginalLogTag); 175 } 176 177 @Before setup()178 public void setup() throws Exception { 179 CtsContentCaptureService.resetStaticState(); 180 CtsTranslationService.resetStaticState(); 181 } 182 183 @After cleanup()184 public void cleanup() throws Exception { 185 if (mActivityScenario != null) { 186 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 187 } 188 if (mVirtualContainerViewActivityScenario != null) { 189 mVirtualContainerViewActivityScenario.moveToState(Lifecycle.State.DESTROYED); 190 } 191 Helper.resetTemporaryContentCaptureService(); 192 Helper.resetTemporaryTranslationService(); 193 } 194 195 @Test testTranslationAfterStartActivityOnSameTask()196 public void testTranslationAfterStartActivityOnSameTask() throws Throwable { 197 final Pair<List<AutofillId>, ContentCaptureContext> result = 198 enableServicesAndStartActivityForTranslation(); 199 200 final List<AutofillId> views = result.first; 201 final ContentCaptureContext contentCaptureContext = result.second; 202 203 // Register callback 204 UiTranslationManager manager = 205 sContext.getSystemService(UiTranslationManager.class); 206 final Executor executor = Executors.newSingleThreadExecutor(); 207 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 208 manager.registerUiTranslationStateCallback(executor, mockCallback); 209 210 try { 211 final String translatedText = "success"; 212 // Set response 213 final TranslationResponse response = 214 createViewsTranslationResponse(views, translatedText); 215 sTranslationReplier.addResponse(response); 216 217 // Start an Activity in the same task then call translation APIs 218 mSimpleActivity.startEmptyActivity(); 219 220 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 221 222 assertScreenText(mTextView, translatedText); 223 224 Mockito.verify(mockCallback, Mockito.times(1)) 225 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 226 227 pauseUiTranslation(contentCaptureContext); 228 229 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 230 231 resumeUiTranslation(contentCaptureContext); 232 233 Mockito.verify(mockCallback, Mockito.times(1)) 234 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 235 236 finishUiTranslation(contentCaptureContext); 237 238 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 239 } finally { 240 manager.unregisterUiTranslationStateCallback(mockCallback); 241 } 242 } 243 244 @Test testUiTranslation()245 public void testUiTranslation() throws Throwable { 246 try { 247 final Pair<List<AutofillId>, ContentCaptureContext> result = 248 enableServicesAndStartActivityForTranslation(); 249 250 final CharSequence originalText = mTextView.getText(); 251 final List<AutofillId> views = result.first; 252 final ContentCaptureContext contentCaptureContext = result.second; 253 254 final String translatedText = "success"; 255 // Set response 256 final TranslationResponse response = 257 createViewsTranslationResponse(views, translatedText); 258 sTranslationReplier.addResponse(response); 259 260 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 261 262 // Check request 263 final TranslationRequest request = sTranslationReplier.getNextTranslationRequest(); 264 final List<ViewTranslationRequest> requests = request.getViewTranslationRequests(); 265 final ViewTranslationRequest viewRequest = requests.get(0); 266 assertThat(viewRequest.getAutofillId()).isEqualTo(views.get(0)); 267 assertThat(viewRequest.getKeys().size()).isEqualTo(1); 268 assertThat(viewRequest.getKeys()).containsExactly(ViewTranslationRequest.ID_TEXT); 269 assertThat(viewRequest.getValue(ViewTranslationRequest.ID_TEXT).getText()) 270 .isEqualTo(originalText.toString()); 271 CtsTranslationService translationService = 272 mTranslationServiceServiceWatcher.getService(); 273 TranslationContext translationContext = translationService.getTranslationContext(); 274 assertThat(translationContext).isNotNull(); 275 assertThat(translationContext.getActivityId()).isNotNull(); 276 assertThat(translationContext.getActivityId()) 277 .isEqualTo(contentCaptureContext.getActivityId()); 278 279 assertScreenText(mTextView, translatedText); 280 assertThat(mTextView.getViewTranslationResponse()) 281 .isEqualTo(response.getViewTranslationResponses().get(0)); 282 283 pauseUiTranslation(contentCaptureContext); 284 285 assertScreenText(mTextView, originalText.toString()); 286 287 resumeUiTranslation(contentCaptureContext); 288 289 assertScreenText(mTextView, translatedText); 290 291 finishUiTranslation(contentCaptureContext); 292 293 assertScreenText(mTextView, originalText.toString()); 294 295 // Check the Translation session is destroyed after calling finishTranslation() 296 translationService.awaitSessionDestroyed(); 297 298 // Test re-translating. 299 sTranslationReplier.addResponse(createViewsTranslationResponse(views, translatedText)); 300 301 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 302 303 assertScreenText(mTextView, translatedText); 304 305 // Also make sure pausing still works. 306 pauseUiTranslation(contentCaptureContext); 307 308 assertScreenText(mTextView, originalText.toString()); 309 } catch (Throwable t) { 310 Helper.takeScreenshotAndSave(sContext, TestNameUtils.getCurrentTestName(), 311 Helper.LOCAL_TEST_FILES_DIR); 312 throw t; 313 } 314 } 315 316 @Test testUiTranslationWithoutAnimation()317 public void testUiTranslationWithoutAnimation() throws Throwable { 318 final float[] originalAnimationDurationScale = new float[1]; 319 try { 320 // Disable animation 321 SystemUtil.runWithShellPermissionIdentity(() -> { 322 ContentResolver resolver = 323 ApplicationProvider.getApplicationContext().getContentResolver(); 324 originalAnimationDurationScale[0] = 325 Settings.Global.getFloat(resolver, ANIMATOR_DURATION_SCALE, 1f); 326 Settings.Global.putFloat(resolver, ANIMATOR_DURATION_SCALE, 0); 327 }); 328 329 final Pair<List<AutofillId>, ContentCaptureContext> result = 330 enableServicesAndStartActivityForTranslation(); 331 332 final CharSequence originalText = mTextView.getText(); 333 final List<AutofillId> views = result.first; 334 final ContentCaptureContext contentCaptureContext = result.second; 335 336 final String translatedText = "success"; 337 // Set response 338 final TranslationResponse response = 339 createViewsTranslationResponse(views, translatedText); 340 sTranslationReplier.addResponse(response); 341 342 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 343 344 assertScreenText(mTextView, translatedText); 345 346 pauseUiTranslation(contentCaptureContext); 347 348 assertScreenText(mTextView, originalText.toString()); 349 350 resumeUiTranslation(contentCaptureContext); 351 352 assertScreenText(mTextView, translatedText); 353 354 finishUiTranslation(contentCaptureContext); 355 356 assertScreenText(mTextView, originalText.toString()); 357 } finally { 358 // restore animation 359 SystemUtil.runWithShellPermissionIdentity(() -> { 360 Settings.Global.putFloat( 361 ApplicationProvider.getApplicationContext().getContentResolver(), 362 ANIMATOR_DURATION_SCALE, originalAnimationDurationScale[0]); 363 }); 364 } 365 } 366 367 @Test testPauseUiTranslationThenStartUiTranslation()368 public void testPauseUiTranslationThenStartUiTranslation() throws Throwable { 369 final Pair<List<AutofillId>, ContentCaptureContext> result = 370 enableServicesAndStartActivityForTranslation(); 371 372 final CharSequence originalText = mTextView.getText(); 373 final List<AutofillId> views = result.first; 374 final ContentCaptureContext contentCaptureContext = result.second; 375 376 final String translatedText = "success"; 377 // Set response 378 final TranslationResponse response = 379 createViewsTranslationResponse(views, translatedText); 380 sTranslationReplier.addResponse(response); 381 382 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 383 384 assertScreenText(mTextView, translatedText); 385 386 pauseUiTranslation(contentCaptureContext); 387 388 assertScreenText(mTextView, originalText.toString()); 389 390 sTranslationReplier.addResponse(createViewsTranslationResponse(views, translatedText)); 391 392 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 393 394 assertScreenText(mTextView, translatedText); 395 } 396 397 @Test testUiTranslation_CustomViewTranslationCallback()398 public void testUiTranslation_CustomViewTranslationCallback() throws Throwable { 399 final Pair<List<AutofillId>, ContentCaptureContext> result = 400 enableServicesAndStartActivityForTranslation(); 401 final List<AutofillId> views = result.first; 402 final ContentCaptureContext contentCaptureContext = result.second; 403 404 // Set ViewTranslationCallback 405 ViewTranslationCallback mockCallback = Mockito.mock(ViewTranslationCallback.class); 406 mTextView.setViewTranslationCallback(mockCallback); 407 // Set response 408 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 409 410 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 411 412 ArgumentCaptor<View> viewArgumentCaptor = ArgumentCaptor.forClass(View.class); 413 Mockito.verify(mockCallback, Mockito.times(1)).onShowTranslation( 414 viewArgumentCaptor.capture()); 415 TextView capturedView = (TextView) viewArgumentCaptor.getValue(); 416 assertThat(capturedView.getAutofillId()).isEqualTo(mTextView.getAutofillId()); 417 418 pauseUiTranslation(contentCaptureContext); 419 420 Mockito.verify(mockCallback, Mockito.times(1)).onHideTranslation( 421 viewArgumentCaptor.capture()); 422 capturedView = (TextView) viewArgumentCaptor.getValue(); 423 assertThat(capturedView.getAutofillId()).isEqualTo(mTextView.getAutofillId()); 424 425 resumeUiTranslation(contentCaptureContext); 426 427 Mockito.verify(mockCallback, Mockito.times(2)).onShowTranslation( 428 viewArgumentCaptor.capture()); 429 capturedView = (TextView) viewArgumentCaptor.getValue(); 430 assertThat(capturedView.getAutofillId()).isEqualTo(mTextView.getAutofillId()); 431 432 // Clear callback 433 mTextView.clearViewTranslationCallback(); 434 435 finishUiTranslation(contentCaptureContext); 436 437 // Verify callback does not be called, keep the latest state 438 Mockito.verify(mockCallback, Mockito.never()).onClearTranslation(any(View.class)); 439 440 // Finally, verify that no unexpected interactions occurred. We cannot use 441 // verifyNoMoreInteractions as the callback has some hidden methods. 442 Mockito.verify(mockCallback, Mockito.times(2)).onShowTranslation(any()); 443 Mockito.verify(mockCallback, Mockito.times(1)).onHideTranslation(any()); 444 } 445 446 447 @Test 448 @ApiTest(apis = {"android.view.translation.UiTranslationManagerTest#startUiTranslation", 449 "android.view.View#setViewTranslationCallback"}) testUiTranslation_CustomViewTranslationCallback_DetachAndReattach()450 public void testUiTranslation_CustomViewTranslationCallback_DetachAndReattach() 451 throws Throwable { 452 final Pair<List<AutofillId>, ContentCaptureContext> result = 453 enableServicesAndStartActivityForTranslation(); 454 final List<AutofillId> views = result.first; 455 final ContentCaptureContext contentCaptureContext = result.second; 456 457 // Set ViewTranslationCallback 458 ViewTranslationCallback mockCallback = Mockito.mock(ViewTranslationCallback.class); 459 mTextView.setViewTranslationCallback(mockCallback); 460 // Set response 461 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 462 463 mActivityScenario.onActivity(activity -> { 464 // Toggling the visibility will cause detach and reattach. This test ensures the 465 // custom callback is not cleared when this happens. 466 mTextView.setVisibility(View.INVISIBLE); 467 mTextView.setVisibility(View.VISIBLE); 468 }); 469 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 470 471 ArgumentCaptor<View> viewArgumentCaptor = ArgumentCaptor.forClass(View.class); 472 Mockito.verify(mockCallback, Mockito.times(1)).onShowTranslation( 473 viewArgumentCaptor.capture()); 474 TextView capturedView = (TextView) viewArgumentCaptor.getValue(); 475 assertThat(capturedView.getAutofillId()).isEqualTo(mTextView.getAutofillId()); 476 } 477 478 @Test testUiTranslation_ViewTranslationCallback_paddingText()479 public void testUiTranslation_ViewTranslationCallback_paddingText() throws Throwable { 480 try { 481 final Pair<List<AutofillId>, ContentCaptureContext> result = 482 enableServicesAndStartActivityForTranslation(); 483 final List<AutofillId> views = result.first; 484 final ContentCaptureContext contentCaptureContext = result.second; 485 486 // Set response 487 final CharSequence originalText = mTextView.getText(); 488 final CharSequence translatedText = "Translated World"; 489 sTranslationReplier.addResponse( 490 createViewsTranslationResponse(views, translatedText.toString())); 491 492 // Use TextView default ViewTranslationCallback implementation 493 startUiTranslation(/* shouldPadContent */ true, views, contentCaptureContext); 494 495 CharSequence currentText = mTextView.getText(); 496 assertThat(currentText.length()).isNotEqualTo(originalText.length()); 497 assertThat(currentText.length()).isEqualTo(translatedText.length()); 498 499 finishUiTranslation(contentCaptureContext); 500 501 // Set Customized ViewTranslationCallback 502 ViewTranslationCallback mockCallback = Mockito.mock(ViewTranslationCallback.class); 503 mTextView.setViewTranslationCallback(mockCallback); 504 505 startUiTranslation(/* shouldPadContent */ true, views, contentCaptureContext); 506 507 assertThat(mTextView.getText().length()).isEqualTo(originalText.length()); 508 } catch (Throwable t) { 509 Helper.takeScreenshotAndSave(sContext, TestNameUtils.getCurrentTestName(), 510 Helper.LOCAL_TEST_FILES_DIR); 511 throw t; 512 } 513 } 514 515 @Test testUiTranslation_hasContentDescription()516 public void testUiTranslation_hasContentDescription() throws Throwable { 517 try { 518 final Pair<List<AutofillId>, ContentCaptureContext> result = 519 enableServicesAndStartActivityForTranslation(); 520 final List<AutofillId> views = result.first; 521 final ContentCaptureContext contentCaptureContext = result.second; 522 523 // Set response 524 final CharSequence translatedText = "Translated World"; 525 final CharSequence originalDescription = "Hello Description"; 526 mActivityScenario.onActivity(activity -> { 527 mTextView.setContentDescription(originalDescription); 528 }); 529 sTranslationReplier.addResponse( 530 createViewsTranslationResponse(views, translatedText.toString())); 531 532 // Use TextView default ViewTranslationCallback implementation 533 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 534 535 assertThat(mTextView.getContentDescription().toString()) 536 .isEqualTo(translatedText.toString()); 537 538 // Check request to make sure the content description key doesn't be changed 539 final TranslationRequest request = sTranslationReplier.getNextTranslationRequest(); 540 final List<ViewTranslationRequest> requests = request.getViewTranslationRequests(); 541 final ViewTranslationRequest viewRequest = requests.get(0); 542 assertThat(viewRequest.getAutofillId()).isEqualTo(views.get(0)); 543 assertThat(viewRequest.getKeys().size()).isEqualTo(2); 544 assertThat(viewRequest.getKeys()).containsExactly(ID_CONTENT_DESCRIPTION, 545 ViewTranslationRequest.ID_TEXT); 546 assertThat(viewRequest.getValue(ID_CONTENT_DESCRIPTION).getText()) 547 .isEqualTo(originalDescription); 548 549 pauseUiTranslation(contentCaptureContext); 550 551 assertThat(mTextView.getContentDescription().toString()) 552 .isEqualTo(originalDescription.toString()); 553 554 resumeUiTranslation(contentCaptureContext); 555 556 assertThat(mTextView.getContentDescription().toString()) 557 .isEqualTo(translatedText.toString()); 558 559 finishUiTranslation(contentCaptureContext); 560 561 assertThat(mTextView.getContentDescription().toString()) 562 .isEqualTo(originalDescription.toString()); 563 } catch (Throwable t) { 564 Helper.takeScreenshotAndSave(sContext, TestNameUtils.getCurrentTestName(), 565 Helper.LOCAL_TEST_FILES_DIR); 566 throw t; 567 } 568 } 569 570 @Test testIMEUiTranslationStateCallback()571 public void testIMEUiTranslationStateCallback() throws Throwable { 572 try (ImeSession imeSession = new ImeSession( 573 new ComponentName(CtsTestIme.IME_SERVICE_PACKAGE, CtsTestIme.class.getName()))) { 574 575 final Pair<List<AutofillId>, ContentCaptureContext> result = 576 enableServicesAndStartActivityForTranslation(); 577 final List<AutofillId> views = result.first; 578 final ContentCaptureContext contentCaptureContext = result.second; 579 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 580 581 // Send broadcast to request IME to register callback 582 BlockingBroadcastReceiver registerResultReceiver = 583 sendCommandToIme(ACTION_REGISTER_UI_TRANSLATION_CALLBACK, false); 584 // Get result 585 registerResultReceiver.awaitForBroadcast(); 586 registerResultReceiver.unregisterQuietly(); 587 588 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 589 590 // Send broadcast to request IME to check the onStarted() result 591 BlockingBroadcastReceiver onStartResultReceiver = sendCommandToIme( 592 ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_START, true); 593 // Get result to check the onStarted() was called 594 Intent onStartIntent = onStartResultReceiver.awaitForBroadcast(); 595 ULocale receivedSource = 596 onStartIntent.getSerializableExtra(EXTRA_SOURCE_LOCALE, ULocale.class); 597 ULocale receivedTarget = 598 onStartIntent.getSerializableExtra(EXTRA_TARGET_LOCALE, ULocale.class); 599 int startedCallCount = onStartIntent.getIntExtra(EXTRA_CALL_COUNT, -999); 600 String startedPackageName = onStartIntent.getStringExtra(EXTRA_PACKAGE_NAME); 601 assertThat(receivedSource).isEqualTo(ULocale.ENGLISH); 602 assertThat(receivedTarget).isEqualTo(ULocale.FRENCH); 603 assertThat(startedCallCount).isEqualTo(1); 604 assertThat(startedPackageName).isEqualTo(CTS_TESTS_PACKAGE); 605 onStartResultReceiver.unregisterQuietly(); 606 607 pauseUiTranslation(contentCaptureContext); 608 609 // Send broadcast to request IME to check the onPaused() result 610 BlockingBroadcastReceiver onPausedResultReceiver = sendCommandToIme( 611 ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_PAUSE, true); 612 // Get result to check the onPaused() was called 613 Intent onPausedIntent = onPausedResultReceiver.awaitForBroadcast(); 614 int pausedCallCount = onPausedIntent.getIntExtra(EXTRA_CALL_COUNT, -999); 615 String pausedPackageName = onPausedIntent.getStringExtra(EXTRA_PACKAGE_NAME); 616 assertThat(pausedCallCount).isEqualTo(1); 617 assertThat(pausedPackageName).isEqualTo(CTS_TESTS_PACKAGE); 618 onPausedResultReceiver.unregisterQuietly(); 619 620 resumeUiTranslation(contentCaptureContext); 621 622 // Send broadcast to request IME to check the onResumed result 623 BlockingBroadcastReceiver onResumedResultReceiver = sendCommandToIme( 624 ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_RESUME, true); 625 // Get result to check the onResumed was called 626 Intent onResumedIntent = onResumedResultReceiver.awaitForBroadcast(); 627 int resumedCallCount = onResumedIntent.getIntExtra(EXTRA_CALL_COUNT, -999); 628 String resumedPackageName = onResumedIntent.getStringExtra(EXTRA_PACKAGE_NAME); 629 assertThat(resumedCallCount).isEqualTo(1); 630 assertThat(resumedPackageName).isEqualTo(CTS_TESTS_PACKAGE); 631 onResumedResultReceiver.unregisterQuietly(); 632 633 // Send broadcast to request IME to unregister callback 634 BlockingBroadcastReceiver unRegisterResultReceiver 635 = sendCommandToIme(ACTION_UNREGISTER_UI_TRANSLATION_CALLBACK, false); 636 unRegisterResultReceiver.awaitForBroadcast(); 637 unRegisterResultReceiver.unregisterQuietly(); 638 639 finishUiTranslation(contentCaptureContext); 640 641 BlockingBroadcastReceiver onFinishResultReceiver = 642 sendCommandToIme(ACTION_ASSERT_UI_TRANSLATION_CALLBACK_ON_FINISH, true); 643 // Get result to check onFinish() isn't called. 644 Intent onFinishIntent = onFinishResultReceiver.awaitForBroadcast(); 645 int finishedCallCount = onFinishIntent.getIntExtra(EXTRA_CALL_COUNT, -999); 646 String finishedPackageName = onFinishIntent.getStringExtra(EXTRA_PACKAGE_NAME); 647 assertThat(finishedCallCount).isEqualTo(0); 648 assertThat(finishedPackageName).isNull(); 649 onFinishResultReceiver.unregisterQuietly(); 650 651 // TODO(b/191417938): add tests for the Activity destroyed for IME package callback 652 } 653 } 654 655 @Test testNonIMEUiTranslationStateCallback()656 public void testNonIMEUiTranslationStateCallback() throws Throwable { 657 final Pair<List<AutofillId>, ContentCaptureContext> result = 658 enableServicesAndStartActivityForTranslation(); 659 660 final List<AutofillId> views = result.first; 661 final ContentCaptureContext contentCaptureContext = result.second; 662 663 UiTranslationManager manager = 664 sContext.getSystemService(UiTranslationManager.class); 665 // Set response 666 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 667 668 // Register callback 669 final Executor executor = Executors.newSingleThreadExecutor(); 670 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 671 manager.registerUiTranslationStateCallback(executor, mockCallback); 672 673 try { 674 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 675 676 // TODO(b/191417938): add tests for the Activity isn't the same package of the 677 // registered callback app 678 Mockito.verify(mockCallback, Mockito.times(1)) 679 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 680 681 pauseUiTranslation(contentCaptureContext); 682 683 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 684 685 resumeUiTranslation(contentCaptureContext); 686 687 Mockito.verify(mockCallback, Mockito.times(1)) 688 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 689 690 finishUiTranslation(contentCaptureContext); 691 692 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 693 694 // Make sure onFinished will not be called twice. 695 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 696 mActivityScenario = null; 697 SystemClock.sleep(UI_WAIT_TIMEOUT); 698 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 699 } finally { 700 manager.unregisterUiTranslationStateCallback(mockCallback); 701 } 702 } 703 704 @Test testActivityDestroyedWithoutFinishTranslation()705 public void testActivityDestroyedWithoutFinishTranslation() throws Throwable { 706 final Pair<List<AutofillId>, ContentCaptureContext> result = 707 enableServicesAndStartActivityForTranslation(); 708 709 final List<AutofillId> views = result.first; 710 final ContentCaptureContext contentCaptureContext = result.second; 711 712 UiTranslationManager manager = 713 sContext.getSystemService(UiTranslationManager.class); 714 // Set response 715 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 716 717 // Register callback 718 final Executor executor = Executors.newSingleThreadExecutor(); 719 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 720 manager.registerUiTranslationStateCallback(executor, mockCallback); 721 722 try { 723 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 724 725 Mockito.verify(mockCallback, Mockito.times(1)) 726 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 727 728 pauseUiTranslation(contentCaptureContext); 729 730 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 731 732 resumeUiTranslation(contentCaptureContext); 733 734 Mockito.verify(mockCallback, Mockito.times(1)) 735 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 736 737 // Make sure onFinished will still be called if Activity is destroyed, even without a 738 // finishTranslation call. 739 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 740 mActivityScenario = null; 741 SystemClock.sleep(UI_WAIT_TIMEOUT); 742 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 743 } finally { 744 manager.unregisterUiTranslationStateCallback(mockCallback); 745 } 746 } 747 748 @Test testCallbackRegisteredAfterTranslationStarted()749 public void testCallbackRegisteredAfterTranslationStarted() throws Throwable { 750 final Pair<List<AutofillId>, ContentCaptureContext> result = 751 enableServicesAndStartActivityForTranslation(); 752 753 final List<AutofillId> views = result.first; 754 final ContentCaptureContext contentCaptureContext = result.second; 755 756 UiTranslationManager manager = 757 sContext.getSystemService(UiTranslationManager.class); 758 // Set response 759 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 760 761 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 762 763 // Register callback 764 final Executor executor = Executors.newSingleThreadExecutor(); 765 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 766 manager.registerUiTranslationStateCallback(executor, mockCallback); 767 SystemClock.sleep(UI_WAIT_TIMEOUT); 768 769 try { 770 // Callback should receive onStarted. 771 Mockito.verify(mockCallback, Mockito.times(1)) 772 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 773 774 pauseUiTranslation(contentCaptureContext); 775 776 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 777 778 resumeUiTranslation(contentCaptureContext); 779 780 Mockito.verify(mockCallback, Mockito.times(1)) 781 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 782 783 finishUiTranslation(contentCaptureContext); 784 785 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 786 787 // Make sure onFinished will not be called twice. 788 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 789 mActivityScenario = null; 790 SystemClock.sleep(UI_WAIT_TIMEOUT); 791 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 792 } finally { 793 manager.unregisterUiTranslationStateCallback(mockCallback); 794 } 795 } 796 797 @Test testCallbackRegisteredAfterTranslationStartedAndPaused()798 public void testCallbackRegisteredAfterTranslationStartedAndPaused() throws Throwable { 799 final Pair<List<AutofillId>, ContentCaptureContext> result = 800 enableServicesAndStartActivityForTranslation(); 801 802 final List<AutofillId> views = result.first; 803 final ContentCaptureContext contentCaptureContext = result.second; 804 805 UiTranslationManager manager = 806 sContext.getSystemService(UiTranslationManager.class); 807 // Set response 808 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 809 810 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 811 812 pauseUiTranslation(contentCaptureContext); 813 814 // Register callback 815 final Executor executor = Executors.newSingleThreadExecutor(); 816 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 817 manager.registerUiTranslationStateCallback(executor, mockCallback); 818 SystemClock.sleep(UI_WAIT_TIMEOUT); 819 820 try { 821 // Callback should receive onStarted and onPaused events. 822 Mockito.verify(mockCallback, Mockito.times(1)) 823 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 824 825 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 826 827 resumeUiTranslation(contentCaptureContext); 828 829 Mockito.verify(mockCallback, Mockito.times(1)) 830 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 831 832 finishUiTranslation(contentCaptureContext); 833 834 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 835 836 // Make sure onFinished will not be called twice. 837 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 838 mActivityScenario = null; 839 SystemClock.sleep(UI_WAIT_TIMEOUT); 840 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 841 } finally { 842 manager.unregisterUiTranslationStateCallback(mockCallback); 843 } 844 } 845 846 @Test testCallbackRegisteredAfterTranslationStartedPausedAndResumed()847 public void testCallbackRegisteredAfterTranslationStartedPausedAndResumed() throws Throwable { 848 final Pair<List<AutofillId>, ContentCaptureContext> result = 849 enableServicesAndStartActivityForTranslation(); 850 851 final List<AutofillId> views = result.first; 852 final ContentCaptureContext contentCaptureContext = result.second; 853 854 UiTranslationManager manager = 855 sContext.getSystemService(UiTranslationManager.class); 856 // Set response 857 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 858 859 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 860 861 pauseUiTranslation(contentCaptureContext); 862 863 resumeUiTranslation(contentCaptureContext); 864 865 // Register callback 866 final Executor executor = Executors.newSingleThreadExecutor(); 867 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 868 manager.registerUiTranslationStateCallback(executor, mockCallback); 869 SystemClock.sleep(UI_WAIT_TIMEOUT); 870 871 try { 872 // Callback should receive onStarted event but NOT an onPaused event, because 873 // translation was already resumed prior to registration. 874 Mockito.verify(mockCallback, Mockito.times(1)) 875 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 876 877 Mockito.verify(mockCallback, Mockito.never()).onPaused(any(String.class)); 878 879 Mockito.verify(mockCallback, Mockito.never()) 880 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 881 882 finishUiTranslation(contentCaptureContext); 883 884 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 885 886 // Make sure onFinished will not be called twice. 887 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 888 mActivityScenario = null; 889 SystemClock.sleep(UI_WAIT_TIMEOUT); 890 Mockito.verify(mockCallback, Mockito.times(1)).onFinished(any(String.class)); 891 } finally { 892 manager.unregisterUiTranslationStateCallback(mockCallback); 893 } 894 } 895 896 @Test testCallbackRegisteredAfterTranslationFinished()897 public void testCallbackRegisteredAfterTranslationFinished() throws Throwable { 898 final Pair<List<AutofillId>, ContentCaptureContext> result = 899 enableServicesAndStartActivityForTranslation(); 900 901 final List<AutofillId> views = result.first; 902 final ContentCaptureContext contentCaptureContext = result.second; 903 904 UiTranslationManager manager = 905 sContext.getSystemService(UiTranslationManager.class); 906 // Set response 907 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 908 909 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 910 911 pauseUiTranslation(contentCaptureContext); 912 913 resumeUiTranslation(contentCaptureContext); 914 915 finishUiTranslation(contentCaptureContext); 916 917 // Register callback 918 final Executor executor = Executors.newSingleThreadExecutor(); 919 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 920 manager.registerUiTranslationStateCallback(executor, mockCallback); 921 SystemClock.sleep(UI_WAIT_TIMEOUT); 922 923 try { 924 // Callback should receive no events. 925 Mockito.verify(mockCallback, Mockito.never()) 926 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 927 928 Mockito.verify(mockCallback, Mockito.never()).onPaused(any(String.class)); 929 930 Mockito.verify(mockCallback, Mockito.never()) 931 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 932 933 Mockito.verify(mockCallback, Mockito.never()).onFinished(any(String.class)); 934 935 // Make sure onFinished will not be called at all. 936 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 937 mActivityScenario = null; 938 SystemClock.sleep(UI_WAIT_TIMEOUT); 939 Mockito.verify(mockCallback, Mockito.never()).onFinished(any(String.class)); 940 } finally { 941 manager.unregisterUiTranslationStateCallback(mockCallback); 942 } 943 } 944 945 @Test testCallbackRegisteredAfterActivityDestroyedWithoutFinishTranslation()946 public void testCallbackRegisteredAfterActivityDestroyedWithoutFinishTranslation() 947 throws Throwable { 948 final Pair<List<AutofillId>, ContentCaptureContext> result = 949 enableServicesAndStartActivityForTranslation(); 950 951 final List<AutofillId> views = result.first; 952 final ContentCaptureContext contentCaptureContext = result.second; 953 954 UiTranslationManager manager = 955 sContext.getSystemService(UiTranslationManager.class); 956 // Set response 957 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 958 959 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 960 961 pauseUiTranslation(contentCaptureContext); 962 963 resumeUiTranslation(contentCaptureContext); 964 965 // Note: No finishTranslation call; Activity is destroyed. 966 mActivityScenario.moveToState(Lifecycle.State.DESTROYED); 967 mActivityScenario = null; 968 SystemClock.sleep(UI_WAIT_TIMEOUT); 969 970 // Register callback 971 final Executor executor = Executors.newSingleThreadExecutor(); 972 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 973 manager.registerUiTranslationStateCallback(executor, mockCallback); 974 975 try { 976 // Callback should receive no events. 977 SystemClock.sleep(UI_WAIT_TIMEOUT); 978 Mockito.verifyZeroInteractions(mockCallback); 979 } finally { 980 manager.unregisterUiTranslationStateCallback(mockCallback); 981 } 982 } 983 984 @Test testCallbackCalledOnceAfterDuplicateCalls()985 public void testCallbackCalledOnceAfterDuplicateCalls() throws Throwable { 986 final Pair<List<AutofillId>, ContentCaptureContext> result = 987 enableServicesAndStartActivityForTranslation(); 988 989 final List<AutofillId> views = result.first; 990 final ContentCaptureContext contentCaptureContext = result.second; 991 992 UiTranslationManager manager = 993 sContext.getSystemService(UiTranslationManager.class); 994 // Set response 995 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 996 997 // Register callback 998 final Executor executor = Executors.newSingleThreadExecutor(); 999 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 1000 manager.registerUiTranslationStateCallback(executor, mockCallback); 1001 1002 // Call startTranslation() multiple times; callback should only be called once. 1003 // Note: The locales don't change with each call. 1004 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1005 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1006 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1007 1008 Mockito.verify(mockCallback, Mockito.times(1)) 1009 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 1010 1011 // Call pauseTranslation() multiple times; callback should only be called once. 1012 pauseUiTranslation(contentCaptureContext); 1013 pauseUiTranslation(contentCaptureContext); 1014 pauseUiTranslation(contentCaptureContext); 1015 1016 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 1017 1018 // Call resumeUiTranslation() multiple times; callback should only be called once. 1019 resumeUiTranslation(contentCaptureContext); 1020 resumeUiTranslation(contentCaptureContext); 1021 resumeUiTranslation(contentCaptureContext); 1022 1023 Mockito.verify(mockCallback, Mockito.times(1)) 1024 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 1025 } 1026 1027 @Test testCallbackCalledForStartTranslationWithDifferentLocales()1028 public void testCallbackCalledForStartTranslationWithDifferentLocales() throws Throwable { 1029 final Pair<List<AutofillId>, ContentCaptureContext> result = 1030 enableServicesAndStartActivityForTranslation(); 1031 1032 final List<AutofillId> views = result.first; 1033 final ContentCaptureContext contentCaptureContext = result.second; 1034 1035 UiTranslationManager manager = 1036 sContext.getSystemService(UiTranslationManager.class); 1037 // Set response 1038 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 1039 1040 // Register callback 1041 final Executor executor = Executors.newSingleThreadExecutor(); 1042 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 1043 manager.registerUiTranslationStateCallback(executor, mockCallback); 1044 1045 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext, 1046 ULocale.ENGLISH, ULocale.FRENCH); 1047 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext, 1048 ULocale.ENGLISH, ULocale.GERMAN); 1049 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext, 1050 ULocale.ITALIAN, ULocale.GERMAN); 1051 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext, 1052 ULocale.JAPANESE, ULocale.KOREAN); 1053 1054 Mockito.verify(mockCallback, Mockito.times(1)) 1055 .onStarted(eq(ULocale.ENGLISH), eq(ULocale.FRENCH), any(String.class)); 1056 Mockito.verify(mockCallback, Mockito.times(1)) 1057 .onStarted(eq(ULocale.ENGLISH), eq(ULocale.GERMAN), any(String.class)); 1058 Mockito.verify(mockCallback, Mockito.times(1)) 1059 .onStarted(eq(ULocale.ITALIAN), eq(ULocale.GERMAN), any(String.class)); 1060 Mockito.verify(mockCallback, Mockito.times(1)) 1061 .onStarted(eq(ULocale.JAPANESE), eq(ULocale.KOREAN), any(String.class)); 1062 1063 // Calling startTranslation() after pauseTranslation() should invoke the callback even if 1064 // the locales are the same as it was before. 1065 pauseUiTranslation(contentCaptureContext); 1066 1067 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 1068 1069 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext, 1070 ULocale.JAPANESE, ULocale.KOREAN); 1071 1072 Mockito.verify(mockCallback, Mockito.times(2)) 1073 .onStarted(eq(ULocale.JAPANESE), eq(ULocale.KOREAN), any(String.class)); 1074 } 1075 1076 @Test testCallbackCalledOnStartTranslationAfterPause()1077 public void testCallbackCalledOnStartTranslationAfterPause() throws Throwable { 1078 final Pair<List<AutofillId>, ContentCaptureContext> result = 1079 enableServicesAndStartActivityForTranslation(); 1080 1081 final List<AutofillId> views = result.first; 1082 final ContentCaptureContext contentCaptureContext = result.second; 1083 1084 UiTranslationManager manager = 1085 sContext.getSystemService(UiTranslationManager.class); 1086 // Set response 1087 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 1088 1089 // Register callback 1090 final Executor executor = Executors.newSingleThreadExecutor(); 1091 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 1092 manager.registerUiTranslationStateCallback(executor, mockCallback); 1093 1094 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1095 1096 Mockito.verify(mockCallback, Mockito.times(1)) 1097 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 1098 1099 pauseUiTranslation(contentCaptureContext); 1100 1101 Mockito.verify(mockCallback, Mockito.times(1)).onPaused(any(String.class)); 1102 1103 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1104 1105 // Start after pause invokes onResumed(), NOT onStarted(). 1106 Mockito.verify(mockCallback, Mockito.times(1)) 1107 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 1108 } 1109 1110 @Test testCallbackNotCalledOnResumeTranslationAfterStart()1111 public void testCallbackNotCalledOnResumeTranslationAfterStart() throws Throwable { 1112 final Pair<List<AutofillId>, ContentCaptureContext> result = 1113 enableServicesAndStartActivityForTranslation(); 1114 1115 final List<AutofillId> views = result.first; 1116 final ContentCaptureContext contentCaptureContext = result.second; 1117 1118 UiTranslationManager manager = 1119 sContext.getSystemService(UiTranslationManager.class); 1120 // Set response 1121 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 1122 1123 // Register callback 1124 final Executor executor = Executors.newSingleThreadExecutor(); 1125 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 1126 manager.registerUiTranslationStateCallback(executor, mockCallback); 1127 1128 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1129 1130 Mockito.verify(mockCallback, Mockito.times(1)) 1131 .onStarted(any(ULocale.class), any(ULocale.class), any(String.class)); 1132 1133 resumeUiTranslation(contentCaptureContext); 1134 1135 Mockito.verify(mockCallback, Mockito.never()) 1136 .onResumed(any(ULocale.class), any(ULocale.class), any(String.class)); 1137 } 1138 1139 @Test testCallbackNotCalledOnPauseOrResumeTranslationWithoutStart()1140 public void testCallbackNotCalledOnPauseOrResumeTranslationWithoutStart() throws Throwable { 1141 final Pair<List<AutofillId>, ContentCaptureContext> result = 1142 enableServicesAndStartActivityForTranslation(); 1143 1144 final List<AutofillId> views = result.first; 1145 final ContentCaptureContext contentCaptureContext = result.second; 1146 1147 UiTranslationManager manager = 1148 sContext.getSystemService(UiTranslationManager.class); 1149 // Set response 1150 sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success")); 1151 1152 // Register callback 1153 final Executor executor = Executors.newSingleThreadExecutor(); 1154 UiTranslationStateCallback mockCallback = Mockito.mock(UiTranslationStateCallback.class); 1155 manager.registerUiTranslationStateCallback(executor, mockCallback); 1156 1157 pauseUiTranslation(contentCaptureContext); 1158 resumeUiTranslation(contentCaptureContext); 1159 1160 Mockito.verifyZeroInteractions(mockCallback); 1161 } 1162 1163 @Test testVirtualViewUiTranslation()1164 public void testVirtualViewUiTranslation() throws Throwable { 1165 // Enable CTS ContentCaptureService 1166 CtsContentCaptureService contentcaptureService = enableContentCaptureService(); 1167 1168 // Start Activity and get needed information 1169 final List<AutofillId> views = startVirtualContainerViewActivityAndGetViewsForTranslation(); 1170 ViewTranslationCallback mockCallback = Mockito.mock(ViewTranslationCallback.class); 1171 mVirtualContainerView.setViewTranslationCallback(mockCallback); 1172 1173 // Wait session created and get the ContentCaptureContext from ContentCaptureService 1174 final ContentCaptureContext contentCaptureContext = 1175 getContentCaptureContextFromContentCaptureService(contentcaptureService); 1176 1177 // enable CTS TranslationService 1178 mTranslationServiceServiceWatcher = CtsTranslationService.setServiceWatcher(); 1179 Helper.setTemporaryTranslationService(CtsTranslationService.SERVICE_NAME); 1180 1181 final String translatedText = "success"; 1182 final UiTranslationManager manager = sContext.getSystemService(UiTranslationManager.class); 1183 // Set response 1184 final TranslationResponse expectedResponse = 1185 createViewsTranslationResponse(views, translatedText); 1186 sTranslationReplier.addResponse(expectedResponse); 1187 1188 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1189 1190 // Check request 1191 final TranslationRequest request = sTranslationReplier.getNextTranslationRequest(); 1192 final List<ViewTranslationRequest> requests = request.getViewTranslationRequests(); 1193 assertThat(requests.size()).isEqualTo(views.size()); 1194 // 1st virtual child in container 1195 final ViewTranslationRequest viewRequest1 = requests.get(0); 1196 assertThat(viewRequest1.getAutofillId()).isEqualTo(views.get(0)); 1197 assertThat(viewRequest1.getKeys()).containsExactly(ViewTranslationRequest.ID_TEXT); 1198 assertThat(viewRequest1.getValue(ViewTranslationRequest.ID_TEXT).getText().toString()) 1199 .isEqualTo("Hello 0"); 1200 // 2nd virtual child in container 1201 final ViewTranslationRequest viewRequest2 = requests.get(1); 1202 assertThat(viewRequest2.getAutofillId()).isEqualTo(views.get(1)); 1203 assertThat(viewRequest2.getKeys()).containsExactly(ViewTranslationRequest.ID_TEXT); 1204 assertThat(viewRequest2.getValue(ViewTranslationRequest.ID_TEXT).getText().toString()) 1205 .isEqualTo("Hello 1"); 1206 1207 // Check responses 1208 final LongSparseArray<ViewTranslationResponse> responses 1209 = mVirtualContainerView.getViewTranslationResponseForCustomView(); 1210 assertThat(responses).isNotNull(); 1211 assertThat(responses.size()).isEqualTo(2); 1212 assertThat(responses.valueAt(0)) 1213 .isEqualTo(expectedResponse.getViewTranslationResponses().valueAt(0)); 1214 assertThat(responses.valueAt(1)) 1215 .isEqualTo(expectedResponse.getViewTranslationResponses().valueAt(1)); 1216 1217 ArgumentCaptor<View> viewArgumentCaptor = ArgumentCaptor.forClass(View.class); 1218 Mockito.verify(mockCallback, Mockito.times(1)) 1219 .onShowTranslation(viewArgumentCaptor.capture()); 1220 VirtualContainerView capturedView = (VirtualContainerView) viewArgumentCaptor.getValue(); 1221 assertThat(capturedView.getAutofillId()).isEqualTo(mVirtualContainerView.getAutofillId()); 1222 1223 pauseUiTranslation(contentCaptureContext); 1224 1225 Mockito.verify(mockCallback, Mockito.times(1)).onHideTranslation(any(View.class)); 1226 1227 finishUiTranslation(contentCaptureContext); 1228 1229 Mockito.verify(mockCallback, Mockito.times(1)).onClearTranslation(any(View.class)); 1230 } 1231 1232 @Test testUiTranslation_translationResponseNotSetForCustomTextView()1233 public void testUiTranslation_translationResponseNotSetForCustomTextView() throws Throwable { 1234 try { 1235 // Enable CTS ContentCaptureService 1236 CtsContentCaptureService contentcaptureService = enableContentCaptureService(); 1237 // Start Activity and get needed information 1238 final List<AutofillId> views = startCustomTextViewActivityAndGetViewsForTranslation(); 1239 1240 // Wait session created and get the ConttCaptureContext from ContentCaptureService 1241 final ContentCaptureContext contentCaptureContext = 1242 getContentCaptureContextFromContentCaptureService(contentcaptureService); 1243 1244 // enable CTS TranslationService 1245 mTranslationServiceServiceWatcher = CtsTranslationService.setServiceWatcher(); 1246 Helper.setTemporaryTranslationService(CtsTranslationService.SERVICE_NAME); 1247 1248 // Set response 1249 final TranslationResponse expectedResponse = 1250 createViewsTranslationResponse(views, "success"); 1251 sTranslationReplier.addResponse(expectedResponse); 1252 1253 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1254 1255 // Verify result. Translation response doesn't set, it should show original text 1256 assertScreenText(mResponseNotSetTextView, "Hello World 1"); 1257 } catch (Throwable t) { 1258 Helper.takeScreenshotAndSave(sContext, TestNameUtils.getCurrentTestName(), 1259 Helper.LOCAL_TEST_FILES_DIR); 1260 throw t; 1261 } 1262 } 1263 1264 @Test testUiTranslation_customTextView()1265 public void testUiTranslation_customTextView() throws Throwable { 1266 try { 1267 // Enable CTS ContentCaptureService 1268 CtsContentCaptureService contentcaptureService = enableContentCaptureService(); 1269 // Start Activity and get needed information 1270 final List<AutofillId> views = startCustomTextViewActivityAndGetViewsForTranslation(); 1271 1272 // Wait session created and get the ConttCaptureContext from ContentCaptureService 1273 final ContentCaptureContext contentCaptureContext = 1274 getContentCaptureContextFromContentCaptureService(contentcaptureService); 1275 1276 // enable CTS TranslationService 1277 mTranslationServiceServiceWatcher = CtsTranslationService.setServiceWatcher(); 1278 Helper.setTemporaryTranslationService(CtsTranslationService.SERVICE_NAME); 1279 1280 final String translatedText = "success"; 1281 // Set response 1282 final TranslationResponse expectedResponse = 1283 createViewsTranslationResponse(views, translatedText); 1284 sTranslationReplier.addResponse(expectedResponse); 1285 1286 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1287 1288 // Verify result. 1289 assertThat(mCustomTextView.isMyTagTranslationSupported()).isTrue(); 1290 assertScreenText(mCustomTextView, translatedText); 1291 1292 finishUiTranslation(contentCaptureContext); 1293 1294 assertScreenText(mCustomTextView, "Hello World 2"); 1295 } catch (Throwable t) { 1296 Helper.takeScreenshotAndSave(sContext, TestNameUtils.getCurrentTestName(), 1297 Helper.LOCAL_TEST_FILES_DIR); 1298 throw t; 1299 } 1300 } 1301 1302 @Test testUiTranslation_selectableText()1303 public void testUiTranslation_selectableText() throws Throwable { 1304 final Pair<List<AutofillId>, ContentCaptureContext> result = 1305 enableServicesAndStartActivityForTranslation(); 1306 1307 final CharSequence originalText = mTextView.getText(); 1308 final List<AutofillId> views = result.first; 1309 final ContentCaptureContext contentCaptureContext = result.second; 1310 1311 final String translatedText = "success"; 1312 // Set responses 1313 final TranslationResponse response = 1314 createViewsTranslationResponse(views, translatedText); 1315 sTranslationReplier.addResponse(response); 1316 1317 mActivityScenario.onActivity(activity -> { 1318 mTextView.setTextIsSelectable(true); 1319 1320 // We want to check that these other flags can be restored after translation is 1321 // finished. 1322 mTextView.setClickable(false); 1323 mTextView.setLongClickable(false); 1324 mTextView.setFocusable(false); 1325 mTextView.setFocusableInTouchMode(false); 1326 }); 1327 1328 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1329 1330 // TextView is not selectable while translated. 1331 assertScreenText(mTextView, translatedText); 1332 assertThat(mTextView.isTextSelectable()).isFalse(); 1333 1334 finishUiTranslation(contentCaptureContext); 1335 1336 // Selectable and other flags are restored after translation is finished. 1337 assertScreenText(mTextView, originalText.toString()); 1338 assertThat(mTextView.isTextSelectable()).isTrue(); 1339 assertThat(mTextView.isClickable()).isFalse(); 1340 assertThat(mTextView.isFocusable()).isFalse(); 1341 assertThat(mTextView.isFocusableInTouchMode()).isFalse(); 1342 assertThat(mTextView.isLongClickable()).isFalse(); 1343 1344 mActivityScenario.onActivity(activity -> { 1345 // We also want to check we can restore flags with true values. 1346 mTextView.setClickable(true); 1347 mTextView.setLongClickable(true); 1348 mTextView.setFocusable(true); 1349 mTextView.setFocusableInTouchMode(true); 1350 }); 1351 1352 sTranslationReplier.addResponse(response); 1353 startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext); 1354 1355 // TextView is not selectable while translated. 1356 assertScreenText(mTextView, translatedText); 1357 assertThat(mTextView.isTextSelectable()).isFalse(); 1358 1359 finishUiTranslation(contentCaptureContext); 1360 1361 // Selectable and other flags are restored after translation is finished. 1362 assertScreenText(mTextView, originalText.toString()); 1363 assertThat(mTextView.isTextSelectable()).isTrue(); 1364 assertThat(mTextView.isClickable()).isTrue(); 1365 assertThat(mTextView.isFocusable()).isTrue(); 1366 assertThat(mTextView.isFocusableInTouchMode()).isTrue(); 1367 assertThat(mTextView.isLongClickable()).isTrue(); 1368 } 1369 assertScreenText(TextView textView, String expected)1370 private void assertScreenText(TextView textView, String expected) { 1371 String screenText = textView.getLayout().getText().toString(); 1372 assertThat(screenText).isEqualTo(expected); 1373 } 1374 startUiTranslation(boolean shouldPadContent, List<AutofillId> views, ContentCaptureContext contentCaptureContext)1375 private void startUiTranslation(boolean shouldPadContent, List<AutofillId> views, 1376 ContentCaptureContext contentCaptureContext) { 1377 startUiTranslation(shouldPadContent, views, contentCaptureContext, ULocale.ENGLISH, 1378 ULocale.FRENCH); 1379 } 1380 startUiTranslation(boolean shouldPadContent, List<AutofillId> views, ContentCaptureContext contentCaptureContext, ULocale sourceLocale, ULocale targetLocale)1381 private void startUiTranslation(boolean shouldPadContent, List<AutofillId> views, 1382 ContentCaptureContext contentCaptureContext, ULocale sourceLocale, 1383 ULocale targetLocale) { 1384 final UiTranslationManager manager = sContext.getSystemService(UiTranslationManager.class); 1385 runWithShellPermissionIdentity(() -> { 1386 // Call startTranslation API 1387 manager.startTranslation( 1388 new TranslationSpec(sourceLocale, TranslationSpec.DATA_FORMAT_TEXT), 1389 new TranslationSpec(targetLocale, TranslationSpec.DATA_FORMAT_TEXT), 1390 views, contentCaptureContext.getActivityId(), 1391 shouldPadContent ? new UiTranslationSpec.Builder().setShouldPadContentForCompat( 1392 true).build() : new UiTranslationSpec.Builder().build()); 1393 SystemClock.sleep(UI_WAIT_TIMEOUT); 1394 }); 1395 } 1396 pauseUiTranslation(ContentCaptureContext contentCaptureContext)1397 private void pauseUiTranslation(ContentCaptureContext contentCaptureContext) { 1398 final UiTranslationManager manager = sContext.getSystemService(UiTranslationManager.class); 1399 runWithShellPermissionIdentity(() -> { 1400 // Call pauseTranslation API 1401 manager.pauseTranslation(contentCaptureContext.getActivityId()); 1402 SystemClock.sleep(UI_WAIT_TIMEOUT); 1403 }); 1404 } 1405 resumeUiTranslation(ContentCaptureContext contentCaptureContext)1406 private void resumeUiTranslation(ContentCaptureContext contentCaptureContext) { 1407 final UiTranslationManager manager = sContext.getSystemService(UiTranslationManager.class); 1408 // Call resume Translation API 1409 runWithShellPermissionIdentity(() -> { 1410 manager.resumeTranslation(contentCaptureContext.getActivityId()); 1411 SystemClock.sleep(UI_WAIT_TIMEOUT); 1412 }); 1413 } 1414 finishUiTranslation(ContentCaptureContext contentCaptureContext)1415 private void finishUiTranslation(ContentCaptureContext contentCaptureContext) { 1416 final UiTranslationManager manager = sContext.getSystemService(UiTranslationManager.class); 1417 runWithShellPermissionIdentity(() -> { 1418 // Call finishTranslation API 1419 manager.finishTranslation(contentCaptureContext.getActivityId()); 1420 SystemClock.sleep(UI_WAIT_TIMEOUT); 1421 }); 1422 } 1423 startCustomTextViewActivityAndGetViewsForTranslation()1424 private List<AutofillId> startCustomTextViewActivityAndGetViewsForTranslation() { 1425 // Start CustomTextViewActivity and get needed information 1426 Intent intent = new Intent(sContext, CustomTextViewActivity.class) 1427 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1428 AtomicReference<List<AutofillId>> viewAutofillIdsRef = new AtomicReference<>(); 1429 1430 mCustomTextViewActivityScenario = ActivityScenario.launch(intent); 1431 mCustomTextViewActivityScenario.onActivity(activity -> { 1432 mResponseNotSetTextView = activity.getResponseNotSetText(); 1433 mCustomTextView = activity.getCustomText(); 1434 // Get the views that need to be translated. 1435 viewAutofillIdsRef.set(activity.getViewsForTranslation()); 1436 }); 1437 return viewAutofillIdsRef.get(); 1438 } 1439 startVirtualContainerViewActivityAndGetViewsForTranslation()1440 private List<AutofillId> startVirtualContainerViewActivityAndGetViewsForTranslation() { 1441 // Start VirtualContainerViewActivity and get needed information 1442 Intent intent = new Intent(sContext, VirtualContainerViewActivity.class) 1443 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1444 AtomicReference<List<AutofillId>> viewAutofillIdsRef = new AtomicReference<>(); 1445 1446 mVirtualContainerViewActivityScenario = ActivityScenario.launch(intent); 1447 mVirtualContainerViewActivityScenario.onActivity(activity -> { 1448 mVirtualContainerView = activity.getVirtualContainerView(); 1449 // Get the views that need to be translated. 1450 viewAutofillIdsRef.set(activity.getViewsForTranslation()); 1451 }); 1452 return viewAutofillIdsRef.get(); 1453 } 1454 sendCommandToIme(String action, boolean mutable)1455 private BlockingBroadcastReceiver sendCommandToIme(String action, boolean mutable) { 1456 final String actionImeServiceCommandDone = action + "_" + SystemClock.uptimeMillis(); 1457 final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(sContext, 1458 actionImeServiceCommandDone); 1459 receiver.register(); 1460 final Intent commandIntent = new Intent(action); 1461 final PendingIntent pendingIntent = 1462 PendingIntent.getBroadcast( 1463 sContext, 1464 0, 1465 new Intent(actionImeServiceCommandDone), 1466 mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE); 1467 commandIntent.putExtra(EXTRA_FINISH_COMMAND, pendingIntent); 1468 sContext.sendBroadcast(commandIntent); 1469 return receiver; 1470 } 1471 enableContentCaptureService()1472 private CtsContentCaptureService enableContentCaptureService() throws Exception { 1473 mContentCaptureServiceWatcher = CtsContentCaptureService.setServiceWatcher(); 1474 Helper.setTemporaryContentCaptureService(CtsContentCaptureService.SERVICE_NAME); 1475 mContentCaptureServiceWatcher.setAllowSelf(); 1476 return mContentCaptureServiceWatcher.waitOnConnected(); 1477 } 1478 getContentCaptureContextFromContentCaptureService( CtsContentCaptureService service)1479 private ContentCaptureContext getContentCaptureContextFromContentCaptureService( 1480 CtsContentCaptureService service) { 1481 service.awaitSessionCreated(CtsContentCaptureService.GENERIC_TIMEOUT_MS); 1482 final ContentCaptureContext contentCaptureContext = service.getContentCaptureContext(); 1483 Log.d(TAG, "contentCaptureContext = " + contentCaptureContext); 1484 1485 assertThat(contentCaptureContext).isNotNull(); 1486 assertThat(contentCaptureContext.getActivityId()).isNotNull(); 1487 1488 return contentCaptureContext; 1489 } 1490 createViewsTranslationResponse(List<AutofillId> viewAutofillIds, String translatedText)1491 private TranslationResponse createViewsTranslationResponse(List<AutofillId> viewAutofillIds, 1492 String translatedText) { 1493 final TranslationResponse.Builder responseBuilder = 1494 new TranslationResponse.Builder(TranslationResponse.TRANSLATION_STATUS_SUCCESS); 1495 for (int i = 0; i < viewAutofillIds.size(); i++) { 1496 ViewTranslationResponse.Builder responseDataBuilder = 1497 new ViewTranslationResponse.Builder(viewAutofillIds.get(i)) 1498 .setValue(ViewTranslationRequest.ID_TEXT, 1499 new TranslationResponseValue.Builder(STATUS_SUCCESS) 1500 .setText(translatedText).build()) 1501 .setValue(Helper.CUSTOM_TRANSLATION_ID_MY_TAG, 1502 new TranslationResponseValue.Builder(STATUS_SUCCESS) 1503 .setText(translatedText).build()) 1504 .setValue(ID_CONTENT_DESCRIPTION, 1505 new TranslationResponseValue.Builder(STATUS_SUCCESS) 1506 .setText(translatedText).build()); 1507 responseBuilder.setViewTranslationResponse(i, responseDataBuilder.build()); 1508 } 1509 return responseBuilder.build(); 1510 } 1511 1512 private Pair<List<AutofillId>, ContentCaptureContext> enableServicesAndStartActivityForTranslation()1513 enableServicesAndStartActivityForTranslation() throws Exception { 1514 // Enable CTS ContentCaptureService 1515 CtsContentCaptureService contentcaptureService = enableContentCaptureService(); 1516 1517 // Start Activity and get needed information 1518 Intent intent = new Intent(sContext, SimpleActivity.class) 1519 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1520 AtomicReference<CharSequence> originalTextRef = new AtomicReference<>(); 1521 AtomicReference<List<AutofillId>> viewAutofillIdsRef = new AtomicReference<>(); 1522 1523 mActivityScenario = ActivityScenario.launch(intent); 1524 mActivityScenario.onActivity(activity -> { 1525 mSimpleActivity = activity; 1526 mTextView = activity.getHelloText(); 1527 originalTextRef.set(activity.getHelloText().getText()); 1528 viewAutofillIdsRef.set(activity.getViewsForTranslation()); 1529 }); 1530 CharSequence originalText = originalTextRef.get(); 1531 // Get the views that need to be translated. 1532 List<AutofillId> views = viewAutofillIdsRef.get(); 1533 1534 // Wait session created and get the ContentCaptureContext from ContentCaptureService 1535 ContentCaptureContext contentCaptureContext = 1536 getContentCaptureContextFromContentCaptureService(contentcaptureService); 1537 1538 // enable CTS TranslationService 1539 mTranslationServiceServiceWatcher = CtsTranslationService.setServiceWatcher(); 1540 Helper.setTemporaryTranslationService(CtsTranslationService.SERVICE_NAME); 1541 1542 // TODO(b/184617863): use separate methods not use Pair here. 1543 return new Pair(views, contentCaptureContext); 1544 } 1545 1546 private static class ImeSession implements AutoCloseable { 1547 1548 private static final long TIMEOUT = 2000; 1549 private final ComponentName mImeName; 1550 ImeSession(ComponentName ime)1551 ImeSession(ComponentName ime) throws Exception { 1552 mImeName = ime; 1553 runShellCommand("ime reset"); 1554 // TODO(b/184617863): get IME component from InputMethodManager#getInputMethodList 1555 runShellCommand("ime enable " + ime.flattenToShortString()); 1556 runShellCommand("ime set " + ime.flattenToShortString()); 1557 PollingCheck.check("Make sure that MockIME becomes available", TIMEOUT, 1558 () -> ime.equals(getCurrentInputMethodId())); 1559 } 1560 1561 @Override close()1562 public void close() throws Exception { 1563 runShellCommand("ime reset"); 1564 PollingCheck.check("Make sure that MockIME becomes unavailable", TIMEOUT, () -> 1565 sContext.getSystemService(InputMethodManager.class) 1566 .getEnabledInputMethodList() 1567 .stream() 1568 .noneMatch(info -> mImeName.equals(info.getComponent()))); 1569 } 1570 getCurrentInputMethodId()1571 private ComponentName getCurrentInputMethodId() { 1572 return ComponentName.unflattenFromString( 1573 Settings.Secure.getString(sContext.getContentResolver(), 1574 Settings.Secure.DEFAULT_INPUT_METHOD)); 1575 } 1576 } 1577 } 1578