| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.afwtest.uiautomator.utils; |
| |
| import android.os.SystemClock; |
| import android.support.test.uiautomator.By; |
| import android.support.test.uiautomator.BySelector; |
| import android.support.test.uiautomator.UiDevice; |
| import android.support.test.uiautomator.UiObject2; |
| import android.util.Log; |
| import android.view.KeyEvent; |
| |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * Text field related util functions. |
| */ |
| public final class TextField { |
| |
| private static final String TAG = "afwtest.TextField"; |
| |
| /** |
| * Default UI waiting time, in milliseconds. |
| */ |
| private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5); |
| |
| /** |
| * Keyboard pop up waiting time, in milliseconds. |
| */ |
| private static final long KEYBOARD_START_TIME_MS = TimeUnit.SECONDS.toMillis(2); |
| |
| /** |
| * Private constructor to prevent instantiation. |
| */ |
| private TextField() { |
| } |
| |
| /** |
| * Inputs text into a text field and activate the navigation button. |
| * |
| * <p>Normally {@link UiObject2}.setText() will input text into a text field. |
| * But on some activities, such as Add Google Account page, the navigation button (e.g. NEXT) |
| * will not be activated until there is some non-space characters entered into the text |
| * field. Calling {@link UiObject2}.setText() will set the text but not activate the |
| * navigate button. |
| * This util function solves this problem by simulating key pressing event to enter '0' |
| * into the text filed to activate the navigation button before calling {@link UiObject2}. |
| * setText() to set the text. |
| * </p> |
| * |
| * @param uiDevice {@link UiDevice} object |
| * @param textFieldSelector {@link BySelector} for the text field |
| * @param text text to set |
| * @param navigationBtnSelector navigation button to activate |
| */ |
| public static void enterTextAndActivateNavigationBtn( |
| UiDevice uiDevice, |
| BySelector textFieldSelector, |
| String text, |
| BySelector navigationBtnSelector) throws Exception { |
| |
| // Try 3 times |
| int maxAttempts = 3; |
| while (maxAttempts > 0) { |
| |
| Log.i(TAG, String.format("Activating navigation button: %s.", |
| navigationBtnSelector.toString())); |
| |
| try { |
| activateNavigationBtn(uiDevice, textFieldSelector, navigationBtnSelector); |
| // Navigation button activated, exit loop |
| break; |
| } catch (Exception e) { |
| |
| --maxAttempts; |
| |
| // Don't throw in the retry loop |
| Log.e(TAG, String.format("Failed to activate navigation button, attempts left: %d.", |
| maxAttempts), e); |
| } |
| } |
| |
| // Throw exception if activation button is not activated. |
| if (maxAttempts <= 0) { |
| throw new RuntimeException(String.format("Failed to activate navigation button", |
| navigationBtnSelector.toString())); |
| } |
| |
| // Hide keyboard. |
| uiDevice.pressBack(); |
| |
| // Set the text now. |
| UiObject2 textField = WidgetUtils.safeWait(uiDevice, |
| textFieldSelector, |
| DEFAULT_TIMEOUT_MS, |
| 3); |
| if (textField == null) { |
| throw new RuntimeException( |
| "Failed to find text field: " + textFieldSelector.toString()); |
| } |
| |
| |
| textField.setText(text); |
| } |
| |
| /** |
| * Activates the navigation button by simulating a key pressing event to enter '0'. |
| * |
| * @param uiDevice {@link UiDevice} object |
| * @param textFieldSelector {@link BySelector} for the text field |
| * @param navigationBtnSelector navigation button to activate |
| */ |
| private static void activateNavigationBtn(UiDevice uiDevice, |
| BySelector textFieldSelector, |
| BySelector navigationBtnSelector) throws Exception { |
| WidgetUtils.waitAndClick(uiDevice, textFieldSelector, DEFAULT_TIMEOUT_MS, 3); |
| |
| // Clicking the text field will bring up the keyboard and change the view hierachy of |
| // current screen; textField may become stale. Try to find it again before simulating |
| // the keyboard events. |
| SystemClock.sleep(KEYBOARD_START_TIME_MS); |
| if (WidgetUtils.safeWait(uiDevice, textFieldSelector, DEFAULT_TIMEOUT_MS, 3) == null) { |
| throw new RuntimeException( |
| "Failed to find text field: " + textFieldSelector.toString()); |
| } |
| |
| // Simulate an event to enter '0' to the text field, this will activate the navigate button. |
| if (!uiDevice.pressKeyCode(KeyEvent.KEYCODE_0)) { |
| throw new RuntimeException(String.format("Failed to enter 0 into the text field %s", |
| textFieldSelector.toString())); |
| } |
| |
| // Wait for the navigation button to be activated. |
| BySelector newNavigationBtnSelector = By.copy(navigationBtnSelector).enabled(true); |
| if (WidgetUtils.safeWait(uiDevice, |
| newNavigationBtnSelector, |
| DEFAULT_TIMEOUT_MS, |
| 3) == null) { |
| throw new RuntimeException(String.format("Failed to activate navigation button: %s", |
| navigationBtnSelector.toString())); |
| } |
| } |
| } |