xref: /aosp_15_r20/cts/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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