Kostadin
Kostadin

Reputation: 41

How to stop handler inside BroadcastReceiver after phone call is answered or canceled?

I'm trying to create simple Android application that simulate camera flashlight blink while phone call is received. If the user answer or cancel the call, I want to stop the flashlight blink. I'm using Handler and Runnable to simulate blinking, but the problem is that I can't stop the handler after user answer or cancel the call. My source code:

public class CallReceiver extends BroadcastReceiver 
{
    private static Camera cam = null;
    private Handler handler = new Handler();

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        //device is ringing
        if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING))
        {
            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) 
            {
                startFlashBlink();
            }
        }
        //call was answered or canceled
        else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE) 
            || intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
        {
            stopFlashBlink();
        }
    }

    //for simulating flash blink
    Runnable flashBlinkRunnable = new Runnable()
    {
        public void run() 
        {   
            cam = Camera.open();
            Parameters p = cam.getParameters();
            p.setFlashMode(Parameters.FLASH_MODE_TORCH);
            cam.setParameters(p);
            cam.startPreview();
            cam.stopPreview();
            cam.release();
            cam = null;
            handler.post(flashBlinkRunnable);
        }       
    };

    //start flash blink light
    public void startFlashBlink()
    {
        flashBlinkRunnable.run();
    }

    //stop flash blink light
    public void stopFlashBlink()
    {
        handler.removeCallbacks(flashBlinkRunnable);
        if (cam != null)
        {
            cam.stopPreview();
            cam.release();
            cam = null;
        }
    }
}

Upvotes: 0

Views: 1620

Answers (3)

Kostadin
Kostadin

Reputation: 41

The problem is solved with a Service.

public class FlashBlinkService extends Service 
{
    private static Camera cam = null;
    private Handler handler = new Handler();

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

    @Override
    public void onCreate()
    {
        super.onCreate();
        startFlashBlink();      
    }

    //for simulating flash blink
    Runnable flashBlinkRunnable = new Runnable()
    {
        public void run() 
        {   
            cam = Camera.open();
            Parameters p = cam.getParameters();
            p.setFlashMode(Parameters.FLASH_MODE_TORCH);
            cam.setParameters(p);
            cam.startPreview();
            cam.stopPreview();
            cam.release();
            cam = null;
            handler.post(flashBlinkRunnable);
        }       
    };

    //start flash blink light
    public void startFlashBlink()
    {
        flashBlinkRunnable.run();
    }

    //stop flash blink light
    public void stopFlashBlink()
    {
        handler.removeCallbacks(flashBlinkRunnable);
        stopCamera(cam);
    }

    //stop camera
    private void stopCamera(Camera cam)
    {
        if (cam != null)
        {
            cam.stopPreview();
            cam.release();
            cam = null;
        }
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        handler.removeCallbacks(flashBlinkRunnable);
        stopCamera(cam);
    }
}


public class CallReceiver extends BroadcastReceiver 
{
    @Override
    public void onReceive(Context context, Intent intent) 
    {
        //device is ringing
        if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING))
        {
            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) 
            {
                startFlashBlinkService(context);
            }
        }
        //call was answered or canceled
        else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE) 
                || intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
        {
            stopFlashBlinkService(context);
        }
    }

    //start flash blink light
    public void startFlashBlinkService(Context context)
    {
        if (!isBlinkServiceRunning(context))
        {
            Intent iService = new Intent(context, FlashBlinkService.class);
            context.startService(iService);
        }
    }

    //stop flash blink light
    public void stopFlashBlinkService(Context context)
    {
        if (isBlinkServiceRunning(context))
        {
            Intent iService = new Intent(context, FlashBlinkService.class);
            context.stopService(iService);
        }
    }


    //check if the blink service is running
    public boolean isBlinkServiceRunning(Context context)
    {
        ActivityManager manager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
        {
            if ("path.to.package.FlashBlinkService".equals(service.service.getClassName()))
            {
                return true;
            }
        }
        return false;
    }
}

(:

Upvotes: 0

WitaloBenicio
WitaloBenicio

Reputation: 3692

Broadcast receivers are a way to tell the OS that has a intention of to do something, than the OS find a app to resolve that intent. In your case, all of your code is in broadcast receiver. Try to create a service to resolve your problem instead try to resolve in your broadcast receiver.

Upvotes: 0

Tomik
Tomik

Reputation: 23977

It won't work like this. There is serious flaw in your code. The problem is that you can't use BroadcastReceiver this way. From the documentation of BroadcastReceiver:

A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.

Also note this from the app fundamentals in the docs:

More commonly, though, a broadcast receiver is just a "gateway" to other components and is intended to do a very minimal amount of work. For instance, it might initiate a service to perform some work based on the event.

So your broadcast receiver ought to start a service and tell it to start or stop flash blinking instead of doing it in the broadcast receiver itself.

Upvotes: 1

Related Questions