Android, détecter lorsque d'autres applications sont lancées

92

J'essaie de développer une application qui empêche un utilisateur d'accéder à une application spécifiée sans mot de passe. Le scénario est ...

  1. l'utilisateur clique sur l'application "E-mail" (par exemple)
  2. mon application détecte le lancement d'une application
  3. mon application confirme qu'il s'agit de l'application "E-mail"
  4. mon application ouvre une vue sur le dessus, demandant un mot de passe
  5. l'utilisateur entre un mot de passe, s'il est correct, mon application disparaît, laissant l'application "E-mail" en haut

Je suis d'accord pour faire le reste, juste la partie 2 me laisse perplexe, et après de nombreux jours à lire sur les intentions de diffusion, etc. et à essayer d'écouter "android.intent.action.MAIN", etc. dans mes projets d'essai, je ne peux pas semblent détecter lorsqu'une application autre que la mienne est démarrée.

Quelqu'un peut-il aider? Est-ce que je procède de la bonne manière, en recherchant de nouvelles applications diffusant une intention de démarrage, ou devrais-je lire le journal système pour de nouvelles intentions, ou faire quelque chose en code natif?

N'importe quel pointeur aiderait, même si vous ne pouvez pas y répondre complètement, je pourrai faire plus de recherches. Merci beaucoup. Ian

Ian
la source
Je ne sais pas comment ils l'ont fait, mais des applications comme App Protector font exactement ce que vous demandez, c'est donc techniquement possible.
hanspeide
@lan comment vous avez résolu votre problème pouvez-vous s'il vous plaît partager vos connaissances
nida
Salut, avez-vous la solution?
ask4solutions

Réponses:

34

Je pense que nous pouvons utiliser logcat et analyser sa sortie.

Dans tous les programmes similaires, j'ai trouvé cette autorisation:

android.permission.READ_LOGS

Cela signifie qu'ils l'utilisent tous, mais il semble que le programme démarre et qu'après cela, notre programme (protecteur d'application) démarrera et se mettra au premier plan.

Utilisez le code ci-dessous:

try
    {
        Process mLogcatProc = null;
        BufferedReader reader = null;
        mLogcatProc = Runtime.getRuntime().exec(new String[]{"logcat", "-d"});

        reader = new BufferedReader(new InputStreamReader(mLogcatProc.getInputStream()));

        String line;
        final StringBuilder log = new StringBuilder();
        String separator = System.getProperty("line.separator"); 

        while ((line = reader.readLine()) != null)
        {
            log.append(line);
            log.append(separator);
        }
        String w = log.toString();
        Toast.makeText(getApplicationContext(),w, Toast.LENGTH_LONG).show();
    }
    catch (Exception e) 
    {
        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
    }

Et n'oubliez pas d'ajouter sa permission dans le fichier Manifest.

M.Movaffagh
la source
s'il vous plaît, où devons-nous mettre ce code? dans un service? dans le onStartCommand ()?
haythem souissi
56
ne fonctionnera pas à partir de JellyBean et au-dessus. L'autorisation READ_LOGS est désormais réservée aux applications système uniquement.
Ran le
5
En êtes-vous absolument sûr? Parce que Smart AppLock semble être capable de le faire même sur les appareils JB. Est-ce parce que l'application s'élève au statut d'administrateur de périphérique? play.google.com/store/apps/…
Karthik Balakrishnan
1
@Torcellite, cette application dispose de l'autorisation "Obtenir les tâches en cours d'exécution", elle peut donc utiliser cette technique à la place.
Sam
1
@Ran alors que faire pour l'utiliser maintenant ... existe-t-il une solution disponible maintenant pour résoudre le problème mentionné dans la question car je dois être au-dessus des
bonbons à la
19

Une façon astucieuse de le faire est d'avoir un service avec une boucle chronométrée qui vérifie

ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfo = am.getRunningAppProcesses();

Vous parcourez cette liste pour voir ce qui fonctionne sur le téléphone. Vous pouvez maintenant les identifier avec les identifiants et processName, donc pour les activités standard, c'est facile pour les activités personnalisées, sauf si vous les arrêtez, il est difficile de les distinguer ...

Remarque: ce n'est pas une liste de ce qui est réellement à l'écran, juste une liste de ce qui est en cours d'exécution ... annulant peut-être un peu votre objectif, mais au moins vous saurez quand quelque chose commence à fonctionner ... cela continuera à l'être. liste même en arrière-plan.

Pour le mot de passe, vous pouvez simplement démarrer votre activité lorsque vous avez trouvé une application protégée ou autre.

Aimeric
la source
est-il possible d'obtenir l'heure à laquelle l'application a été lancée / reprise?
0LLiena
4
Dans Android L, utilisez android.app.usageplutôt le package. developer.android.com/reference/android/app/usage/…
Plo_Koon
12

Je pense et j'espère que ce n'est pas possible. Pensez à la facilité avec laquelle une telle fonctionnalité pourrait être abusée par des logiciels malveillants. Vous pouvez écouter les intentions qui vous sont adressées et celles qui sont diffusées, mais le lancement d'une application ne doit pas être un événement de diffusion.

Ce que vous pourrez peut-être faire est de remplacer le lanceur . Si l'utilisateur y consent.

Pontus Gagge
la source
1
Pourquoi cela ne serait-il pas possible? C'est mon appareil et je décide quoi exécuter dessus. En quoi est-ce plus problématique que les autres autorisations que nous accordons régulièrement? Un lanceur de remplacement n'attrapera pas le lancement de toutes les applications uniquement celles lancées directement par lui. Il y a de nombreux commentaires à ce sujet et des discussions similaires sur SO affirmant que pouvoir simplement voir les intentions passer serait un problème énorme, mais personne n'explique quel est le problème et pourquoi il devrait être considéré comme si méchant que le système de privilèges existant ne le peut pas. être utilisé pour faire comprendre à l'utilisateur ce qui se passe.
Kevin Whitefoot
En ce qui concerne les autorisations potentielles, celui-ci est un doozy. L'intérêt d'avoir un modèle de sécurité est de permettre la plupart des cas d'utilisation légitimes, tout en empêchant la plupart (idéalement tous) les exploits. Ce n'est pas seulement vous (vraisemblablement un utilisateur averti) qui avez besoin d'être protégé, mais aussi les utilisateurs naïfs installant des applications et les créateurs d'applications qui n'ont pas à prendre en compte un autre vecteur d'attaque. Toute sécurité est un compromis: dans ce cas, entre l'utilité et la puissance contre une exploitabilité massive. Vous êtes libre de cloner la pile Android et de coder votre propre système si vous voulez vraiment ce degré de liberté pour vous-même.
Pontus Gagge
12
class CheckRunningActivity extends Thread{
    ActivityManager am = null;
    Context context = null;

    public CheckRunningActivity(Context con){
        context = con;
        am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    }

    public void run(){
        Looper.prepare();

        while(true){
            // Return a list of the tasks that are currently running,
            // with the most recent being first and older ones after in order.
            // Taken 1 inside getRunningTasks method means want to take only
            // top activity from stack and forgot the olders.
            List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1);

            String currentRunningActivityName = taskInfo.get(0).topActivity.getClassName();

            if (currentRunningActivityName.equals("PACKAGE_NAME.ACTIVITY_NAME")) {
                // show your activity here on top of PACKAGE_NAME.ACTIVITY_NAME
            }
        }
        Looper.loop();
    }
}

Vous pouvez obtenir le fonctionnement actuel Activityet vérifier si cela Activitycorrespond à l' Email application.

Exécuter CheckRunningActivity Threadau Applicationdémarrage (ou au démarrage de l'appareil).

new CheckRunningActivity().start();

Mise à jour: cette classe a besoin d'une android.permission.GET_TASKSautorisation, alors ajoutez la ligne suivante au manifeste:

<uses-permission android:name="android.permission.GET_TASKS" />
Veaceslav Gaidarji
la source
J'utilise cette approche, mais cela ouvrira votre "// afficher votre activité ici au-dessus de PACKAGE_NAME.ACTIVITY_NAME" encore et encore en raison de la boucle. Une solution de contournement pour cela?
Anuj Sharma
arrêtez le thread CheckRunningActivity lorsque vous obtenez le résultat souhaité
Veaceslav Gaidarji
Merci pour la réponse, alors comment / quand ce fil est-il redémarré? J'utilise un service Sticky.
Anuj Sharma
dépend du contexte du problème, décrivez plus en détail ce que vous voulez obtenir.
Veaceslav Gaidarji
2
Dans votre code ici, l' Looper.loop()instruction semble ne jamais être exécutée car la while(true)boucle ne se termine jamais. Est-ce une erreur?
Sam
11

Le problème principal est que vous essayez d'écouter les intentions implicites lorsque le lanceur (écran d'accueil) utilise généralement des intentions explicites.

Une intention implicite est lorsque vous voulez dire "Quelqu'un joue cette vidéo" et qu'Android choisit une application qui peut gérer cette intention.

Une intention explicite est ce qui se produit lorsque vous cliquez sur l'icône "E-mail" sur l'écran d'accueil. Il indique spécifiquement à Android d'ouvrir cette application spécifique par un nom complet (c'est-à-dire com.android.mail ou quelque chose).

Il n'y a aucun moyen pour l'AFAIK d'intercepter de telles intentions explicites. C'est une mesure de sécurité intégrée à Android que deux activités ne peuvent pas avoir le même nom de package complet. Cela empêche un tiers de cloner l'application et de se faire passer pour cette application. Si ce que vous souhaitez faire était possible, vous pourriez théoriquement installer une application qui pourrait empêcher toutes les applications de vos concurrents de fonctionner.

Ce que vous essayez de faire va à l'encontre du modèle de sécurité Android.

Une chose que vous pouvez faire est de vous associer à des développeurs d'applications spécifiques pour transmettre les intentions à votre système de sécurité, mais ce n'est probablement pas quelque chose que vous voulez traiter.

CodeFusionMobile
la source
7

getRunningTasks() est obsolète dans Android L.

Pour obtenir des statistiques d'utilisation des applications, vous pouvez utiliser la classe UsageStats du package android.app.usage .

La nouvelle API de statistiques d'utilisation des applications permet aux développeurs d'applications de collecter des statistiques liées à l'utilisation des applications. Cette API fournit des informations d'utilisation plus détaillées que la méthode obsolète getRecentTasks ().

Pour utiliser cette API, vous devez d'abord déclarer l' android.permission.PACKAGE_USAGE_STATSautorisation dans votre manifeste. L'utilisateur doit également activer l'accès pour cette application via Settings > Security > Apps with usage access.

Voici un exemple d'application de base montrant comment utiliser l'API de statistiques d'utilisation des applications pour permettre aux utilisateurs de collecter des statistiques liées à l'utilisation des applications.

Plo_Koon
la source
comment les statistiques d'utilisation peuvent aider à savoir quelle application est au premier plan?
Ajay
3

Peut-être avez-vous besoin d'un service, quelque chose qui fonctionnera constamment en arrière-plan. Que votre service fasse ce que vous avez dit. Écoutez le android.intent.action.MAIN également avec la catégorie android.intent.category.LAUNCHER. Ensuite, demandez à ce récepteur de diffusion de remplacer la méthode onReceive et de vérifier le nom de l'application, etc.

Jacob Malliet
la source
2
Cela ressemble à la méthode à laquelle je pensais, mais j'ai du mal à recevoir l'émission MAIN (cat. LAUNCHER) avec un BroadcastReceiver de base. Quelqu'un a-t-il déjà réussi à faire cela? À ce stade, je cherche simplement à détecter qu'une application a été lancée ou reprise. Je peux alors comparer le nom du package à une chaîne contenant le (s) nom (s) que je recherche.
Ian