20

I'm trying to make an app that detects when a user takes a photo. I set up a broadcast receiver class and registered it in the manifest file by:

<receiver android:name="photoReceiver" >
  <intent-filter>
    <action android:name="com.android.camera.NEW_PICTURE"/>
      <data android:mimeType="image/*"/>
 </intent-filter>
</receiver>

No matter what I try to do the program won't receive the broadcast. Here is my receiver class:

public class photoReceiver extends BroadcastReceiver {
  private static final String TAG = "photoReceiver";

@Override
public void onReceive(Context context, Intent intent) {
    CharSequence text = "caught it";
    int duration = Toast.LENGTH_LONG;
    Log.d(TAG, "Received new photo");

    Toast toast = Toast.makeText(context, text, duration);
    toast.show();
 }
}

If I remove the mimeType line in the manifest and in my activity I send my own broadcast using

Intent intent = new Intent("com.android.camera.NEW_PICTURE");
sendBroadcast(intent);

then I successfully receive the broadcast and can see the log and toast window. Am I approaching this the right way? Is there any thing that I need to add?

Cœur
  • 37,241
  • 25
  • 195
  • 267
John
  • 361
  • 1
  • 2
  • 6
  • 1
    Where did you get `com.android.camera.NEW_PICTURE` from? From what I can tell after a quick look round the sdk, that action doesn't exist. – techi.services Dec 31 '10 at 19:35
  • @sugarynugs I found it on some other threads. Here is one of them, apparently its from the source of the camera. stackoverflow.com/questions/3015448/…, when a picture is taken it calls sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", mLastContentUri)); – John Jan 01 '11 at 08:18
  • what version of android are you testing this on? – techi.services Jan 01 '11 at 17:34
  • @sugarynugs I'm testing it right on my HTC Evo with Froyo(2.2). I also tested it on the emulator on 2.2 with no luck. I've been trying a lot of different things like registering the receiver programmatically and still no luck. Is there a different way that you know of that I can track when a picture was taken in the background? I want my app to stay in the background and listen for the event. The only other thing I can think of would be setting up a mediastore receiver and listening for images being saved from the camera, but that would be much more of a hastle! Thanks for the help so far! – John Jan 01 '11 at 21:21
  • @sugarynugs Also, I am wondering if HTC's Sense could somehow change the way the camera would broadcast, but even if this was the case it should be working on the emulator. Just a thought. – John Jan 01 '11 at 21:22
  • @John Trying to do the same thing. Just because the default camera app sends a broadcast when a picture is taken, it doesn't mean that other camera app will send one too. At least there's a convention to save photos to "/DCIM/100MEDIA" though watching this is also unreliable. – siamii Mar 06 '11 at 22:08
  • Just what are "sugarynugs" anyway? – gonzobrains May 25 '13 at 00:22
  • @siamii Is watching that directory unreliable because other directories can be used instead? What about using the Camera.ACTION_NEW_PICTURE intent? – gonzobrains May 25 '13 at 00:23

5 Answers5

16

I solved this but by using a different method. Instead of using a broadcast receiver I set up a fileobserver on separate folders that the camera saved to. It's not as practical as the other way, but it still works fine. Here's how I set it up:

FileObserver observer = new FileObserver(android.os.Environment.getExternalStorageDirectory().toString() + "/DCIM/100MEDIA") { // set up a file observer to watch this directory on sd card
            @Override
        public void onEvent(int event, String file) {
            if(event == FileObserver.CREATE && !file.equals(".probe")){ // check if its a "create" and not equal to .probe because thats created every time camera is launched
                Log.d(TAG, "File created [" + android.os.Environment.getExternalStorageDirectory().toString() + "/DCIM/100MEDIA/" + file + "]");
                fileSaved = "New photo Saved: " + file;
            }
        }
    };
    observer.startWatching(); // start the observer
John
  • 361
  • 1
  • 2
  • 6
  • 1
    nice! good to see someone who can think for themselves ;D. I was looking at the camera source and a method `storeImage` in the `ImageCapture` class is responsible for firing of that intent. That method only fires the intent if `!mIsImageCaptureIntent`. I didn't look further but I would have thought that means, do the following if the image capture did not occur due to an intent. Not sure how you are taking a picture and whether the camera app uses an intent to take a picture but food for thought. – techi.services Jan 04 '11 at 16:03
  • 10
    The problem with this solution is that the app **must be running in the background all the time** in order to observe the filesystem. Major problem and not playing nice. – AlikElzin-kilaka Jul 16 '12 at 08:30
  • 3
    Can you use this solution to monitor multiple folders or must you create a separate FileObserver for each folder you wish to observe? – gonzobrains May 27 '13 at 21:04
  • You have to create an observer for every folder you want to monitor. – Ruzard Jun 09 '13 at 19:11
  • 1
    2 years late to the party, but I tried the solution given by Tanay below and it actually works on image capture! Any objections to why I shouldn't use it? – Snake Dec 02 '13 at 04:52
11

I sure this way works 100% . I tested carefully.

Register your broadcast receiver in AndroidManifest. Most of answers above miss "category android:name="android.intent.category.DEFAULT" . BroadcastReceiver can't start without this

  <receiver
    android:name=".CameraReciver"
    android:enabled="true" >
        <intent-filter>
            <action android:name="com.android.camera.NEW_PICTURE" />
            <action android:name="android.hardware.action.NEW_PICTURE" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="image/*" />

        </intent-filter>
    </receiver>

And finally, you create a class named "CameraReciver.java" extend from BroadcastReceiver and this my code :

public class CameraReciver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Log.i("INFO", "Enter BroadcastReceiver");



Cursor cursor = context.getContentResolver().query(intent.getData(),
                null, null, null, null);
        cursor.moveToFirst();
        String image_path = cursor.getString(cursor.getColumnIndex("_data"));
        Toast.makeText(context, "New Photo is Saved as : " + image_path, 1000)
                .show();



}

After that, deploy your project to Emulator ( I use genymotion),of course nothing happened because your BroadCastReceiver works without GUI. Let you open camera app, and click capture button. If everything OK, you'll get a toast with content like "New Photo is Saved as : storage/emulated/0/DCIM/Camera/IMG_20140308.jpg". Let enjoy ^_^

Thanks "tanay khandelwal" (answered above) for how to get the path of new Photo captured by camera ^_^

Hope to help everyone

VO DUC HUY
  • 176
  • 1
  • 6
  • I tried it, but it didn't helped me. I also asked the question about this. Here is my work. http://stackoverflow.com/questions/24989221/how-to-get-camera-click-event-with-the-help-of-broadcast-receiver – Amit Jayaswal Jul 28 '14 at 08:20
  • Above code works perfect for photos captured, any idea how we can get receiver for videos captured? – Shrikant Nov 03 '15 at 07:14
  • I am using camera in my app. will I get toast if the user has taken the picture( and has been taken to Save/Discard screen)? – Harshit Gupta May 06 '16 at 15:54
  • 2
    From android 7.0, this has stopped working :( . Is there any workaround?? – Ujjwal May 16 '17 at 12:13
9

you should check out here: ImageTableObserver and here PicasaPhotoUploader how they do it.

Basically, they have an observer for Media.EXTERNAL_CONTENT_URI that will notify of whatever happens on the SD card, then in the Observer, they check if the data returned is a photo.

camera = new ImageTableObserver(new Handler(), this, queue);
getContentResolver().registerContentObserver(Media.EXTERNAL_CONTENT_URI, true, camera);

At least this way you don't have to hardcode the directory.

AZ_
  • 21,688
  • 25
  • 143
  • 191
Mortimer
  • 2,966
  • 23
  • 24
7

Hello friends I was also trying to implement some task on capture event and after studying and working on it I prepared this code which is working fine so it may help you

first create a receiver for your event say CameraEventReciver and in that you can implement your code I m also giving you the path of the new image so it will be more useful to you for your code

    public class CameraEventReciver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

    Cursor cursor = context.getContentResolver().query(intent.getData(),      null,null, null, null);
    cursor.moveToFirst();
    String image_path = cursor.getString(cursor.getColumnIndex("_data"));
    Toast.makeText(context, "New Photo is Saved as : -" + image_path, 1000).show();
      }
    }

And in Android Manifest you just have to take some permissions and register your reciever with intent filter and appropriate action for image capture also make your receiver android enabled

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

   <receiver
        android:name="com.android.application.CameraEventReciver"
        android:enabled="true" >
        <intent-filter>
            <action android:name="com.android.camera.NEW_PICTURE" />
            <data android:mimeType="image/*" />
        </intent-filter>
    </receiver>
  • I tried it, but not working for me ... Here is my question which I asked, please help me. http://stackoverflow.com/questions/24989221/how-to-get-camera-click-event-with-the-help-of-broadcast-receiver – Amit Jayaswal Jul 28 '14 at 08:21
0

The issue is that, you've put the constant name with package into apostrophes (as string). The actual string constant has different value.

ViliusK
  • 11,345
  • 4
  • 67
  • 71