I'm starting learning android development, so my knowledge is really limited at the moment.
I'm trying playing with broadcasts, but I'm stuck and I can't understand what I'm doing wrong.
What I'm trying to do it's just show a simple Toast from the broadcast receiver.
The Intent is a custom intent defined in the manifest:
<receiver android:name=".receiver.SendReceiver" android:enabled="true">
<intent-filter>
<action android:name="com.android.terralink.sem.SOCCIA"></action>
</intent-filter>
</receiver>
The receiver is defined like this:
public class SearchReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "asasa", Toast.LENGTH_SHORT).show();
}
}
In the first action called from the application I do this:
Intent i2 = new Intent(this, SearchReceiver.class);
i2.setAction(CUSTOM_INTENT);
sendBroadcast(i2);
I checked that the Toast code works in the Activity, but not in the broadcast.
It is because the Toast can't be shown in the receiver context?
Also, another question more about android application structure.
If from my Activty I allow the user to insert a string in a text box and submit (button bind), and I want the application do a search in the background and notify the user once the result is ready, is correct do the following?
1) Main Activity with search box
2) Start a Service that fetches the data, send a broadcast
3) The receiver notofy the user and open an Activity that shows the result
Does it make sense do something like that?
Or the notification should be done by the service itself before finish its job?
Thanks
I found out that the problem was in the manifest, when I registered the receiver.
Actually it is possible to show a Toast in the receiver without any issue.
Cheers
You cannot show a Toast in a broadcast receiver.
Android will usually shut down your process once the onReceive() call has finished (for which it only allowed to take max. 10 seconds currently). Since a toast is shown asynchronously, I think its context is killed before it is even displayed.
As an alternative to Toast, you can take a look at the concept of RemoveViews for updating UI in another process from a receiver. Or, launch an activity that shows a toast and closes immediately.
For your question #2, I suggest that you keep the activity running after the search button is clicked and start an AsyncTask for the search, which updates the search results as they come in.
To show toast from a broadcast receiver we can use the following code:
public class ServiceReceiver extends BroadcastReceiver {
Context context;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
MyPhoneStateListener phoneListener = new MyPhoneStateListener();
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
private class MyPhoneStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(context, "Idle call", Toast.LENGTH_LONG).show();
Log.d("***************************DEBUG", "IDLE");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d("***************************DEBUG", "OFFHOOK");
break;
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(context, "Ringing call", Toast.LENGTH_LONG)
.show();
Log.d("***************************DEBUG", "RINGING");
break;
}
}
}
}
Related
I'm very new to mobile development and to Xamarin.
I created a new Xamarin.Forms solution "AndroidApp1" which by default consists of two projects, "AndroidApp1.Android" and "AndroidApp1".
If I understood correctly what I read, the first one contains the code specific to Android and the second one contains the code that can be used in Android, iOS or Windows Phone.
My solution runs in an Android emulation in debug mode, now I'd like to be notified when there's an incoming call, I'd like to get the telephone number that is calling me.
Google told me, that I need to create a class that inherits from BroadcastReceiver and override the OnReceive function.
I assume that this class needs to reside in the Android specific project (AndroidApp1.Android), so I created the class here, but now what?
I can't find any information about what to do with this class? Where do I instantiate it? How do I get the notification and the phone number to react on in my "AndroidApp1" project?
Here's the source code of my BroadcastReceiver (copied from the internet):
[BroadcastReceiver(Enabled = true, Exported = false)]
[IntentFilter(new[] { "android.intent.action.PHONE_STATE" })]
public class IncomingCallReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// ensure there is information
if (intent.Extras != null)
{
// get the incoming call state
string state = intent.GetStringExtra(TelephonyManager.ExtraState);
// check the current state
if (state == TelephonyManager.ExtraStateRinging)
{
// read the incoming call telephone number...
string telephone = intent.GetStringExtra(TelephonyManager.ExtraIncomingNumber);
// check the reade telephone
if (string.IsNullOrEmpty(telephone))
telephone = string.Empty;
}
else if (state == TelephonyManager.ExtraStateOffhook)
{
// incoming call answer
}
else if (state == TelephonyManager.ExtraStateIdle)
{
// incoming call end
}
}
}
}
You need to register brodcast receiver for the call state.
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
and create a notification once your get broadcast events.
Make sure you have defined permission.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
You need to have a Broadcast Receiver something like this.
/**
* Listener to detect incoming calls.
*/
private class CallStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// called when someone is ringing to this phone
Toast.makeText(ctx, "Incoming: "+incomingNumber,
Toast.LENGTH_LONG).show();
break;
}
}
You can register the lister for incoming call events.
tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
Here is the more info
https://stackoverflow.com/questions/9684866/how-to-detect-when-phone-is-answered-or-rejected
Finally I am one step forward. I created a class StateListener that inherits from PhoneStateListener in the Android specific project like this:
public class StateListener : PhoneStateListener
{
public override void OnCallStateChanged(CallState state, string incomingNumber)
{
base.OnCallStateChanged(state, incomingNumber);
switch (state)
{
case CallState.Ringing:
break;
case CallState.Offhook:
break;
case CallState.Idle:
break;
}
}
}
Then I instantiated this class in the OnCreate function of the MainActivity class of the Android specific project with these three lines of code:
StateListener phoneStateListener = new StateListener();
TelephonyManager telephonyManager = (TelephonyManager)GetSystemService(Context.TelephonyService);
telephonyManager.Listen(phoneStateListener, PhoneStateListenerFlags.CallState);
Now when I set break points in the case parts of the switch (state) in OnCallStateChanged they break, but the incomingNumber is always empty, although I've set the corresponding rights in the manifest.
So, that will be my next step, to get the calling number.
I have "ComposeActivity" which calls the "SendSMS" method after onClick, which than calls metod in SMS class. I had also registered two BroadcastReceiver: SmsDeliveredReceiver and SmsSentReceiver, similar to: https://stackoverflow.com/a/17164931/1888738. How can I inform ComposeActivity, that sms was succesfullly sent, and that activity can clean some EditText's, and maybe show crouton with information that sms was sent or not(and why)? My codes: http://pastebin.com/LNRuSeBu
If you have receivers to handle when the SMS messages are sent or not sent. You could modify the onReceive of both of the receivers to send and intent to the ComposeActivity by creating an intent and calling intent.setComponent to specify where the intent should go. with some data that tells the ComposeActivity the result of trying to send the message.
Update:
public void onReceive(Context context, Intent arg1) {
Intent i = new Intent(action);
i.setComponent(new ComponentName("com.mypackage.compose","ComposeActivity"));
switch (getResultCode()) {
case Activity.RESULT_OK:
Log.d(getClass().getSimpleName(), "SMS delivered");
intent.setAction("com.mypackage.compose.SMS_SENT"); // String you define to match the intent-filter of ComposeActivity.
break;
case Activity.RESULT_CANCELED:
Log.d(getClass().getSimpleName(), "SMS not delivered");
intent.setAction("com.mypackage.compose.SMS_FAILED"); // String you define to match the intent-filter of ComposeActivity.
break;
}
startActivity(intent); // you may not necessarily have to call startActivity but call whatever method you need to to deliver the intent.
}
At that point it should just be matter of addind an intent-filter and a receiver to your compose activity either via the manifest or programatically. Your call. The strings I used were made up but you could pick an exiting intent action string or declare strings that you use in the intent filter. Again up to you. May also be helpful to look at questions about sending explicit intents to components like Android explicit intent with target component
or looking at the android docs.
Ok, after 5 hours of trying, I've already solved this:
in BroadcastReceiver in onReceive:
Intent intent = new Intent();
intent.setAction("SOMEACTION");
context.sendBroadcast(intent);
in Activity:
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("SOMEACTION")) {
Log.d(TAG, "Sent");
}
}
};
and in onCreate Activity I registered BroadcastReceiver:
registerReceiver(receiver, new IntentFilter("SOMEACTION"));
Thats all...
I want to listen incoming calls and outgoing calls and this process should run as service.I made a activity which is working fine to recognize incoming and outgoing calls but I need to change it to service so that it can run into background.I can't find out how to change it.My activity follows:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager mTelephonyMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyMgr.listen(new TeleListener(), PhoneStateListener.LISTEN_CALL_STATE);
}
class TeleListener extends PhoneStateListener
{
public void onCallStateChanged(int state, String incomingNumber)
{
super.onCallStateChanged(state, incomingNumber);
switch (state)
{
case TelephonyManager.CALL_STATE_IDLE:
//CALL_STATE_IDLE;
Toast.makeText(getApplicationContext(), "CALL_STATE_IDLE", 10000).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//CALL_STATE_OFFHOOK;
Toast.makeText(getApplicationContext(), "CALL_STATE_OFFHOOK", 10000).show();
break;
case TelephonyManager.CALL_STATE_RINGING:
//CALL_STATE_RINGING
Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING", 10000).show();
break;
default:
break;
}
}
}
}
And my Second question can I install a service without an activity into my phone.
Just extends Service instead of Activity. You do need an activity to start a service. You can start your service at boot by register a ACTION_BOOT_COMPLETED and have your broadcast receiver start your service. However, from ICS upward you need an activity to launch your service at least once. After that the activity will never be needed again.
You need to pass an intent to start a service. You can create an activity that only starts your service, and this activity does not have a view.
Make your class extend Service rather than Activity, and create another activity that instantiates your service and executes startService(yourserviceInstance);
I am developing an application which has a countdown timer. I want to pause that timer only if there is an incoming call on the phone. Is there any way to fire an event whenever we receive a call?
I think you should extends PhoneStateListener class.In that class you handle the phone state.For that use the permission in the manifest file for handling phone state (i.e. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">).
And use TelephonyManager to get the status of phone.
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
manager.listen(this, LISTEN_CALL_STATE); // Registers a listener object to receive notification of changes in specified telephony states.
And override this method.
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
// Here you can perform your task while phone is ringing.
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
}
When a Phone-Call is received OS fires a Message, technically called Broadcast.
Any Application can view/Respond to this message via Registering for PhoneIntentReceiver,
if more than one Application installed has registered for this, then all of them are given a chance to view this message based on Priority.
You can register for PhoneIntentReceiver via Manifest or Programatically. In both case you specify a Class that extends broadcast receiver in your project, that will receive a callback on detecting an Incoming call.
Then in this class the control is passed on to onReceive method. Its here that you can Stop your Timmer.
This is the story behind it.Happy Coding.
You have to write the Broadcast receiver which listens for incoming call
see this link for more info...
you have to use broadcast receiver for that........
First of all register your receiver in manifest.xml
<receiver android:name="com.cygnet.phonefinder.receiver.PhoneIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
then you have to handle that reciever in
public class PhoneIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) { } }
I would say the best implementation would be to utilize time stamps, timers (java.util.Timer or android.app.AlarmManager), and then listen for phone events using a broadcast receiver.
Basically every time you need to start an alarm for a certain period of time store a timestamp for the start of that alarm(probably easiest in an sql db) and then start the timer/alarm. When an alarm goes off make sure to clean up your stored timestamps.
Make sure to listen to phone state changes and on a phone call answered change clear all your alarms/timers and record the stop dates along with the previous timestamps and then when the phone call ends (from your reciever event) restart the timers/alarms for the remaining time.
In your Broadcastreceiver onReceive() write following code
Don't forget to give appropriate permission
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
MyCallStateListener customPhoneListener = new MyCallStateListener();
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
if (!intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
return;
public class MyCallStateListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
}
}
}
public class OutgoingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "My Toast", Toast.LENGTH_LONG).show();
}
}
Try This receiver to fire an event
I have an activity for display new sms and SmsReceiver (extends BroadcastReceiver) to receive incoming sms. After receive sms, what is the best practice to update the UI?
Well if you have your own activity it is obious that you want you activity to be shown after the user receive a sms. Then in your receiver , onReceive method you can do this
startActivity(new Intent(context,MyActivity.class));
and the activity is presented to the user...
If you want to put additional info you can use putExtra("key","value") (it is method from the intent)
you can use like
Intent i=new Intent():
i.putExtra("key","value");
startActivity(context,i);
then in the activity onCreate method you can get this info by
String value = intent.getStringExtra("key");
and like this you can implement your business logic
Edit
when the activity is already running you can use
android:launchMode=["multiple" | "singleTop" |
"singleTask" | "singleInstance"]
I think singleInstance and singleTask will keep only one instance of your activity
Since you're using BroadcastReceiver there is no reason to use startActivity() as Lukap suggests. Simply use the receiver to actually receive messages.
When the SMS have arrived and you want to update the UI, do something like this:
Intent intent = new Intent(SOME_FANCY_NAME);
String msg = String.format("%d new SMS(s)!", numNewSMS);
intent.putExtra(SOME_FANCY_NAME_EXTRA, msg);
sendBroadcast(intent);
Then, in your activity:
class MyMessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(SOME_FANCY_NAME)) {
// Here goes your UI-updates
String msg = intent.getStringExtra(SOME_FANCY_NAME_EXTRA);
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
}