I have an app in android in which I wanna take a photo when physical hardware button for camera gets pressed.I registered an intent for this type of action but my broadcast receiver never gets called.
Here is how I did it:
class that extends BroadcastReceiver
public class Adisor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) != null) {
// prevent the camera app from opening
abortBroadcast();
System.out.println("HEY");
mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}
}
}
Here is where I register my receiver to listen for actions:
protected void onResume() {
Log.e(TAG, "onResume");
super.onResume();
drb = new Adisor();
IntentFilter i = new IntentFilter(
"android.intent.action.CAMERA_BUTTON"
);
registerReceiver(drb, i);
}
And in my manifest file I have this:
<activity android:name=".TakePhoto" />
<receiver android:name=".Adisor" >
<intent-filter android:priority="10000">
<action android:name="android.intent.action.CAMERA_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
The name of the activity in which I'm doing all this is:TakePhoto.My question is why my onReceive() method never gets called!
Neither this:
System.out.println("HEY");
appears in my logcat or the method
System.out.println("HEY");
mCamera.takePicture(null, mPictureCallbacmPictureCallback);
gets called!
What I'm doing wrong?
You should either have the receiver registered in the manifest or register programmatically. Remove the registerReceiver() call from the onResume method.
Edit:
Add these to your manifest.
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
Your intent filter should never have a priority of 10000. The maximum allowed for user applications is 999.
See setPriority(int) on the AndroidDev website.
For opening the only the camera of your application you can use intent like:
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, ACTION_IMAGE_CAPTURE);
Related
To put it simply; BroadcastReceiver Works when defined in Manifest but it works with a short Delay and it doesn't Always trigger unless Registered Manually.
Here is the BroadcastReceiver I created to capture event when date changes (day is passed):
public class BootBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, intent.getAction(), Toast.LENGTH_LONG).show();
switch (intent.getAction()){
case Intent.ACTION_TIME_TICK:
case Intent.ACTION_TIME_CHANGED:
case Intent.ACTION_TIMEZONE_CHANGED:
case Intent.ACTION_DATE_CHANGED:
case Intent.ACTION_BOOT_COMPLETED:
Log.d("BroadcastReceiver", intent.getAction().toString());
}
}
}
Here registered in Manifest, It works but has a short delay and also doesn't always trigger:
<receiver android:name=".Receivers.BootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.TIME_TICK" />
<action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.DATE_CHANGED"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
But when registered manually via my background service it works just fine:
public class ApplicationService extends Service{
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_DATE_CHANGED);
intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
intentFilter.addAction(Intent.ACTION_TIME_TICK);
registerReceiver(new BootBroadcastReceiver(), intentFilter);
return START_STICKY;
}
}
To investigate this issue further I created two similar app which in one BroadcastReceiver registered in Manifest and in the other one receiver is registered Manually via Service.
In the Manifest one all events are triggered few second after Manual one..
Try this :
<receiver android:name=".Receivers.BootBroadcastReceiver">
<intent-filter
android:enabled="true"
android:exported="true">
<action android:name="android.intent.action.TIME_TICK" />
<action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.DATE_CHANGED"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
I guess you can have multiple each one having its action.
https://developer.android.com/guide/components/intents-filters.html
The documentation says that "An app component should declare separate filters for each unique job it can do." This would allow finer grained detail for different actions
The answer was hidden in Intent documentation:
ACTION_TIME_TICK Added in API level 1
public static final String ACTION_TIME_TICK
Broadcast Action: The current time has changed. Sent every minute. You
cannot receive this through components declared in manifests, only by
explicitly registering for it with
Context#registerReceiver(BroadcastReceiver, IntentFilter).
To simply put, you can't receive TIME_TICK through registering the BroadcastReceiver in manifest, it has to be registered in your application components (Service, Activity, etc.)
Define a BootBroadcastReceiver anywhere in Activity/Fragment like this:
mBootBroadcastReceiver = new BootBroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG," BootBroadcastReceiver"); //do something with intent
}
};
mIntentFilter=new IntentFilter("action_name");
Now register the BootBroadcastReceiver in onResume() and Unregister in onPause()
#Override
protected void onResume() {
super.onResume();
registerReceiver(mBootBroadcastReceiver, mIntentFilter);
}
#Override
protected void onPause() {
if(mReceiver != null) {
unregisterReceiver(mBootBroadcastReceiver);
mBootBroadcastReceiver = null;
}
super.onPause();
}
add permission in your Manifest.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="ANDROID.PERMISSION.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
http://developer.android.com/reference/android/provider/VoicemailContract.html
i don't know how to make a brocast receiver with VOICEMAIL. When you receive a voicemail,you will see "NEW VOICEMAIL" in notification,the icon just like a tape.
here is my code:
AndroidManifest.xml
<receiver android:name=".VoiceBrocast" >
<intent-filter>
<action android:name="android.intent.action.NEW_VOICEMAIL" />
</intent-filter>
</receiver>
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
i tried to register in xx.java,but it's no works.
MainActivity.java:
protected VoiceBrocast mUiBroadcastReceiver;
mUiBroadcastReceiver = new VoiceBrocast();
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction("android.intent.action.ACTION_NEW_VOICEMAIL");
MainActivity.this.registerReceiver(mUiBroadcastReceiver, mIntentFilter);
VoiceBrocast.Java
public class VoiceBrocast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
System.out.println("voicemail");
}
}
when i received a voicemail, nothing to print, i can't see "voicemail" in LogCat.
Not sure that else is wrong, but one problem is: the intent action is not called "android.intent.action.ACTION_NEW_VOICEMAIL" but "android.intent.action.NEW_VOICEMAIL".
Perhaps you mixed it up with the constant name on the VoicemailContract class which is VoicemailContract.ACTION_NEW_VOICEMAIL.
The minimum permission needed to access this content provider is ADD_VOICEMAIL
Do you have such permission ?
I have an app in which I'm trying to register a BroadcastReceiver that listens for intent of this type: android.intent.action.CAMERA_BUTTON but the problem is that my onReceive() method never gets called!
This is how I did:
in onCreate() I've also tried to register this in onResume() but with the same result:
drb=new Adisor();
IntentFilter intent=new IntentFilter("android.intent.action.CAMERA_BUTTON");
registerReceiver(drb,intent);
and my class Adisor:
public class Adisor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("Bau");
if (intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) != null) {
// prevent the camera app from opening
abortBroadcast();
System.out.println("HEY");
// mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}
}
}
And I have the following permissions in the manifest file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera" />
But when I press the camera button no message is displayed in the logcat!Any idea why?
EDIT: I also tried registering my intent in manifest file
<activity android:name=".TakePhoto"
>
<receiver android:name="com.Contest.Adisor"
android:enabled="true" android:exported="true">
<intent-filter android:priority="10000">
<action android:name="android.intent.action.CAMERA_BUTTON" />
</intent-filter>
</receiver>
Adisor is an inner class of `TakePhoto`.
Try like this.
IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_CAMERA_BUTTON);
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
registerReceiver(drb, intentFilter);
Edited code.
Replace the following code portion.
public class Adisor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("Bau");
if (intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) != null) {
// prevent the camera app from opening
abortBroadcast();
System.out.println("HEY");
// mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}
}
}
with this.
private final BroadcastReceiver drb = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("Bau");
if (intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) != null) {
// prevent the camera app from opening
abortBroadcast();
System.out.println("HEY");
// mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}
}
};
Are you pressing hardware camera button or software button? It is called only when the hardware camera button is pressed, not with the button in the camera application.
EDIT
Also, just found this:
android.intent.action.CAMERA_BUTTON not broadcasting on Desire Z (Froyo)?
There is no requirement for a device manufacturer to send any
broadcast when the CAMERA button is clicked, from my reading of the
Compatibility Definition Document. It might only be used by the
foreground activity on the Desire Z. I don't have a Z and so cannot
confirm your tests.
Since the vast majority of Android devices do not have a CAMERA button
at all, you will need to ensure that your app works well without such
a button, and that you advise users that the CAMERA button may or may
not work with your app depending upon device.
You have to change following changes in your manifest
<activity android:name=".TakePhoto">
<receiver android:name="com.Contest.TakePhoto$Adisor"
android:enabled="true" android:exported="true">
<intent-filter android:priority="10000">
<action android:name="android.intent.action.CAMERA_BUTTON" />
</intent-filter>
</receiver>
Because you had declare broadcast receiver inside your activity TakePhoto
I saw many posts in StackOverflow regarding how to listen to camera events, and got few information but still there are few questions remain in my mind please let me know the answers for these:
I have an application which have a broadcast receiver and my broadcast receiver will lauch my activity, but the main purpose of having broadcast receiver is to listen to camera photo/video capture intent.
I want to know which is the intent i have to listen for this, and is it possible to do in this way.
thanks
For Receiving camera photo capture intent, try following code
public class CameraEventReciver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "New Photo Clicked", Toast.LENGTH_LONG).show();
}
and in manifest, register the receiver:-
<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>
In your Android Manifest, you need to specify which intents you want to receive. For camera that'd be the following code (this goes within the <application> tags):
<receiver android:name="com.receiver.CameraReceiver">
<intent-filter android:priority="10000">
<action android:name="android.intent.action.CAMERA_BUTTON" />
</intent-filter>
</receiver>
In addition to that, you should add this to your <intent-filter> within the <activity> tags:
<category android:name="android.intent.category.DEFAULT" />
Finally, take care of the event in your activity's code like so:
#Override
public void onReceive(Context context, Intent intent) {
abortBroadcast();
//TODO: your code here
}
You can use thread that will control your directory camera like:
FileObserver observer =new FileObserver("/mnt/extSd/DCIM/Camera/"){
#Override
public void onEvent(int event, String file) {
// TODO Auto-generated method stub
if(event == FileObserver.CREATE ){
//Do Some things With The file
}
}};
} catch (FileNotFoundException e) {
e.printStackTrace();
}
observer.startWatching();
I'm just trying this little sample project, all it does:
Activity one has a Button that sends a Broadcast. Activity two displays a toast when received.
Below is the code, the Broadcast is never received. What do I do wrong?
Sending the Broadcast
public class SendBroadcast extends Activity {
public static String BROADCAST_ACTION = "com.unitedcoders.android.broadcasttest.SHOWTOAST";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void sendBroadcast(View v){
Intent broadcast = new Intent();
broadcast.setAction(BROADCAST_ACTION);
sendBroadcast(broadcast);
}
}
Receiving it
public class ToastDisplay extends Activity {
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
}
};
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction(SendBroadcast.BROADCAST_ACTION);
registerReceiver(receiver, filter);
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(receiver);
super.onPause();
}
}
Manifest
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".SendBroadcast" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ToastDisplay">
<intent-filter>
<action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"></action>
</intent-filter>
</activity>
</application>
What do I do wrong?
The source code of ToastDisplay is OK (mine is similar and works), but it will only receive something, if it is currently in foreground (you register receiver in onResume). But it can not receive anything if a different activity (in this case SendBroadcast activity) is shown.
Instead you probably want to startActivity ToastDisplay from the first activity?
BroadcastReceiver and Activity make sense in a different use case. In my application I need to receive notifications from a background GPS tracking service and show them in the activity (if the activity is in the foreground).
There is no need to register the receiver in the manifest. It would be even harmful in my use case - my receiver manipulates the UI of the activity and the UI would not be available during onReceive if the activity is not currently shown. Instead I register and unregister the receiver for activity in onResume and onPause as described in
BroadcastReceiver documentation:
You can either dynamically register an instance of this class with Context.registerReceiver() or statically publish an implementation through the tag in your AndroidManifest.xml.
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
makes the toast, but doesnt show it.
You have to do Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT).show();
Extends the ToastDisplay class with BroadcastReceiver and register the receiver in the manifest file,and dont register your broadcast receiver in onResume() .
<application
....
<receiver android:name=".ToastDisplay">
<intent-filter>
<action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"/>
</intent-filter>
</receiver>
</application>
if you want to register in activity then register in the onCreate() method e.g:
onCreate(){
sentSmsBroadcastCome = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "SMS SENT!!", Toast.LENGTH_SHORT).show();
}
};
IntentFilter filterSend = new IntentFilter();
filterSend.addAction("m.sent");
registerReceiver(sentSmsBroadcastCome, filterSend);
}
You need to define the receiver as a class in the manifest and it will receive the intent:
<application
....
<receiver android:name=".ToastReceiver">
<intent-filter>
<action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"/>
</intent-filter>
</receiver>
</application>
And you don't need to create the class manually inside ToastDisplay.
In the code you provided, you must be inside ToastDisplay activity to actually receive the Intent.
I think your problem is that you send the broadcast before the other activity start ! so the other activity will not receive anything .
The best practice to test your code is to sendbroadcast from thread or from a service so the activity is opened and its registered the receiver and the background process sends a message.
start the ToastDisplay activity from the sender activity ( I didn't test that but it may work probably )
You forget to write .show() at the end, which is used to show the toast message.
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT).show();
It is a common mistake that programmer does, but i am sure after this you won't repeat the mistake again... :D
Your also have to register the receiver in onCreate(), like this:
IntentFilter filter = new IntentFilter();
filter.addAction("csinald.meg");
registerReceiver(receiver, filter);