Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 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.autofillservice.cts;
     18 
     19 import static android.app.Activity.RESULT_CANCELED;
     20 import static android.app.Activity.RESULT_OK;
     21 import static android.autofillservice.cts.Helper.ID_PASSWORD;
     22 import static android.autofillservice.cts.Helper.ID_USERNAME;
     23 import static android.autofillservice.cts.Helper.UNUSED_AUTOFILL_VALUE;
     24 import static android.autofillservice.cts.Helper.assertTextAndValue;
     25 import static android.autofillservice.cts.Helper.findNodeByResourceId;
     26 import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
     27 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
     28 import static android.view.View.IMPORTANT_FOR_AUTOFILL_NO;
     29 
     30 import static com.google.common.truth.Truth.assertThat;
     31 import static com.google.common.truth.Truth.assertWithMessage;
     32 
     33 import android.app.assist.AssistStructure.ViewNode;
     34 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
     35 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
     36 import android.content.IntentSender;
     37 import android.os.Bundle;
     38 import android.platform.test.annotations.AppModeFull;
     39 import android.support.test.uiautomator.UiObject2;
     40 import android.view.View;
     41 import android.view.autofill.AutofillValue;
     42 
     43 import org.junit.Test;
     44 
     45 import java.util.concurrent.CountDownLatch;
     46 import java.util.regex.Pattern;
     47 
     48 public class AuthenticationTest extends AbstractLoginActivityTestCase {
     49 
     50     @Test
     51     public void testDatasetAuthTwoFields() throws Exception {
     52         datasetAuthTwoFields(false);
     53     }
     54 
     55     @Test
     56     @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
     57     public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
     58         datasetAuthTwoFields(true);
     59     }
     60 
     61     private void datasetAuthTwoFields(boolean cancelFirstAttempt) throws Exception {
     62         // Set service.
     63         enableService();
     64         final MyAutofillCallback callback = mActivity.registerCallback();
     65 
     66         // Prepare the authenticated response
     67         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
     68                 new CannedDataset.Builder()
     69                         .setField(ID_USERNAME, "dude")
     70                         .setField(ID_PASSWORD, "sweet")
     71                         .build());
     72 
     73         // Configure the service behavior
     74         sReplier.addResponse(new CannedFillResponse.Builder()
     75                 .addDataset(new CannedDataset.Builder()
     76                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
     77                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
     78                         .setPresentation(createPresentation("Tap to auth dataset"))
     79                         .setAuthentication(authentication)
     80                         .build())
     81                 .build());
     82 
     83         // Set expectation for the activity
     84         mActivity.expectAutoFill("dude", "sweet");
     85 
     86         // Trigger auto-fill.
     87         requestFocusOnUsername();
     88 
     89         // Wait for onFill() before proceeding.
     90         sReplier.getNextFillRequest();
     91         final View username = mActivity.getUsername();
     92         callback.assertUiShownEvent(username);
     93         mUiBot.assertDatasets("Tap to auth dataset");
     94 
     95         // Make sure UI is show on 2nd field as well
     96         final View password = mActivity.getPassword();
     97         requestFocusOnPassword();
     98         callback.assertUiHiddenEvent(username);
     99         callback.assertUiShownEvent(password);
    100         mUiBot.assertDatasets("Tap to auth dataset");
    101 
    102         // Now tap on 1st field to show it again...
    103         requestFocusOnUsername();
    104         callback.assertUiHiddenEvent(password);
    105         callback.assertUiShownEvent(username);
    106         mUiBot.assertDatasets("Tap to auth dataset");
    107 
    108         if (cancelFirstAttempt) {
    109             // Trigger the auth dialog, but emulate cancel.
    110             AuthenticationActivity.setResultCode(RESULT_CANCELED);
    111             mUiBot.selectDataset("Tap to auth dataset");
    112             callback.assertUiHiddenEvent(username);
    113             callback.assertUiShownEvent(username);
    114             mUiBot.assertDatasets("Tap to auth dataset");
    115 
    116             // Make sure it's still shown on other fields...
    117             requestFocusOnPassword();
    118             callback.assertUiHiddenEvent(username);
    119             callback.assertUiShownEvent(password);
    120             mUiBot.assertDatasets("Tap to auth dataset");
    121 
    122             // Tap on 1st field to show it again...
    123             requestFocusOnUsername();
    124             callback.assertUiHiddenEvent(password);
    125             callback.assertUiShownEvent(username);
    126         }
    127 
    128         // ...and select it this time
    129         AuthenticationActivity.setResultCode(RESULT_OK);
    130         mUiBot.selectDataset("Tap to auth dataset");
    131         callback.assertUiHiddenEvent(username);
    132         mUiBot.assertNoDatasets();
    133 
    134         // Check the results.
    135         mActivity.assertAutoFilled();
    136     }
    137 
    138     @Test
    139     @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
    140     public void testDatasetAuthTwoFieldsReplaceResponse() throws Exception {
    141         // Set service.
    142         enableService();
    143         final MyAutofillCallback callback = mActivity.registerCallback();
    144 
    145         // Prepare the authenticated response
    146         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    147                 new CannedFillResponse.Builder().addDataset(
    148                         new CannedDataset.Builder()
    149                                 .setField(ID_USERNAME, "dude")
    150                                 .setField(ID_PASSWORD, "sweet")
    151                                 .setPresentation(createPresentation("Dataset"))
    152                                 .build())
    153                         .build());
    154 
    155         // Set up the authentication response client state
    156         final Bundle authentionClientState = new Bundle();
    157         authentionClientState.putCharSequence("clientStateKey1", "clientStateValue1");
    158 
    159         // Configure the service behavior
    160         sReplier.addResponse(new CannedFillResponse.Builder()
    161                 .addDataset(new CannedDataset.Builder()
    162                         .setField(ID_USERNAME, (AutofillValue) null)
    163                         .setField(ID_PASSWORD, (AutofillValue) null)
    164                         .setPresentation(createPresentation("Tap to auth dataset"))
    165                         .setAuthentication(authentication)
    166                         .build())
    167                 .setExtras(authentionClientState)
    168                 .build());
    169 
    170         // Set expectation for the activity
    171         mActivity.expectAutoFill("dude", "sweet");
    172 
    173         // Trigger auto-fill.
    174         requestFocusOnUsername();
    175 
    176         // Wait for onFill() before proceeding.
    177         sReplier.getNextFillRequest();
    178         final View username = mActivity.getUsername();
    179 
    180         // Authenticate
    181         callback.assertUiShownEvent(username);
    182         mUiBot.selectDataset("Tap to auth dataset");
    183         callback.assertUiHiddenEvent(username);
    184 
    185         // Select a dataset from the new response
    186         callback.assertUiShownEvent(username);
    187         mUiBot.selectDataset("Dataset");
    188         callback.assertUiHiddenEvent(username);
    189         mUiBot.assertNoDatasets();
    190 
    191         // Check the results.
    192         mActivity.assertAutoFilled();
    193 
    194         final Bundle data = AuthenticationActivity.getData();
    195         assertThat(data).isNotNull();
    196         final String extraValue = data.getString("clientStateKey1");
    197         assertThat(extraValue).isEqualTo("clientStateValue1");
    198     }
    199 
    200     @Test
    201     @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
    202     public void testDatasetAuthTwoFieldsNoValues() throws Exception {
    203         // Set service.
    204         enableService();
    205         final MyAutofillCallback callback = mActivity.registerCallback();
    206 
    207         // Create the authentication intent
    208         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    209                 new CannedDataset.Builder()
    210                         .setField(ID_USERNAME, "dude")
    211                         .setField(ID_PASSWORD, "sweet")
    212                         .build());
    213 
    214         // Configure the service behavior
    215         sReplier.addResponse(new CannedFillResponse.Builder()
    216                 .addDataset(new CannedDataset.Builder()
    217                         .setField(ID_USERNAME, (String) null)
    218                         .setField(ID_PASSWORD, (String) null)
    219                         .setPresentation(createPresentation("Tap to auth dataset"))
    220                         .setAuthentication(authentication)
    221                         .build())
    222                 .build());
    223 
    224         // Set expectation for the activity
    225         mActivity.expectAutoFill("dude", "sweet");
    226 
    227         // Trigger auto-fill.
    228         requestFocusOnUsername();
    229 
    230         // Wait for onFill() before proceeding.
    231         sReplier.getNextFillRequest();
    232         final View username = mActivity.getUsername();
    233 
    234         // Authenticate
    235         callback.assertUiShownEvent(username);
    236         mUiBot.selectDataset("Tap to auth dataset");
    237         callback.assertUiHiddenEvent(username);
    238         mUiBot.assertNoDatasets();
    239 
    240         // Check the results.
    241         mActivity.assertAutoFilled();
    242     }
    243 
    244     @Test
    245     @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
    246     public void testDatasetAuthTwoDatasets() throws Exception {
    247         // Set service.
    248         enableService();
    249         final MyAutofillCallback callback = mActivity.registerCallback();
    250 
    251         // Create the authentication intents
    252         final CannedDataset unlockedDataset = new CannedDataset.Builder()
    253                 .setField(ID_USERNAME, "dude")
    254                 .setField(ID_PASSWORD, "sweet")
    255                 .build();
    256         final IntentSender authentication1 = AuthenticationActivity.createSender(mContext, 1,
    257                 unlockedDataset);
    258         final IntentSender authentication2 = AuthenticationActivity.createSender(mContext, 2,
    259                 unlockedDataset);
    260 
    261         // Configure the service behavior
    262         sReplier.addResponse(new CannedFillResponse.Builder()
    263                 .addDataset(new CannedDataset.Builder()
    264                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
    265                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
    266                         .setPresentation(createPresentation("Tap to auth dataset 1"))
    267                         .setAuthentication(authentication1)
    268                         .build())
    269                 .addDataset(new CannedDataset.Builder()
    270                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
    271                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
    272                         .setPresentation(createPresentation("Tap to auth dataset 2"))
    273                         .setAuthentication(authentication2)
    274                         .build())
    275                 .build());
    276 
    277         // Set expectation for the activity
    278         mActivity.expectAutoFill("dude", "sweet");
    279 
    280         // Trigger auto-fill.
    281         requestFocusOnUsername();
    282 
    283         // Wait for onFill() before proceeding.
    284         sReplier.getNextFillRequest();
    285         final View username = mActivity.getUsername();
    286 
    287         // Authenticate
    288         callback.assertUiShownEvent(username);
    289         mUiBot.assertDatasets("Tap to auth dataset 1", "Tap to auth dataset 2");
    290 
    291         mUiBot.selectDataset("Tap to auth dataset 1");
    292         callback.assertUiHiddenEvent(username);
    293         mUiBot.assertNoDatasets();
    294 
    295         // Check the results.
    296         mActivity.assertAutoFilled();
    297     }
    298 
    299     @Test
    300     @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
    301     public void testDatasetAuthMixedSelectAuth() throws Exception {
    302         datasetAuthMixedTest(true);
    303     }
    304 
    305     @Test
    306     @AppModeFull // testDatasetAuthTwoFields() is enough to test ephemeral apps support
    307     public void testDatasetAuthMixedSelectNonAuth() throws Exception {
    308         datasetAuthMixedTest(false);
    309     }
    310 
    311     private void datasetAuthMixedTest(boolean selectAuth) throws Exception {
    312         // Set service.
    313         enableService();
    314         final MyAutofillCallback callback = mActivity.registerCallback();
    315 
    316         // Prepare the authenticated response
    317         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    318                 new CannedDataset.Builder()
    319                         .setField(ID_USERNAME, "dude")
    320                         .setField(ID_PASSWORD, "sweet")
    321                         .build());
    322 
    323         // Configure the service behavior
    324         sReplier.addResponse(new CannedFillResponse.Builder()
    325                 .addDataset(new CannedDataset.Builder()
    326                         .setField(ID_USERNAME, "dude")
    327                         .setField(ID_PASSWORD, "sweet")
    328                         .setPresentation(createPresentation("Tap to auth dataset"))
    329                         .setAuthentication(authentication)
    330                         .build())
    331                 .addDataset(new CannedDataset.Builder()
    332                         .setField(ID_USERNAME, "DUDE")
    333                         .setField(ID_PASSWORD, "SWEET")
    334                         .setPresentation(createPresentation("What, me auth?"))
    335                         .build())
    336                 .build());
    337 
    338         // Set expectation for the activity
    339         if (selectAuth) {
    340             mActivity.expectAutoFill("dude", "sweet");
    341         } else {
    342             mActivity.expectAutoFill("DUDE", "SWEET");
    343         }
    344 
    345         // Trigger auto-fill.
    346         requestFocusOnUsername();
    347 
    348         // Wait for onFill() before proceeding.
    349         sReplier.getNextFillRequest();
    350         final View username = mActivity.getUsername();
    351 
    352         // Authenticate
    353         callback.assertUiShownEvent(username);
    354         mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
    355 
    356         final String chosenOne = selectAuth ? "Tap to auth dataset" : "What, me auth?";
    357         mUiBot.selectDataset(chosenOne);
    358         callback.assertUiHiddenEvent(username);
    359         mUiBot.assertNoDatasets();
    360 
    361         // Check the results.
    362         mActivity.assertAutoFilled();
    363     }
    364 
    365     @Test
    366     @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
    367     public void testDatasetAuthNoFiltering() throws Exception {
    368         // Set service.
    369         enableService();
    370         final MyAutofillCallback callback = mActivity.registerCallback();
    371 
    372         // Create the authentication intents
    373         final CannedDataset unlockedDataset = new CannedDataset.Builder()
    374                 .setField(ID_USERNAME, "dude")
    375                 .setField(ID_PASSWORD, "sweet")
    376                 .build();
    377         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    378                 unlockedDataset);
    379 
    380         // Configure the service behavior
    381         sReplier.addResponse(new CannedFillResponse.Builder()
    382                 .addDataset(new CannedDataset.Builder()
    383                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
    384                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
    385                         .setPresentation(createPresentation("Tap to auth dataset"))
    386                         .setAuthentication(authentication)
    387                         .build())
    388                 .build());
    389 
    390         // Set expectation for the activity
    391         mActivity.expectAutoFill("dude", "sweet");
    392 
    393         // Trigger auto-fill.
    394         requestFocusOnUsername();
    395 
    396         // Wait for onFill() before proceeding.
    397         sReplier.getNextFillRequest();
    398         final View username = mActivity.getUsername();
    399 
    400         // Make sure it's showing initially...
    401         callback.assertUiShownEvent(username);
    402         mUiBot.assertDatasets("Tap to auth dataset");
    403 
    404         // ..then type something to hide it.
    405         mActivity.onUsername((v) -> v.setText("a"));
    406         callback.assertUiHiddenEvent(username);
    407         mUiBot.assertNoDatasets();
    408 
    409         // Now delete the char and assert it's shown again...
    410         mActivity.onUsername((v) -> v.setText(""));
    411         callback.assertUiShownEvent(username);
    412         mUiBot.assertDatasets("Tap to auth dataset");
    413 
    414         // ...and select it this time
    415         mUiBot.selectDataset("Tap to auth dataset");
    416         callback.assertUiHiddenEvent(username);
    417         mUiBot.assertNoDatasets();
    418 
    419         // Check the results.
    420         mActivity.assertAutoFilled();
    421     }
    422 
    423     @Test
    424     @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
    425     public void testDatasetAuthFilteringUsingAutofillValue() throws Exception {
    426         // Set service.
    427         enableService();
    428         final MyAutofillCallback callback = mActivity.registerCallback();
    429 
    430         // Create the authentication intents
    431         final CannedDataset unlockedDataset = new CannedDataset.Builder()
    432                 .setField(ID_USERNAME, "dude")
    433                 .setField(ID_PASSWORD, "sweet")
    434                 .build();
    435         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    436                 unlockedDataset);
    437 
    438         // Configure the service behavior
    439         sReplier.addResponse(new CannedFillResponse.Builder()
    440                 .addDataset(new CannedDataset.Builder()
    441                         .setField(ID_USERNAME, "dude")
    442                         .setField(ID_PASSWORD, "sweet")
    443                         .setPresentation(createPresentation("DS1"))
    444                         .setAuthentication(authentication)
    445                         .build())
    446                 .addDataset(new CannedDataset.Builder()
    447                         .setField(ID_USERNAME, "DUDE,THE")
    448                         .setField(ID_PASSWORD, "SWEET")
    449                         .setPresentation(createPresentation("DS2"))
    450                         .setAuthentication(authentication)
    451                         .build())
    452                 .addDataset(new CannedDataset.Builder()
    453                         .setField(ID_USERNAME, "ZzBottom")
    454                         .setField(ID_PASSWORD, "top")
    455                         .setPresentation(createPresentation("DS3"))
    456                         .setAuthentication(authentication)
    457                         .build())
    458                 .build());
    459 
    460         // Set expectation for the activity
    461         mActivity.expectAutoFill("dude", "sweet");
    462 
    463         // Trigger auto-fill.
    464         requestFocusOnUsername();
    465 
    466         // Wait for onFill() before proceeding.
    467         sReplier.getNextFillRequest();
    468         final View username = mActivity.getUsername();
    469 
    470         // Make sure it's showing initially...
    471         callback.assertUiShownEvent(username);
    472         mUiBot.assertDatasets("DS1", "DS2", "DS3");
    473 
    474         // ...then type something to hide them.
    475         mActivity.onUsername((v) -> v.setText("a"));
    476         callback.assertUiHiddenEvent(username);
    477         mUiBot.assertNoDatasets();
    478 
    479         // Now delete the char and assert they're shown again...
    480         mActivity.onUsername((v) -> v.setText(""));
    481         callback.assertUiShownEvent(username);
    482         mUiBot.assertDatasets("DS1", "DS2", "DS3");
    483 
    484         // ...then filter for 2
    485         mActivity.onUsername((v) -> v.setText("d"));
    486         mUiBot.assertDatasets("DS1", "DS2");
    487 
    488         // ...up to 1
    489         mActivity.onUsername((v) -> v.setText("du"));
    490         mUiBot.assertDatasets("DS1", "DS2");
    491         mActivity.onUsername((v) -> v.setText("dud"));
    492         mUiBot.assertDatasets("DS1", "DS2");
    493         mActivity.onUsername((v) -> v.setText("dude"));
    494         mUiBot.assertDatasets("DS1", "DS2");
    495         mActivity.onUsername((v) -> v.setText("dude,"));
    496         mUiBot.assertDatasets("DS2");
    497 
    498         // Now delete the char and assert 2 are shown again...
    499         mActivity.onUsername((v) -> v.setText("dude"));
    500         final UiObject2 picker = mUiBot.assertDatasets("DS1", "DS2");
    501 
    502         // ...and select it this time
    503         mUiBot.selectDataset(picker, "DS1");
    504         callback.assertUiHiddenEvent(username);
    505         mUiBot.assertNoDatasets();
    506 
    507         // Check the results.
    508         mActivity.assertAutoFilled();
    509     }
    510 
    511     @Test
    512     public void testDatasetAuthFilteringUsingRegex() throws Exception {
    513         // Set service.
    514         enableService();
    515         final MyAutofillCallback callback = mActivity.registerCallback();
    516 
    517         // Create the authentication intents
    518         final CannedDataset unlockedDataset = new CannedDataset.Builder()
    519                 .setField(ID_USERNAME, "dude")
    520                 .setField(ID_PASSWORD, "sweet")
    521                 .build();
    522         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    523                 unlockedDataset);
    524 
    525         // Configure the service behavior
    526 
    527         final Pattern min2Chars = Pattern.compile(".{2,}");
    528         sReplier.addResponse(new CannedFillResponse.Builder()
    529                 .addDataset(new CannedDataset.Builder()
    530                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE, min2Chars)
    531                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
    532                         .setPresentation(createPresentation("Tap to auth dataset"))
    533                         .setAuthentication(authentication)
    534                         .build())
    535                 .build());
    536 
    537         // Set expectation for the activity
    538         mActivity.expectAutoFill("dude", "sweet");
    539 
    540         // Trigger auto-fill.
    541         requestFocusOnUsername();
    542 
    543         // Wait for onFill() before proceeding.
    544         sReplier.getNextFillRequest();
    545         final View username = mActivity.getUsername();
    546 
    547         // Make sure it's showing initially...
    548         callback.assertUiShownEvent(username);
    549         mUiBot.assertDatasets("Tap to auth dataset");
    550 
    551         // ...then type something to hide it.
    552         mActivity.onUsername((v) -> v.setText("a"));
    553         callback.assertUiHiddenEvent(username);
    554         mUiBot.assertNoDatasets();
    555 
    556         // ...now type something again to show it, as the input will have 2 chars.
    557         mActivity.onUsername((v) -> v.setText("aa"));
    558         callback.assertUiShownEvent(username);
    559         mUiBot.assertDatasets("Tap to auth dataset");
    560 
    561         // Delete the char and assert it's not shown again...
    562         mActivity.onUsername((v) -> v.setText("a"));
    563         callback.assertUiHiddenEvent(username);
    564         mUiBot.assertNoDatasets();
    565 
    566         // ...then type something again to show it, as the input will have 2 chars.
    567         mActivity.onUsername((v) -> v.setText("aa"));
    568         callback.assertUiShownEvent(username);
    569 
    570         // ...and select it this time
    571         mUiBot.selectDataset("Tap to auth dataset");
    572         callback.assertUiHiddenEvent(username);
    573         mUiBot.assertNoDatasets();
    574 
    575         // Check the results.
    576         mActivity.assertAutoFilled();
    577     }
    578 
    579     @Test
    580     @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
    581     public void testDatasetAuthMixedFilteringSelectAuth() throws Exception {
    582         datasetAuthMixedFilteringTest(true);
    583     }
    584 
    585     @Test
    586     @AppModeFull // testDatasetAuthFilteringUsingRegex() is enough to test ephemeral apps support
    587     public void testDatasetAuthMixedFilteringSelectNonAuth() throws Exception {
    588         datasetAuthMixedFilteringTest(false);
    589     }
    590 
    591     private void datasetAuthMixedFilteringTest(boolean selectAuth) throws Exception {
    592         // Set service.
    593         enableService();
    594         final MyAutofillCallback callback = mActivity.registerCallback();
    595 
    596         // Create the authentication intents
    597         final CannedDataset unlockedDataset = new CannedDataset.Builder()
    598                 .setField(ID_USERNAME, "DUDE")
    599                 .setField(ID_PASSWORD, "SWEET")
    600                 .build();
    601         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    602                 unlockedDataset);
    603 
    604         // Configure the service behavior
    605         sReplier.addResponse(new CannedFillResponse.Builder()
    606                 .addDataset(new CannedDataset.Builder()
    607                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
    608                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
    609                         .setPresentation(createPresentation("Tap to auth dataset"))
    610                         .setAuthentication(authentication)
    611                         .build())
    612                 .addDataset(new CannedDataset.Builder()
    613                         .setField(ID_USERNAME, "dude")
    614                         .setField(ID_PASSWORD, "sweet")
    615                         .setPresentation(createPresentation("What, me auth?"))
    616                         .build())
    617                 .build());
    618 
    619         // Set expectation for the activity
    620         if (selectAuth) {
    621             mActivity.expectAutoFill("DUDE", "SWEET");
    622         } else {
    623             mActivity.expectAutoFill("dude", "sweet");
    624         }
    625 
    626         // Trigger auto-fill.
    627         requestFocusOnUsername();
    628 
    629         // Wait for onFill() before proceeding.
    630         sReplier.getNextFillRequest();
    631         final View username = mActivity.getUsername();
    632 
    633         // Make sure it's showing initially...
    634         callback.assertUiShownEvent(username);
    635         mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
    636 
    637         // Filter the auth dataset.
    638         mActivity.onUsername((v) -> v.setText("d"));
    639         mUiBot.assertDatasets("What, me auth?");
    640 
    641         // Filter all.
    642         mActivity.onUsername((v) -> v.setText("dw"));
    643         callback.assertUiHiddenEvent(username);
    644         mUiBot.assertNoDatasets();
    645 
    646         // Now delete the char and assert the non-auth is shown again.
    647         mActivity.onUsername((v) -> v.setText("d"));
    648         callback.assertUiShownEvent(username);
    649         mUiBot.assertDatasets("What, me auth?");
    650 
    651         // Delete again and assert all dataset are shown.
    652         mActivity.onUsername((v) -> v.setText(""));
    653         mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
    654 
    655         // ...and select it this time
    656         final String chosenOne = selectAuth ? "Tap to auth dataset" : "What, me auth?";
    657         mUiBot.selectDataset(chosenOne);
    658         callback.assertUiHiddenEvent(username);
    659         mUiBot.assertNoDatasets();
    660 
    661         // Check the results.
    662         mActivity.assertAutoFilled();
    663     }
    664 
    665     @Test
    666     public void testDatasetAuthClientStateSetOnIntentOnly() throws Exception {
    667         fillDatasetAuthWithClientState(ClientStateLocation.INTENT_ONLY);
    668     }
    669 
    670     @Test
    671     @AppModeFull // testDatasetAuthClientStateSetOnIntentOnly() is enough to test ephemeral apps
    672     public void testDatasetAuthClientStateSetOnFillResponseOnly() throws Exception {
    673         fillDatasetAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
    674     }
    675 
    676     @Test
    677     @AppModeFull // testDatasetAuthClientStateSetOnIntentOnly() is enough to test ephemeral apps
    678     public void testDatasetAuthClientStateSetOnIntentAndFillResponse() throws Exception {
    679         fillDatasetAuthWithClientState(ClientStateLocation.BOTH);
    680     }
    681 
    682     private void fillDatasetAuthWithClientState(ClientStateLocation where) throws Exception {
    683         // Set service.
    684         enableService();
    685 
    686         // Prepare the authenticated response
    687         final CannedDataset dataset = new CannedDataset.Builder()
    688                 .setField(ID_USERNAME, "dude")
    689                 .setField(ID_PASSWORD, "sweet")
    690                 .build();
    691         final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
    692                 ? AuthenticationActivity.createSender(mContext, 1,
    693                         dataset)
    694                 : AuthenticationActivity.createSender(mContext, 1,
    695                         dataset, newClientState("CSI", "FromIntent"));
    696 
    697         // Configure the service behavior
    698         sReplier.addResponse(new CannedFillResponse.Builder()
    699                 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
    700                 .setExtras(newClientState("CSI", "FromResponse"))
    701                 .addDataset(new CannedDataset.Builder()
    702                         .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
    703                         .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
    704                         .setPresentation(createPresentation("Tap to auth dataset"))
    705                         .setAuthentication(authentication)
    706                         .build())
    707                 .build());
    708 
    709         // Set expectation for the activity
    710         mActivity.expectAutoFill("dude", "sweet");
    711 
    712         // Trigger auto-fill.
    713         requestFocusOnUsername();
    714         sReplier.getNextFillRequest();
    715 
    716         // Tap authentication request.
    717         mUiBot.selectDataset("Tap to auth dataset");
    718 
    719         // Check the results.
    720         mActivity.assertAutoFilled();
    721 
    722         // Now trigger save.
    723         mActivity.onUsername((v) -> v.setText("malkovich"));
    724         mActivity.onPassword((v) -> v.setText("malkovich"));
    725         final String expectedMessage = getWelcomeMessage("malkovich");
    726         final String actualMessage = mActivity.tapLogin();
    727         assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
    728         mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
    729 
    730         // Assert client state on authentication activity.
    731         assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
    732 
    733         // Assert client state on save request.
    734         final SaveRequest saveRequest = sReplier.getNextSaveRequest();
    735         final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
    736                 ? "FromResponse" : "FromIntent";
    737         assertClientState("on save", saveRequest.data, "CSI", expectedValue);
    738     }
    739 
    740     @Test
    741     public void testFillResponseAuthBothFields() throws Exception {
    742         fillResponseAuthBothFields(false);
    743     }
    744 
    745     @Test
    746     @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
    747     public void testFillResponseAuthBothFieldsUserCancelsFirstAttempt() throws Exception {
    748         fillResponseAuthBothFields(true);
    749     }
    750 
    751     private void fillResponseAuthBothFields(boolean cancelFirstAttempt) throws Exception {
    752         // Set service.
    753         enableService();
    754         final MyAutofillCallback callback = mActivity.registerCallback();
    755 
    756         // Prepare the authenticated response
    757         final Bundle clientState = new Bundle();
    758         clientState.putString("numbers", "4815162342");
    759         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    760                 new CannedFillResponse.Builder().addDataset(
    761                         new CannedDataset.Builder()
    762                                 .setField(ID_USERNAME, "dude")
    763                                 .setField(ID_PASSWORD, "sweet")
    764                                 .setId("name")
    765                                 .setPresentation(createPresentation("Dataset"))
    766                                 .build())
    767                         .setExtras(clientState).build());
    768 
    769         // Configure the service behavior
    770         sReplier.addResponse(new CannedFillResponse.Builder()
    771                 .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
    772                 .setPresentation(createPresentation("Tap to auth response"))
    773                 .setExtras(clientState)
    774                 .build());
    775 
    776         // Set expectation for the activity
    777         mActivity.expectAutoFill("dude", "sweet");
    778 
    779         // Trigger auto-fill.
    780         requestFocusOnUsername();
    781 
    782         // Wait for onFill() before proceeding.
    783         sReplier.getNextFillRequest();
    784         final View username = mActivity.getUsername();
    785         callback.assertUiShownEvent(username);
    786         mUiBot.assertDatasets("Tap to auth response");
    787 
    788         // Make sure UI is show on 2nd field as well
    789         final View password = mActivity.getPassword();
    790         requestFocusOnPassword();
    791         callback.assertUiHiddenEvent(username);
    792         callback.assertUiShownEvent(password);
    793         mUiBot.assertDatasets("Tap to auth response");
    794 
    795         // Now tap on 1st field to show it again...
    796         requestFocusOnUsername();
    797         callback.assertUiHiddenEvent(password);
    798         callback.assertUiShownEvent(username);
    799 
    800         if (cancelFirstAttempt) {
    801             // Trigger the auth dialog, but emulate cancel.
    802             AuthenticationActivity.setResultCode(RESULT_CANCELED);
    803             mUiBot.selectDataset("Tap to auth response");
    804             callback.assertUiHiddenEvent(username);
    805             callback.assertUiShownEvent(username);
    806             mUiBot.assertDatasets("Tap to auth response");
    807 
    808             // Make sure it's still shown on other fields...
    809             requestFocusOnPassword();
    810             callback.assertUiHiddenEvent(username);
    811             callback.assertUiShownEvent(password);
    812             mUiBot.assertDatasets("Tap to auth response");
    813 
    814             // Tap on 1st field to show it again...
    815             requestFocusOnUsername();
    816             callback.assertUiHiddenEvent(password);
    817             callback.assertUiShownEvent(username);
    818         }
    819 
    820         // ...and select it this time
    821         AuthenticationActivity.setResultCode(RESULT_OK);
    822         mUiBot.selectDataset("Tap to auth response");
    823         callback.assertUiHiddenEvent(username);
    824         callback.assertUiShownEvent(username);
    825         final UiObject2 picker = mUiBot.assertDatasets("Dataset");
    826         mUiBot.selectDataset(picker, "Dataset");
    827         callback.assertUiHiddenEvent(username);
    828         mUiBot.assertNoDatasets();
    829 
    830         // Check the results.
    831         mActivity.assertAutoFilled();
    832 
    833         final Bundle data = AuthenticationActivity.getData();
    834         assertThat(data).isNotNull();
    835         final String extraValue = data.getString("numbers");
    836         assertThat(extraValue).isEqualTo("4815162342");
    837     }
    838 
    839     @Test
    840     @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
    841     public void testFillResponseAuthJustOneField() throws Exception {
    842         // Set service.
    843         enableService();
    844         final MyAutofillCallback callback = mActivity.registerCallback();
    845 
    846         // Prepare the authenticated response
    847         final Bundle clientState = new Bundle();
    848         clientState.putString("numbers", "4815162342");
    849         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    850                 new CannedFillResponse.Builder().addDataset(
    851                         new CannedDataset.Builder()
    852                                 .setField(ID_USERNAME, "dude")
    853                                 .setField(ID_PASSWORD, "sweet")
    854                                 .setPresentation(createPresentation("Dataset"))
    855                                 .build())
    856                         .build());
    857 
    858         // Configure the service behavior
    859         sReplier.addResponse(new CannedFillResponse.Builder()
    860                 .setAuthentication(authentication, ID_USERNAME)
    861                 .setIgnoreFields(ID_PASSWORD)
    862                 .setPresentation(createPresentation("Tap to auth response"))
    863                 .setExtras(clientState)
    864                 .build());
    865 
    866         // Set expectation for the activity
    867         mActivity.expectAutoFill("dude", "sweet");
    868 
    869         // Trigger auto-fill.
    870         requestFocusOnUsername();
    871 
    872         // Wait for onFill() before proceeding.
    873         sReplier.getNextFillRequest();
    874         final View username = mActivity.getUsername();
    875         callback.assertUiShownEvent(username);
    876         mUiBot.assertDatasets("Tap to auth response");
    877 
    878         // Make sure UI is not show on 2nd field
    879         requestFocusOnPassword();
    880         callback.assertUiHiddenEvent(username);
    881         mUiBot.assertNoDatasets();
    882         // Now tap on 1st field to show it again...
    883         requestFocusOnUsername();
    884         callback.assertUiShownEvent(username);
    885 
    886         // ...and select it this time
    887         mUiBot.selectDataset("Tap to auth response");
    888         callback.assertUiHiddenEvent(username);
    889         final UiObject2 picker = mUiBot.assertDatasets("Dataset");
    890 
    891         callback.assertUiShownEvent(username);
    892         mUiBot.selectDataset(picker, "Dataset");
    893         callback.assertUiHiddenEvent(username);
    894         mUiBot.assertNoDatasets();
    895 
    896         // Check the results.
    897         mActivity.assertAutoFilled();
    898         final Bundle data = AuthenticationActivity.getData();
    899         assertThat(data).isNotNull();
    900         final String extraValue = data.getString("numbers");
    901         assertThat(extraValue).isEqualTo("4815162342");
    902     }
    903 
    904     @Test
    905     @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
    906     public void testFillResponseAuthWhenAppCallsCancel() throws Exception {
    907         // Set service.
    908         enableService();
    909         final MyAutofillCallback callback = mActivity.registerCallback();
    910 
    911         // Prepare the authenticated response
    912         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
    913                 new CannedFillResponse.Builder().addDataset(
    914                         new CannedDataset.Builder()
    915                                 .setField(ID_USERNAME, "dude")
    916                                 .setField(ID_PASSWORD, "sweet")
    917                                 .setId("name")
    918                                 .setPresentation(createPresentation("Dataset"))
    919                                 .build())
    920                         .build());
    921 
    922         // Configure the service behavior
    923         sReplier.addResponse(new CannedFillResponse.Builder()
    924                 .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
    925                 .setPresentation(createPresentation("Tap to auth response"))
    926                 .build());
    927 
    928         // Trigger autofill.
    929         requestFocusOnUsername();
    930 
    931         // Wait for onFill() before proceeding.
    932         sReplier.getNextFillRequest();
    933         final View username = mActivity.getUsername();
    934         callback.assertUiShownEvent(username);
    935         mUiBot.assertDatasets("Tap to auth response");
    936 
    937         // Disables autofill so it's not triggered again after the auth activity is finished
    938         // (and current session is canceled) and the login activity is resumed.
    939         username.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
    940 
    941         // Autofill it.
    942         final CountDownLatch latch = new CountDownLatch(1);
    943         AuthenticationActivity.setResultCode(latch, RESULT_OK);
    944 
    945         mUiBot.selectDataset("Tap to auth response");
    946         callback.assertUiHiddenEvent(username);
    947 
    948         // Cancel session...
    949         mActivity.getAutofillManager().cancel();
    950 
    951         // ...before finishing the Auth UI.
    952         latch.countDown();
    953 
    954         mUiBot.assertNoDatasets();
    955     }
    956 
    957     @Test
    958     @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
    959     public void testFillResponseAuthServiceHasNoDataButCanSave() throws Exception {
    960         fillResponseAuthServiceHasNoDataTest(true);
    961     }
    962 
    963     @Test
    964     @AppModeFull // testFillResponseAuthBothFields() is enough to test ephemeral apps support
    965     public void testFillResponseAuthServiceHasNoData() throws Exception {
    966         fillResponseAuthServiceHasNoDataTest(false);
    967     }
    968 
    969     private void fillResponseAuthServiceHasNoDataTest(boolean canSave) throws Exception {
    970         // Set service.
    971         enableService();
    972         final MyAutofillCallback callback = mActivity.registerCallback();
    973 
    974         // Prepare the authenticated response
    975         final CannedFillResponse response = canSave
    976                 ? new CannedFillResponse.Builder()
    977                         .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
    978                         .build()
    979                 : CannedFillResponse.NO_RESPONSE;
    980 
    981         final IntentSender authentication =
    982                 AuthenticationActivity.createSender(mContext, 1, response);
    983 
    984         // Configure the service behavior
    985         sReplier.addResponse(new CannedFillResponse.Builder()
    986                 .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
    987                 .setPresentation(createPresentation("Tap to auth response"))
    988                 .build());
    989 
    990         // Trigger auto-fill.
    991         requestFocusOnUsername();
    992 
    993         // Wait for onFill() before proceeding.
    994         sReplier.getNextFillRequest();
    995         final View username = mActivity.getUsername();
    996         callback.assertUiShownEvent(username);
    997 
    998         // Select the authentication dialog.
    999         mUiBot.selectDataset("Tap to auth response");
   1000         callback.assertUiHiddenEvent(username);
   1001         mUiBot.assertNoDatasets();
   1002 
   1003         if (!canSave) {
   1004             // Our work is done!
   1005             return;
   1006         }
   1007 
   1008         // Set credentials...
   1009         mActivity.onUsername((v) -> v.setText("malkovich"));
   1010         mActivity.onPassword((v) -> v.setText("malkovich"));
   1011 
   1012         // ...and login
   1013         final String expectedMessage = getWelcomeMessage("malkovich");
   1014         final String actualMessage = mActivity.tapLogin();
   1015         assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
   1016 
   1017         // Assert the snack bar is shown and tap "Save".
   1018         mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
   1019 
   1020         final SaveRequest saveRequest = sReplier.getNextSaveRequest();
   1021         sReplier.assertNoUnhandledSaveRequests();
   1022         assertThat(saveRequest.datasetIds).isNull();
   1023 
   1024         // Assert value of expected fields - should not be sanitized.
   1025         final ViewNode usernameNode = findNodeByResourceId(saveRequest.structure, ID_USERNAME);
   1026         assertTextAndValue(usernameNode, "malkovich");
   1027         final ViewNode passwordNode = findNodeByResourceId(saveRequest.structure, ID_PASSWORD);
   1028         assertTextAndValue(passwordNode, "malkovich");
   1029     }
   1030 
   1031     @Test
   1032     public void testFillResponseAuthClientStateSetOnIntentOnly() throws Exception {
   1033         fillResponseAuthWithClientState(ClientStateLocation.INTENT_ONLY);
   1034     }
   1035 
   1036     @Test
   1037     @AppModeFull // testFillResponseAuthClientStateSetOnIntentOnly() is enough to test ephemeral
   1038     public void testFillResponseAuthClientStateSetOnFillResponseOnly() throws Exception {
   1039         fillResponseAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
   1040     }
   1041 
   1042     @Test
   1043     @AppModeFull // testFillResponseAuthClientStateSetOnIntentOnly() is enough to test ephemeral
   1044     public void testFillResponseAuthClientStateSetOnIntentAndFillResponse() throws Exception {
   1045         fillResponseAuthWithClientState(ClientStateLocation.BOTH);
   1046     }
   1047 
   1048     enum ClientStateLocation {
   1049         INTENT_ONLY,
   1050         FILL_RESPONSE_ONLY,
   1051         BOTH
   1052     }
   1053 
   1054     private void fillResponseAuthWithClientState(ClientStateLocation where) throws Exception {
   1055         // Set service.
   1056         enableService();
   1057 
   1058         // Prepare the authenticated response
   1059         final CannedFillResponse.Builder authenticatedResponseBuilder =
   1060                 new CannedFillResponse.Builder()
   1061                 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
   1062                 .addDataset(new CannedDataset.Builder()
   1063                         .setField(ID_USERNAME, "dude")
   1064                         .setField(ID_PASSWORD, "sweet")
   1065                         .setPresentation(createPresentation("Dataset"))
   1066                         .build());
   1067 
   1068         if (where == ClientStateLocation.FILL_RESPONSE_ONLY || where == ClientStateLocation.BOTH) {
   1069             authenticatedResponseBuilder.setExtras(newClientState("CSI", "FromAuthResponse"));
   1070         }
   1071 
   1072         final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
   1073                 ? AuthenticationActivity.createSender(mContext, 1,
   1074                         authenticatedResponseBuilder.build())
   1075                 : AuthenticationActivity.createSender(mContext, 1,
   1076                         authenticatedResponseBuilder.build(), newClientState("CSI", "FromIntent"));
   1077 
   1078         // Configure the service behavior
   1079         sReplier.addResponse(new CannedFillResponse.Builder()
   1080                 .setAuthentication(authentication, ID_USERNAME)
   1081                 .setIgnoreFields(ID_PASSWORD)
   1082                 .setPresentation(createPresentation("Tap to auth response"))
   1083                 .setExtras(newClientState("CSI", "FromResponse"))
   1084                 .build());
   1085 
   1086         // Set expectation for the activity
   1087         mActivity.expectAutoFill("dude", "sweet");
   1088 
   1089         // Trigger autofill.
   1090         requestFocusOnUsername();
   1091         sReplier.getNextFillRequest();
   1092 
   1093         // Tap authentication request.
   1094         mUiBot.selectDataset("Tap to auth response");
   1095 
   1096         // Tap dataset.
   1097         mUiBot.selectDataset("Dataset");
   1098 
   1099         // Check the results.
   1100         mActivity.assertAutoFilled();
   1101 
   1102         // Now trigger save.
   1103         mActivity.onUsername((v) -> v.setText("malkovich"));
   1104         mActivity.onPassword((v) -> v.setText("malkovich"));
   1105         final String expectedMessage = getWelcomeMessage("malkovich");
   1106         final String actualMessage = mActivity.tapLogin();
   1107         assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
   1108         mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
   1109 
   1110         // Assert client state on authentication activity.
   1111         assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
   1112 
   1113         // Assert client state on save request.
   1114         final SaveRequest saveRequest = sReplier.getNextSaveRequest();
   1115         final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
   1116                 ? "FromAuthResponse" : "FromIntent";
   1117         assertClientState("on save", saveRequest.data, "CSI", expectedValue);
   1118     }
   1119 
   1120     // TODO(on master): move to helper / reuse in other places
   1121     private void assertClientState(String where, Bundle data, String expectedKey,
   1122             String expectedValue) {
   1123         assertWithMessage("no client state on %s", where).that(data).isNotNull();
   1124         final String extraValue = data.getString(expectedKey);
   1125         assertWithMessage("invalid value for %s on %s", expectedKey, where)
   1126             .that(extraValue).isEqualTo(expectedValue);
   1127     }
   1128 
   1129     // TODO(on master): move to helper / reuse in other places
   1130     private Bundle newClientState(String key, String value) {
   1131         final Bundle clientState = new Bundle();
   1132         clientState.putString(key, value);
   1133         return clientState;
   1134     }
   1135 
   1136     @Test
   1137     public void testFillResponseFiltering() throws Exception {
   1138         // Set service.
   1139         enableService();
   1140         final MyAutofillCallback callback = mActivity.registerCallback();
   1141 
   1142         // Prepare the authenticated response
   1143         final Bundle clientState = new Bundle();
   1144         clientState.putString("numbers", "4815162342");
   1145         final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
   1146                 new CannedFillResponse.Builder().addDataset(
   1147                         new CannedDataset.Builder()
   1148                                 .setField(ID_USERNAME, "dude")
   1149                                 .setField(ID_PASSWORD, "sweet")
   1150                                 .setId("name")
   1151                                 .setPresentation(createPresentation("Dataset"))
   1152                                 .build())
   1153                         .setExtras(clientState).build());
   1154 
   1155         // Configure the service behavior
   1156         sReplier.addResponse(new CannedFillResponse.Builder()
   1157                 .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
   1158                 .setPresentation(createPresentation("Tap to auth response"))
   1159                 .setExtras(clientState)
   1160                 .build());
   1161 
   1162         // Set expectation for the activity
   1163         mActivity.expectAutoFill("dude", "sweet");
   1164 
   1165         // Trigger auto-fill.
   1166         requestFocusOnUsername();
   1167 
   1168         // Wait for onFill() before proceeding.
   1169         sReplier.getNextFillRequest();
   1170         final View username = mActivity.getUsername();
   1171 
   1172         // Make sure it's showing initially...
   1173         callback.assertUiShownEvent(username);
   1174         mUiBot.assertDatasets("Tap to auth response");
   1175 
   1176         // ..then type something to hide it.
   1177         mActivity.onUsername((v) -> v.setText("a"));
   1178         callback.assertUiHiddenEvent(username);
   1179         mUiBot.assertNoDatasets();
   1180 
   1181         // Now delete the char and assert it's shown again...
   1182         mActivity.onUsername((v) -> v.setText(""));
   1183         callback.assertUiShownEvent(username);
   1184         mUiBot.assertDatasets("Tap to auth response");
   1185 
   1186         // ...and select it this time
   1187         AuthenticationActivity.setResultCode(RESULT_OK);
   1188         mUiBot.selectDataset("Tap to auth response");
   1189         callback.assertUiHiddenEvent(username);
   1190         callback.assertUiShownEvent(username);
   1191         final UiObject2 picker = mUiBot.assertDatasets("Dataset");
   1192         mUiBot.selectDataset(picker, "Dataset");
   1193         callback.assertUiHiddenEvent(username);
   1194         mUiBot.assertNoDatasets();
   1195 
   1196         // Check the results.
   1197         mActivity.assertAutoFilled();
   1198 
   1199         final Bundle data = AuthenticationActivity.getData();
   1200         assertThat(data).isNotNull();
   1201         final String extraValue = data.getString("numbers");
   1202         assertThat(extraValue).isEqualTo("4815162342");
   1203     }
   1204 }
   1205