7 votes

Comment appuyer deux fois sur un bouton à l'aide de Google UiAutomator ?

J'ai le script suivant pour taper '33' dans la calculatrice, dans Android, en utilisant UiAutomator. Cependant, seul le premier '3' est accepté, la deuxième pression est entièrement ignorée.

import com.android.uiautomator.core.*;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;

public class MyFirstUiAutomatorTest extends UiAutomatorTestCase {
    UiObject getByDescription(String description) {
        return new UiObject(new UiSelector().description(description));
    }

    UiObject getByText(String description) {
        return new UiObject(new UiSelector().text(description));
    }

    UiObject scrollableGetByText(String text ) throws UiObjectNotFoundException {
            UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
            uiScrollable.setAsHorizontalList();
            return uiScrollable.getChildByText(new UiSelector().className(
                    android.widget.TextView.class.getName()),
                    text);      
    }

    public void testStuff() throws UiObjectNotFoundException {
        getUiDevice().pressHome();
        getByDescription("Apps").clickAndWaitForNewWindow();
        getByText("Apps").click();
        scrollableGetByText("Calculator").clickAndWaitForNewWindow();

        // pressing '+' and '=' effectively clears the previous input
        getByText("+").click();
        getByText("=").click();
        getByText("3").click();
        // this second '3' is ignored
        getByText("3").click();
    }
}

J'ai essayé d'ajouter une mise en veille pendant 2 secondes après le premier clic, en faisant :

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

... mais cela n'a rien changé.

J'ai également essayé de cliquer sur un bouton différent, entre les 2 '3', c'est-à-dire :

        new UiObject(new UiSelector().text("3")).click();
        new UiObject(new UiSelector().className("android.widget.EditText")).click();
        new UiObject(new UiSelector().text("3")).click();

... mais ça n'a pas marché non plus.

Des idées ?

(Note : utilisation d'Android 4.1.2, dans un AVD ; fonctionnement sur Ubuntu linux 12.04)

Edit, suite aux observations de Rami, j'ai essayé ce qui suit, pour réutiliser le même objet UiObject pour une deuxième demande pour la même description :

HashMap<String,UiObject> objectByText = new HashMap<String,UiObject>(); 
UiObject getByText(String description) {
    if( objectByText.containsKey(description)) {
        System.out.println("" + objectByText.get(description) );
        return objectByText.get(description);
    }
    System.out.println("Created new object for [" + description + "]");
    UiObject object = new UiObject(new UiSelector().text(description));
    objectByText.put(description, object );
    System.out.println("" + object );
    return object;
}

... mais cela n'a pas fonctionné, même s'il est clair que le même UiObject est réutilisé à chaque fois, car il n'est indiqué qu'une seule fois "Created new object for [3]".

J'ai ensuite essayé le "truc" UiDevice.click(), en créant une fonction "click" comme suit, en suivant les observations de Rami :

void click(UiObject target ) throws UiObjectNotFoundException {
    Rect rect = target.getBounds();
    System.out.println("rect: " + rect );
    getUiDevice().click(rect.centerX(), rect.centerY());
}

Cependant, cela n'a pas fonctionné pour moi non plus : seul le premier "3" apparaît, et le second est ignoré, même si les deux clics sont clairement au même endroit, parce que l'élément "3" n'a pas été utilisé. rect: Les emplacements de sortie sont identiques. Si je clique deux fois sur '3' manuellement, en utilisant ma propre souris de bureau, les deux 3 apparaissent correctement.

J'ai aussi essayé d'ajouter une seconde Thread.sleep() entre les clics, et toujours un seul '3' est apparu pour moi.

4voto

tophernuts Points 378

Au lieu de rechercher uniquement par le texte, essayez de rechercher par le texte et la classe. Voici un exemple de méthode pour le faire.

Uiobject getByTextAndClass(String text, String className) {
    return new UiObject(new UiSelector().text(text).className(className));
}

Et ensuite, si vous essayez d'appeler cette méthode pour le bouton de la calculatrice avec le numéro 3 dessus :

getByTextAndClass("3", android.widget.Button.class.getName()).click();

Vous pouvez utiliser l'outil UiAutomatorViewer : {Android-sdk}/tools/uiautomator.bat pour vérifier les noms de classe et autres attributs de différents UiObjects.

Cela fonctionne sur mes appareils 4.2.2, mais je suis en train de télécharger la 4.1.2 pour la tester également.

Je l'ai essayé sur un AVD 4.1.2 et il fonctionne sur ma machine Windows.

3voto

gangaramstyle Points 31

Ce problème semble être intégré dans la façon dont UiObject est configuré. Pour autant que je puisse dire, une instance de UiObject ne semble pas faire référence à un objet spécifique à l'écran. Il s'agit plutôt d'une instance de ce qui est pointé par l'UiSelector lorsque l'UiObject a été défini. La clé ici est que chaque fois que l'objet est appelé, il recherche un nouvel élément qui correspond aux exigences de l'UiSelector.

Des preuves :

UiObject ok = new UiObject(new UiSelector().text("OK"));
ok.click();
// clicks a button with the text ok on the page
// Navigate to some different page with a button with the text ok
ok.click();
// this ok button on a completely different page is still clicked

Par conséquent, je pense que la solution de Rami pourrait être la bonne façon de procéder (enregistrer l'emplacement de l'objet par ses coordonnées et cliquer sur le centre de cet emplacement). Il est important de noter que la solution de Rami consiste à enregistrer les coordonnées/le rectangle une fois, puis à réutiliser ces coordonnées/ce rectangle chaque fois que vous voulez vous référer à l'objet. Utiliser obj.getBounds() plusieurs fois sur le même objet ne semble pas fonctionner.

En outre, les enregistrements des éléments qui ont déjà été transmis lors de l'instanciation d'un UiObject semblent être stockés dans l'application. Exécuter deux fois un test qui trouve un UiObject (ex. le bouton 4 dans la page de réglage de l'alarme) et qui clique dessus échoue de la même manière qu'un test qui trouve un UiObject et qui clique dessus deux fois. Cela signifie que les données des requêtes d'objets doivent être stockées sur l'appareil car la réinitialisation de UIautomator ne fait aucune différence.

2voto

Rami Kuret Points 2911

J'ai trouvé une petite astuce pour contourner le problème pour l'instant. Obtenez les limites à chaque fois que vous exécutez le test afin qu'il ne soit pas centré sur l'appareil et s'adapte à la volée.

UiObject obj1 = new UiObject(new UiSelector().text("4"));

  Rect four = obj1.getBounds();

  getUiDevice().click(four.centerX(), four.centerY());

1voto

Rami Kuret Points 2911

J'ai le même problème, on dirait qu'il cherche un autre élément de l'interface utilisateur qui a le même texte. J'essaie d'automatiser la création d'une alarme mais quand l'heure est par exemple à 4:45 pm. Uiautomator va cliquer sur le bon bouton.

 clickByText("4");
 clickByText("4");
 clickByText("5");
 clickByText("PM");
 clickByText("OK");

private void clickByText(String text) throws UiObjectNotFoundException {
            UiObject obj = new UiObject(new UiSelector().text(text));
            obj.click();
    }

Voici le journal pour le premier clic "4" :

07-04 16:54:05.259 : I/QueryController(25605) : [ ] UiSelector [TEXT=4] <<==>> [Android.view.accessibi boundsInParent : Rect(0, 0 - 202, 129) ; boundsInScreen : Rect(56, 508 - 258, 637) ; nom du paquet : com.Android.deskclock ; nom de la classe : Android.widget.Button ; texte : 4 ; contentDescription : null ; checkable : false ; checked : false ; focusable : true ; focused : false ; selected : false ; clickable : true ; longClickable : false ; enabled : true ; password : false ; scrollable : false ; [ACTION_FOCUS, ACTION_SELECT, ACTION_CLEAR_SELECTION, ACTION_CLICK, ACTION_ACCESSIBILITY_FOCUS, ACTION_NEXT_AT_MOVEMENT_GRANULARITY, ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY]]

Voici le journal pour le deuxième clic "4" :

07-04 16:54:07.798 : I/QueryController(25605) : [ ] UiSelector [TEXT=4] <<==>> [Android. boundsInParent : Rect(0, 0 - 66, 90) ; boundsInScreen : Rect(191, 264 - 257, 354) ; nom du paquet : com.Android.des Android.widget.TextView ; texte : 4 ; contentDescription : null ; checkable : false ; checked : false ; focusable : false ; focused : false ; selected : false ; clickable : false ; longClickable : false ; enabled : true ; password : false ; scrollable : false ; [ACTION_SELECT, ACTION_CLEAR_SELECTION, ACTION_ACCESSIBILITY_FOCUS, ACTION_NEXT_AT_MOVEMENT_GRANULARITY, ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY]]

Nous pouvons voir que l'un d'entre eux clique sur le bouton Android.widget.Button de droite et que le second clique sur l'Android.widget.TextView.

0voto

Quick learner Points 637

Créez un UiObject pour le bouton 3 et cliquez deux fois.ci-dessous est le snippet

UiObject three = new UiObject(new UiSelector().text("3"));
three.click();
three.click();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X