7
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$
  • 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;            
            }
        }
    };
\$\endgroup\$
  • \$\begingroup\$ Thanks :) I'd like to see you playing 1.9 seconds of angry bird ;) \$\endgroup\$ – CommonGuy Mar 22 '14 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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