Comment lire le contenu de la fenêtre (en utilisant accessibilityService) et évoquer L'UI en utilisant draw over autre permission d'application sous Android?

Mon dernière question sur le même sujet n'était pas assez claire et a été mis en attente par la communauté et plus tard, il a été automatiquement supprimé. J'explique donc cette Question en détail afin que la communauté puisse mieux comprendre et aider.

je veux des fonctionnalités similaires à Voodoo App et MySmartPrice offres.

Maintenant, ce qu'ils font

Etape 1: quand nous ouvrons le Vaudou Application pour la première fois, ils montrent un petit tutoriel. À la fin du tutoriel, il y a un bouton "Activer maintenant" qui, une fois appuyé, nous amène à l'écran des paramètres D'accessibilité.

Etape 2: dans L'écran Accessibilité, il indique comment trouver et désactiver le service Voodoo.

Etape 3: lorsque nous l'activons, il demande en outre d'accorder les permissions "observez votre Action" et "récupérez le contenu de la fenêtre".

Étape 4: une fois que nous avons accordé les permissions sur l'écran Accessibilité, et passer à une application de magasinage ou accéder au site de magasinage via le navigateur et atteindre la page du produit un bouton flottant voodoo apparaît automatiquement.

Étape 5: une fois que nous cliquons dessus, il affiche le prix des mêmes produits/apparentés/similaires disponibles sur d'autres applications ou site web afin que l'utilisateur puisse vérifier la meilleure offre disponible.

Screenshot de référence 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 de la communauté:

  1. comment je peux montrer mon aide UI over Écran d'accessibilité et page de détails sur les produits.
  2. Comment détecter quand une page produit est-il sur l'écran et d'évoquer mon bouton flottant.
  3. Comment récupérer le nom du produit affiché sur l'écran.
  4. comment restreindre cette fonctionnalité de lecture d'écran pour certaines applications seulement? (comme je n'ai pas envie de finir dans quelques problème de droit d'auteur)
  5. Est-il un tutoriel qui peut m'aider? Bien que J'avais déjà essayé sur Google pour n'importe quel tutoriel direct et n'ai pas obtenu succès.

Maintenant pourquoi j'ai besoin de cette information:

je planifie une application pour les étudiants qui les aidera à y arriver désirés (ou similaire) livre (ebook) gratuitement si elle est disponible sur mon serveur ou sur un site web qui est disponible. Je veux restreindre les fonctionnalités de certaines applications seulement pour des questions de droits sur certains livres.

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

16
demandé sur Community 2016-03-07 14:39:38

2 réponses

j'ai essayé de résumer comment j'ai pu résoudre le problème dans un billet de blog. Quiconque a besoin d'aide peut jeter un coup d'oeil.

service D'accessibilité au niveau suivant

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

le moyen le plus facile est fourni par android lui-même. Si vous construisez quelque chose sur votre propre application c'est le meilleur et la façon la plus simple possible 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 le res id. Vous avez à construire une logique avec la combinaison de parent, enfant, niveau sur lequel vos données est trouvé, le type d'événement. Vous devez chercher un modèle dans l'événement ou la source ou la combinaison des valeurs ci-dessus dit pour obtenir les données requises preciously. En outre, vous devez mettre en place certains tweak dans votre code pour obtenir les données précises selon votre tâche. Comme dans notre tâche, nous avons quelques regex pour obtenir de précieuses données.

Vous devez prendre soin que si la vue ou de l'INTERFACE utilisateur est modifié ou res id modifié votre logique pourrait échouer. Donc, vous devez garder un oeil de près l'application sur laquelle vous construisez votre service. Voici quelques exemples de code dans lequel nous obtenons des données sans restriction qui pourraient être utiles pour vous de comprendre comment cela va fonctionner.

imprimer source et é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 childcount

source.getChildCount();

Si l'enfant est >0, vous pourriez avoir à le regarder.

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();
        }
}

il est un peu maladroit mais pour le faire fonctionner vous devez regarder profondément dans les logs pour trouver un modèle qui vous mènera à vos données requises.

mise à Jour 20/11/2017 Google suspend toutes les applications utiliser les services d'accessibilité à des fins autres que l'accessibilité. J'avais reçu un e-mail concernant la même chose pour une de mes applications et d'autres développeurs reçoivent également le même e-mail de google ( Reddit). Donc, je pense que nous devrions chercher une autre façon de faire les choses et je vous demande de le mettre à jour ici aussi, si quelqu'un trouve une autre implémentation pour atteindre le même comportement, cela aiderait d'autres aussi.

Merci Umesh Chauhan!--6-->

21
répondu Umesh Chauhan 2017-11-20 09:27:18

j'ai fait avec succès ce type d'application, comme le vaudou.et obtenir le titre de la page de produit Flipkart, le prix etc avec succès. la méthode suivante utilisée pour obtenir l'écran de produit ouvert de l'utilisateur.

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 pour utiliser obtenir le nom du titre du produit et le 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
répondu Aashish Vivekanand 2018-01-08 05:36:16