Android, Detect when other apps are launched

I'm trying to develop an app that prevents a user from getting to a specified app without a password. The scenario is...

  1. user clicks on "Email" app (for example)
  2. my app detects launch of an app
  3. my app confirms it is the "Email" app
  4. my app opens a view over the top, asking for a password
  5. user enters a password, if correct, my app disappears, leaving the "Email" app on top

I'm ok doing the rest of it, just part 2 is puzzling me, and after many days reading up on Broadcast Intents etc and trying to listen for "android.intent.action.MAIN" etc in my trial projects I can't seem to detect when an app other than mine is started.

Can anyone help? Am I going about it the right way, in looking for new apps broadcasting an intent to start, or should I be reading the system log for new intents, or doing something in native code?

Any pointers would help, even if you can't answer it fully I'll be able to do some more research. Thanks a lot. Ian


Solution 1:

I think we can use logcat and analyze it's output.

In all similar programs I have found this permission :

android.permission.READ_LOGS

It means all of them use it but it seems the program starts and after that our program (app protector) will start and bring front.

Use below code :

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

And do not forget to add it's permission in Manifest file.

Solution 2:

A gimmicky way to do it is have a service with a timed loop that checks

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

You run through that list to look at what is running on the phone. Now you can identify them with ids and processName, so for standard activity this is easy for custom ones well unless you stop them all its hard to discriminate...

Note: this isnt a list of whats is actually on the screen, just a list of whats is running...kinda nullifying your goal maybe but at least you will know when something is starting to run... it will keep being in that list even when in background though.

For the password thing you can just start your activity when you found an app thats protected or whatever.

Solution 3:

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

You can get current running Activity and check if this Activity corresponds to Email application.

Run CheckRunningActivity Thread on Application start (or on device boot).

new CheckRunningActivity().start();

Update: This class need android.permission.GET_TASKS permission, so add next line to the Manifest:

<uses-permission android:name="android.permission.GET_TASKS" />