I am trying to "listen" when a user take picture using the default camera app. I used the broadcast receiver solution as below
Manifest:
<receiver
android:name=".CameraEventReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="com.android.camera.NEW_PICTURE" />
<action android:name="android.hardware.action.NEW_PICTURE" />
<data android:mimeType="image/*" />
</intent-filter>
</receiver>
The receiver:
public class CameraEventReceiver 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, Toast.LENGTH_SHORT).show();
Intent i = new Intent(context, MyAct.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
The problem is that the event is fired multiple times (twice). My breakpoint at where context.startActivity(i) is called twice and both with the action android.hardware.action.NEW_PICTURE.
Any reason why this is happening or how to prevent it?
Thank you
The stock Camera app on KitKat send both android.hardware.action.NEW_PICTURE and com.android.camera.NEW_PICTURE broadcasts (don't know for older versions), that may be why your receiver is notified twice.
If your app is only for ICS+ you can remove com.android.camera.NEW_PICTURE from your intent filter as it is not documented.
If you still want to handle this, your receiver should implement some logic to know the intent has already been handled for the data it receives. This logic depends on your application and what you do with the received data.
Related
Can anybody help me please? My question is that how to to display popup message on camera image capture using broadcast receiver.
I have register Receiver but it is not working.
Receiver class:
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,Toast.LENGTH_LONG).show();
}
}
Manifest file:
<receiver
android:name="com.example.abdullahnawaz.mycamera.CameraReciver"
android:enabled="true" >
<intent-filter>
<action android:name="com.android.camera.NEW_PICTURE" />
<data android:mimeType="image/*" />
<action android:name="android.intent.action.CAMERA_BUTTON" />
</intent-filter>
</receiver>
Starting from Android 7.0, please use JobInfo.Builder.addTriggerContentUri().
For older devices, you can listen to the ACTION_NEW_PICTURE or ACTION_NEW_VIDEO broadcast. These broadcasts are no long sent on 7.0 and above.
I am sending intent from "activity" to a receiver in "service" (and pass the data). My code has activity and service (that has reciever). Receiver is declared as follows
<receiver android:name="xxx"
android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<!-- protected intents meant for os and not for us <action android:name="android.intent.action.ACTION_NEW_OUTGOING_CALL" android:priority="0" /> -->
</intent-filter>
</receiver>
Activity is defined as follows
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I reviewed
Use an intent to send data to my activity
Intent I am invoking is the call intent and passing the destination call number, with the following code
Log.e(TAG,"Calling "+number);
Intent callIntent = new Intent(Intent.ACTION_CALL); //ACTION_NEW_OUTGOING_CALL is deprecated in API 21, hence ACTION_CALL
callIntent.putExtra("PHONE_NUMBER",number);
number = "tel:"+number;
callIntent.setData(Uri.parse(number));
startActivity(callIntent);
Above code successfully makes a telephone call from my app. I also have a receiver to intercept the calls and the reciever intercepts the above call just fine. However 'extras' of above intent is missing in the receiver; I always get "PHONE_NUMBER" as null in the following code
#Override
public void onReceive(Context context, Intent intent) {
//blah blah..
savedNumber = intent.getExtras().getString("PHONE_NUMBER");
if(savedNumber == null)
savedNumber = intent.getStringExtra("PHONE_NUMBER");
Log.e(TAG, " savedNumber = "+savedNumber);
}
What is my mistake and why is that I get the intent in the reciever but the 'extras' is missing (as you may have noticed, I tried to get it both ways from intent)
Try this:
Intent intent = context.getIntent();
savedNumber = intent.getStringExtra("PHONE_NUMBER");
getIntent() is method of Activity class. You can see in the onReceive() method has an intent argument, you get string from this.
String number = null;
number = intent.getStringExtra("PHONE_NUMBER");
But i read on this article: How to pass Extra to BroadcastReceiver, when initiating ACTION_CALL
Only the Android system itself can broadcast the NEW_OUTGOING_CALL Intent.
You can't add your own extras to this Intent. You'll need to come up with another way to do whatever it is you are trying to accomplish.
Start service like this-
Intent callIntent=new Intent(this, Service.class);
callIntent.putExtra("phonenumber",number);
this.startService(callIntent);
Then retrieve data from the service;
data=(String) intent.getExtras().get("phonenumber");
You can access your parameter from either the onHandleIntent or onStartCommand Intent parameter.
Service
protected void onStartCommand (Intent intent, int flags, int startId) {
data=(String) intent.getExtras().get("data");
}
IntentService
protected void onHandleIntent(Intent intent) {
data=(String) intent.getExtras().get("data");
}
It depends on which type of service you are running.
I have 2 applications. One of them is doing broadcast custom strings continously and the other one is receiving. I have to be notified and delete some datas in the reciever application when the broadcaster application is deleted. Is there a method like onDelete() or something like that? How can I do this?
Yeah! There's an intent called ACTION_PACKAGE_REMOVED that you can listen for.
Add this inside <application> in your manifest: (don't forget to change the package name)
<receiver android:name="com.arjnklc.receiverapp.UninstallReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package" />
</intent-filter>
</receiver>
Then you need to create the class mentioned above.
public class UninstallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getData().getSchemeSpecificPart() == "com.arjnklc.broadcasterapp")
cleanUpEverything();
}
}
Not exactly sure when you want to do but from what I understand, you want your second application to know when the first application is deleted?
If that's the case, do this:
In AndroidManifest.xml, you MUST have a new BroadcastReceiver because this receiver used a different data scheme:
<receiver
android:name=".PackageReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
Then your BroadcastReceiver:
public class PackageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
Log.d(TAG, "ACTION_PACKAGE_REMOVED");
String data = intent.getData().toString();
// data string has the package name
// if that is your package name, your first app was uninstalled
}
}
}
Just make sure, it's a separate BroadcastReceiver. It can not be combined with any other Receiver or the other actions will stop working.
Hope this works.
I am writing a Gallery like app.
I want to be notified when an image is copied to device via MTP.
I tried to register a broadcast receiver to listen for media scanner finished action, but it never got called. I tried to both register in AndroidManifest.xml or register in Java code, neither works.
<receiver android:name="com.robin.huangwei.omnigif.content.MediaScannerReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_SCANNER_FINISHED" />
<data android:scheme="file" />
</intent-filter>
</receiver>
public class MediaScannerReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("-----", "Scan finished, new item: " + intent);
}
}
or using JAVA code as below
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("-----", "Scan finished, new item: " + intent);
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_FINISHED);
filter.addDataScheme("file");
registerReceiver(mReceiver, filter);
None of the above works.
Whats wrong with my code? I can see every time a new image is copied, it could show in Gallery App. It might be using content observer to watch the media store database, which I don't want to.
I just want to be notified when a new image is added into the device storage via MTP. Since it is added into media store, which must be done by media scanner, why cannot my app capture the broadcast intent? If this is not even correct, I want to know the answer I post as the title.
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?
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
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
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.
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>
The issue is that, you've put the constant name with package into apostrophes (as string). The actual string constant has different value.