web-dev-qa-db-fra.com

Comment lire le contenu de la fenêtre (avec accessibilityService) et comment évoquer une interface utilisateur en utilisant Draw par rapport aux autorisations d'autres applications dans Android?

Ma dernière question sur le même sujet n'était pas assez claire et a été mise en attente par la communauté. Elle a ensuite été automatiquement supprimée. J'explique donc cette question de manière détaillée afin que la communauté puisse comprendre et aider de manière plus efficace.

Je veux des fonctionnalités similaires aux offres Voodoo App _ et MySmartPrice .

Maintenant ce qu'ils font

Étape 1: Lorsque nous ouvrons l'application Voodoo pour la première fois, un didacticiel est présenté. À la fin du didacticiel, il existe un bouton "Activer maintenant" qui, lorsqu'il est enfoncé, nous amène à l'écran de paramètres d'accessibilité.

Étape 2: Sur l'écran d'accessibilité, il explique également comment rechercher et désactiver le service Voodoo.

Étape 3: Lorsque nous l'activons, il demande en outre d'accorder les autorisations "Observez votre action" et "Récupérer le contenu de la fenêtre".

Étape 4: Une fois que nous avons fini d'octroyer les autorisations sur l'écran d'accessibilité et de passer à une application de shopping ou d'accéder à un site de vente via un navigateur et d'atteindre la page du produit, un bouton flottant vaudou apparaît automatiquement.

Étape 5: Une fois que nous avons cliqué dessus, le prix des produits identiques/apparentés/similaires disponibles sur d'autres applications ou sur un site Web s'affiche, de sorte que l'utilisateur puisse rechercher la meilleure offre disponible.

Capture d'écran de référence de Voodoo

Voodoo Screen 1

Accessibility screen

Accessibility screen 2

Permission Granting Screen

Voodoo Screen 2

Voodoo Floating Button on product page

Voodoo Results with the help of draw over other app

Maintenant, ce que je veux savoir forme communauté:

  1. Comment puis-je afficher mon interface utilisateur d'aide sur l'écran d'accessibilité et la page de détail du produit?.
  2. Comment détecter quand une page de produit est là à l'écran et comment évoquer mon bouton flottant.
  3. Comment récupérer le nom du produit affiché à l'écran.
  4. Comment limiter cette fonctionnalité de lecture d'écran pour certaines applications uniquement? (comme je ne veux pas me retrouver dans une question de droit d'auteur)
  5. Existe-t-il un tutoriel qui puisse m'aider? Bien que j'avais déjà essayé sur Google pour un tutoriel direct et n'ai pas eu de succès. 

Maintenant, pourquoi j'ai besoin de cette information:

Je suis en train de planifier une application pour les étudiants qui les aidera à y parvenir gratuitement (ebook), s'il est disponible sur mon serveur ou sur un site Web disponible. Je souhaite limiter la fonctionnalité à certaines applications uniquement en raison de problèmes de droits d'auteur sur certains livres.

Maintenant, ce que je sais de mon étude sur ce sujet (mais je ne suis pas sûr de savoir si je suis sur la bonne voie ou non)

17
Umesh Chauhan

J'avais essayé de résumer comment j'avais pu résoudre le problème dans un article de blog. Quiconque a besoin d'aide peut y jeter un coup d'œil.

Service d'accessibilité au niveau suivant

Ma réponse précédente a été supprimée par les modérateurs car je viens de poster un lien vers un blog. Donc, je poste encore ma réponse avec des détails ici aussi.

Le moyen le plus simple est fourni par Android lui-même. Si vous construisez quelque chose sur votre propre application, c'est le moyen le plus simple et le plus simple de le faire. Vous devez utiliser «findAccessibilityNodeInfosByViewId ()» Comme expliqué ci-dessous.

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    AccessibilityNodeInfo source = event.getSource(); 
    if (source == null) {
        return; 
    } 
    List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId = source.findAccessibilityNodeInfosByViewId("YOUR PACKAGE NAME:id/RESOURCE ID FROM WHERE YOU WANT DATA"); 
    if (findAccessibilityNodeInfosByViewId.size() > 0) {
        AccessibilityNodeInfo parent = (AccessibilityNodeInfo) findAccessibilityNodeInfosByViewId.get(0);
        // You can also traverse the list if required data is deep in view hierarchy. 
        String requiredText = parent.getText().toString();
        Log.i("Required Text", requiredText);
    }
}  

Si vous construisez quelque chose sur d’autres applications et que vous ne connaissez pas l’identifiant res. Vous devez créer une logique associant parent, nombre d'enfants, niveau sur lequel vos données sont trouvées et type d'événement. Vous devez rechercher un modèle dans event ou source ou la combinaison des valeurs ci-dessus pour obtenir précieusement les données requises. De plus, vous devez configurer quelques modifications dans votre code pour obtenir des données précises en fonction de votre tâche. Comme dans notre tâche, nous avons des regex pour obtenir des données précieuses.

Vous devez veiller à ce que la logique actuelle échoue si la vue ou l'interface utilisateur est modifiée ou si les identifiants de connexion sont modifiés. Donc, vous devez regarder de près l'application sur laquelle vous construisez votre service. Vous trouverez ci-dessous un exemple de code dans lequel nous obtenons des données sans identifiant de réseau, ce qui peut vous être utile pour comprendre comment cela fonctionnera.

Pour imprimer la source et l'événement

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    AccessibilityNodeInfo source = event.getSource();
    if (source == null) {
        return;
    } 
    Log.i("Event", event.toString+””); 
    Log.i("Source", source.toString+””);
}

Pour obtenir le nombre d'enfants

source.getChildCount();

Si le nombre d'enfants est> 0, vous devrez peut-être examiner la question.

Exemple de code 1

if (level == 0 && source.getClassName().equals("Android.widget.TextView") && source.getText()!=null && !source.getText().toString().isEmpty()){
    // here level is iteration of for loop
    String recivedText = source.getText().toString(); 
    if(source.getClassName().equals("Android.widget.TextView") && source.getParent()!=null && source.getParent().getClassName().equals("Android.widget.FrameLayout") && source.getParent().getParent()==null){ 
        return recivedText;
    }
}

Exemple de code 2

if (source.getPackageName().equals("PACKAGE NAME OF APP FOR WHICH YOUR EXPECTING EVENT")) {
    if(event.getEventType()==AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && "COMPLETE NAME OF ACTIVITY CLASS WITH PACKAGE NAME (if you want it for some specific screen)".equals(event.getClassName())){
        if(source.getText()!=null && source.getClassName().equals("Android.widget.TextView") && source.getParent()!=null && source.getParent().getClassName().equals("Android.widget.RelativeLayout")&& source.getParent().getParent()!=null && source.getParent().getParent().getClassName().equals("Android.widget.ScrollView") && source.getParent().getParent().getParent()!=null && source.getParent().getParent().getParent().getClassName().equals("Android.support.v4.view.ViewPager")&& source.getParent().getParent().getParent().getParent()!=null && source.getParent().getParent().getParent().getParent().getClassName().equals("Android.widget.FrameLayout")&& source.getParent().getParent().getParent().getParent().getParent()==null){
        return source.getText().toString();
        }
}

C'est un peu maladroit, mais pour que cela fonctionne, vous devez examiner en profondeur les journaux pour trouver un modèle qui vous mènera aux données requises.

Mise à jour 20/11/2017 Google suspend toutes les applications utilisant des services d'accessibilité pour des tâches autres que l'accessibilité. J'avais reçu un courrier électronique le concernant pour l'une de mes applications et d'autres développeurs recevaient également le même courrier électronique de Google ( Reddit ). Donc, je pense que nous devrions chercher une autre façon de faire les choses et je vous demande de bien vouloir l'actualiser ici aussi, si quelqu'un propose une autre implémentation pour obtenir le même comportement, cela aiderait également les autres.

Merci Umesh Chauhan

24
Umesh Chauhan

J'ai réussi à réaliser ce type d'application comme voodoo.et obtenir le titre, le prix, etc., de la page produit Flipkart. la méthode suivante utilisée pour que l’utilisateur ouvre l’écran du produit.

private boolean isOpenFlipkartProductScreen(AccessibilityNodeInfo nodeInfo){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
        if(nodeInfo.getViewIdResourceName()!=null){
            if(nodeInfo.getViewIdResourceName().equals("com.flipkart.Android:id/callout_last_linearlayout")){
                Utils.sPrint("You just open product page : " + nodeInfo.getClass());
                isOpenProductPage = true;
                return true;
            }
        }
    }
    return false;
}

et le code suivant à utiliser obtient le nom du titre du produit et son prix.

private String getObtainTitle(AccessibilityNodeInfo sourceInfo){

    if(sourceInfo == null)
        return "";

    AccessibilityNodeInfo nodeInfo = sourceInfo.getParent().getParent();
    if(nodeInfo!=null){
        int i = 0;
        int i2 = 0;
        for(int i3=0;i3<nodeInfo.getChildCount();i3++){

            try{
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    if(nodeInfo.getChild(i3).getViewIdResourceName().equals("com.flipkart.Android:id/title_layout")) {
                        i = 0;
                        //   while ( i < nodeInfo.getChild(i).getChildCount()){
                        AccessibilityNodeInfo child = nodeInfo.getChild(i3).getChild(i);
                        String charSequence = child.getText().toString();
                        //   Utils.sPrint("Title is : " + charSequence);
                        if(charSequence!=null){
                            return  charSequence;
                        }
                        // }

                    }
                }
               /*
               *
               * Below code to used for getProduct prise in flipkart app product
               *
               * */
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    if(nodeInfo.getChild(i3).getViewIdResourceName().equals("com.flipkart.Android:id/price_layout")){
                        AccessibilityNodeInfo child = nodeInfo.getChild(i3).getChild(i);
                        String charSequence = child.getText().toString();

                        if (child.getText().toString().toUpperCase().startsWith("RS.") ||
                                child.getText().toString().toUpperCase().startsWith("\u20b9")) {
                            String replace = charSequence.replace("Rs.",
                                    "").replace("\u20b9", "");

                            //return replace
                            //   Utils.sPrint("Prise is : " + replace);
                        }

                    }
                }
            }catch (Exception ex){
              //  Utils.sPrint("Ex : " + ex.getMessage());
                return "";
            }

        }
    }
    return "";
}
0
user6443638