I have developed a service to automatically detect whether an app has started. If the user forbid this app to start (could be chosen from a list of apps), a dialog will be shown.

public class AppStartReceiver extends Service {
    private static final int DELAY_IN_MS = 2000;
    private List<String> forbiddenApps = new ArrayList<String>();
    private BroadcastReceiver screenReceiver = null;
    private Timer timer;
    private static boolean screenOn = true;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        //register screen on/off receiver
        registerScreenReceiver();

        if (forbiddenApps.isEmpty()) {
            DatabaseHelper db = new DatabaseHelper(this);
            forbiddenApps = db.getAllApps();
        }

        //start listening for app starts
        listenForAppStarts();

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(screenReceiver);
        timer.cancel();
        super.onDestroy();
    }

    /**
     * start listening for apps to start
     * only foreground apps are being watched
     */
    private void listenForAppStarts() {
        final ActivityManager actMgr = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {

            public void run() {
                final String foregroundApp = actMgr.getRunningTasks(1).get(0).topActivity.getPackageName();
                if (forbiddenApps.contains(foregroundApp)) {
                    //forbidden app detected => show dialog
                    Intent dialogIntent = new Intent(getBaseContext(), AlertActivity.class);
                    dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(dialogIntent);
                }

                // stop if user turns screen off
                if(!screenOn) {
                    timer.cancel();
                }
            }
        }, 0, DELAY_IN_MS);
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    /**
     * register screen receiver
     * gets callback from it
     */
    private void registerScreenReceiver() {
        // create new receiver
        screenReceiver = new BroadcastReceiver(){
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                    Log.i("ScreenReceiver", "Screen off");
                    screenOn = false;
                } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                    Log.i("ScreenReceiver", "Screen on");
                    listenForAppStarts();
                    screenOn = true;            
                }
            }
        };

        //register receiver
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        registerReceiver(screenReceiver, filter);
    }

}

I works perfectly, but I don't know how good it is (does it drain too much battery?). Also, I'd like to know if my programming style is ok.

share|improve this question
up vote 3 down vote accepted
  • Code-Style: Good
  • Functionality: no problem seen
  • Potential Bugs: only one I can see
  • Android-Expert-Level: I am not an android expert.
  • Android-Basic-Level: Everything looks sane

Bug (in jest):

People can play 1.9 seconds of angry birds, swap to a different app, and then swap back ;-)

Suggestions:

There is only one improvement I can suggest.

   private BroadcastReceiver screenReceiver = null;

This line is out-of-place. The only place it is used is in your registerScreenReceiver method. You may as well declare it in that method.

I would be tempted actually to pull the declaration out of the method and make it a final in-initialization anonymous instance:

 private final BroadcastReceiver screenReceiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                Log.i("ScreenReceiver", "Screen off");
                screenOn = false;
            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                Log.i("ScreenReceiver", "Screen on");
                listenForAppStarts();
                screenOn = true;            
            }
        }
    };
share|improve this answer
    
Thanks :) I'd like to see you playing 1.9 seconds of angry bird ;) – Manu Mar 22 '14 at 10:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.