I am trying to make my broadcast receiver fire when the phone goes in and out of reception areas. The issue is the receiver never gets called when the cell reception changes. The BroadcastReceiver works fine for getting phone call states (call idle, started ect...), and also for getting the airplane mode switched on and off because the broadcast receiver handles both.
I added the permissions and intent filter to the receiver in the manifest and they are working fine.
Here is what I have for my BroadcastReceiver and PhoneStateListener.
public class PhoneStateReceiver extends BroadcastReceiver {
private PhoneStateListener mListener = new ServiceStateListener();
private TelephonyManager mTelephonyManager;
private Context mContext;
/**
* TODO add some sort of call back interface to allow for different uses of this phone state receiver
*/
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
mContext = context;
if (action.intern().equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
if (!isAirplaneModeOn) {
SmsRetryManager.getInstance().retryAllSms(context);
}
} else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
mTelephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Toast.makeText(mContext, "Receiver registered!", Toast.LENGTH_LONG).show();
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
}
public void onDestroy() {
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
}
private class ServiceStateListener extends PhoneStateListener {
#Override
public void onServiceStateChanged (ServiceState serviceState) {
super.onServiceStateChanged(serviceState);
boolean connected = (serviceState.getState() == ServiceState.STATE_IN_SERVICE);
if (connected) {
Toast.makeText(mContext, "Connection Gained!", Toast.LENGTH_LONG).show();
//todo retry sms here
SmsRetryManager.getInstance().retryAllSms(mContext);
} else {
Toast.makeText(mContext, "Connection Lost!", Toast.LENGTH_LONG).show();
}
}
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
super.onSignalStrengthsChanged(signalStrength);
Toast.makeText(mContext, "Signal changed - cdma : " + signalStrength.getCdmaDbm() + " gsm : " + signalStrength.getGsmSignalStrength(), Toast.LENGTH_LONG).show();
}
}
Any insight would be awesome. I have been banging my head on this one for a while.
Thanks!
I assume you are listening the broadcast android.intent.action.SERVICE_STATE
If so, try using:
if (TelephonyManager.getnetworkOperator.length()==0) connected=false;
on your OnReceive method, to know if the phone is not connected. It works fine for me.
If this solution doesn't work, please show how you register the receiver: is it statically registered at manifest.xml? or dynamically with PackageManager.setComponentEnabledSetting? Note: With static registration you'll find the receiver is not triggered after reinstalling the app, needing to add to the receiver tag
<intent-filter>
<action android:name= "android.intent.action.MY_PACKAGE_REPLACED"/></intent-filter>
You can also look at the values that return the ServiceState.
See here http://developer.android.com/reference/android/telephony/ServiceState.html
And check which of these values is returned:
int STATE_EMERGENCY_ONLY = The phone is registered and locked. Only
emergency numbers are allowed.
int STATE_IN_SERVICE = Normal operation condition, the phone is registered with an operator either in home network or in roaming.
int STATE_OUT_OF_SERVICE = Phone is not registered with any operator,
the phone can be currently searching a new operator to register to, or
not searching to registration at all, or registration is denied, or
radio signal is not available.
int STATE_POWER_OFF = Radio of telephony is explicitly powered off.
Related
Is there a way to get notified when the user mutes the incoming call ring signal by pressing the volume button and/or turn to silence?
I have tried all methods I can find, using AudioManager.RINGER_MODE_CHANGE_ACTION, android.media.VOLUME_CHANGE_ACTION, android.media.MASTER_MUTE_CHANGED_ACTION and a few more...
None of them give a clear indication that the ring signal is muted.
My problem is not solved by the "possible duplicate", so I will expand with parts of my code for more help.
In my service:
#Override
public void onCreate() {
super.onCreate();
mVolumeReceiver = new VolumeReceiver();
IntentFilter intentFilter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(mVolumeReceiver, intentFilter);
}
private class VolumeReceiver extends BroadcastReceiver {
private final String TAG = VolumeReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
final String[] Modes = { "Unknown", "Silent", "Vibrate", "Normal" };
if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
int newMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
Log.i(TAG, "Ringer mode changed to: " + Modes[newMode + 1]);
}
}
}
I am certain that my service is started, since it's doing other things as it should.
I also tried to register a BroadcastReceiver class in my manifest, but that didn't work either.
I do get one Logcat entry telling me mode is changed to "Normal", probably when the receiver is registered. After that, nothing.
I have written the following code for detecting the network status from within the BroadcastReceiver. I start a service when the network is available and stop the service when the network is not available.
I have the following class level variable.
private boolean IsNetworkAlreadyConnected = false;
Within onCreate method of the main class I start the service if the internet is available.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (InternetConnectivity.isConnected(MainActivity.this)) {
IsNetworkAlreadyConnected = true;
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
startService(timerIntent);
}
}
and below is the code for my BroadcastReceiver in the same class,
public class mConnectivityCheckReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.net.conn.CONNECTIVITY_CHANGE")) {
try {
boolean networkAvailable = InternetConnectivity.isConnected(context);
if (networkAvailable) {
if (!IsNetworkAlreadyConnected) {
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
startService(timerIntent);
IsNetworkAlreadyConnected = true;
}
else {
Log.d("KC_HomeActivity", "Network was already connected. No need to start service again.");
}
}
else {
Log.d("KC_HomeActivity", "Network Disconnected. Service Stopped.");
IsNetworkAlreadyConnected = false;
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
stopService(timerIntent);
}
}
catch (Exception e) {
}
}
}
};
When both Mobile data and Wifi are turned on then the service is started from onCreate method and it is not started again in the BroadcastReceiver but when I turn off the Wifi the Android changes the network mode to Mobile Data but for few seconds there is no internet connectivity and the service is stopped and then started again. I don't want to do this. If there is no connectivity only then the service should be stopped. If the network is shifting from Wifi to Mobile Data then the service should not be stopped.
Note: To check the internet connectivity I am using,
NetworkInfo info = InternetConnectivity.getNetworkInfo(context);
return (info != null && info.isConnectedOrConnecting());
Network connections aren't that precise. You should make it relax a bit, or you'll pull your hair out.
I would implement a smoothing function from the broadcasts. When you get a connectivity change notification, set a timeout for like 15 seconds. At that time, check your status and either start, stop, or do nothing. If another broadcast comes in, clear the first and reset for another 15 seconds. That will give the device time to reconnect.
In the OnReceive method I have something like this:
Bundle bundle=intent.getExtras();
String phonenumber=intent.getStrngExtra(Intent.EXTRA_PHONE_NUMBER);
How to chech if the dialing call is still on or the client hanged up the call?
How to check if the call was answered?
I need to print up a toat when the client hanged up the call or when the called client answered to the call.
You will need a broadcast receiver registered for action android.intent.action.PHONE_STATEiF THE phone state has not changed to idle once it is offhook, it means the call is still going on.
the call was answered if the state in read phone state broadcast receiver changes to offhook. Put a toast as need in these states.
public class CallDurationReceiver extends BroadcastReceiver {
static boolean flag =false;
static long start_time,end_time;
#Override
public void onReceive(Context arg0, Intent intent) {
String action = intent.getAction();
if(action.equalsIgnoreCase("android.intent.action.PHONE_STATE")){
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_RINGING)) {
//tOAST FOR INCOMING CALL, NOT YET PICKED UP
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE)) {
end_time=System.currentTimeMillis();
//Total time talked =
long total_time = end_time-start_time;
//Store total_time somewhere or pass it to an Activity using intent
} if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK)) {
start_time=System.currentTimeMillis();
}
}
}
Register your receiver in your manifest file like this:
<receiver android:name=".CallDurationReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
}
Also add the uses permission:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Well all I find out a solution for this and I successfully implemented it.Its not possible to fetch the exact time when the callee has accepted an outgoing call.
Before picking up a call in the other end it has already passed through 2 stages namely on_State_idle and on_state_offhook. On_state_ringing is not working for the outgoing calls.
Let's assume a phone is ringing for 40sec (this am not sure) continuously if the person at the other side didn't pick the call.
Start a timer along with the starting stage of on_State_idle and on_state_offhook.
Two cases if the timer cross above 40sec means the person at the other hand pick my call.
If on_State_idle->on_state_offhook->on_State_idle worked within 40sec means the other hand didn't pick my call.
If the second case is true, fetch the call talk duration from the call log.
Totaltimer running time - time in call log gives you the exact time of picking of the outgoing Call!
you can use the below code for handling call state:::
private Runnable callMonitor = new Runnable() {
public void run() {
try {
EndCallListener callListener = new EndCallListener();
TelephonyManager mTM = (TelephonyManager)m_activity.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch(Exception e) {
Log.e("callMonitor", "Exception: "+e.toString());
}
}
};
private class EndCallListener extends PhoneStateListener {
private boolean active = false;
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if(TelephonyManager.CALL_STATE_RINGING == state) {
Log.i("EndCallListener", "RINGING, number: " + incomingNumber);
}
if(TelephonyManager.CALL_STATE_OFFHOOK == state) {
//wait for phone to go offhook (probably set a boolean flag) so you know your app initiated the call.
active = true;
Log.i("EndCallListener", "OFFHOOK");
}
if(TelephonyManager.CALL_STATE_IDLE == state) {
//when this state occurs, and your flag is set, restart your app
Log.i("EndCallListener", "IDLE");
if (active) {
active = false;
// stop listening
TelephonyManager mTM = (TelephonyManager)m_activity.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(this, PhoneStateListener.LISTEN_NONE);
// restart the inbox activity
// Intent intent = new Intent(m_activity, MDInboxActivity.class);
// m_activity.startActivity(intent);
}
}
}
}
I'd like to build an Android application that can contact the current caller via a pre-determined text message. Sending a text message is simple enough but determining the phone number of the current caller in a stand-alone application is the challenge. Is the there an easy way to divine the phone number so I can send them a message while still on the call?
Of course there are manual ways to do this: write down the number, key it into a new text message, enter the message. But I want to define the message up front and be able to "send it to current caller".
#Override
public void onReceive(Context context, Intent intent) {
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneCallStateListener customPhoneListener = new PhoneCallStateListener(context);
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
helper = new ContactDatabaseHelper(context);
list = helper.getAllContacts();
try{
incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (list.size() != 0){
for ( int i = 0, size = list.size(); i < size; i++ ){
if (PhoneNumberUtils.compare(incomingNumber, list.get(i).getContactNumber())){
ToastMsg.showToast(context,list.get(i).getContactName()+" Calling");
}
}
}
}catch (Exception e) {
// TODO: handle exception
}
}
public class PhoneCallStateListener extends PhoneStateListener{
private Context context;
public PhoneCallStateListener(Context context){
this.context = context;
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
break;
case PhoneStateListener.LISTEN_CALL_STATE:
}
super.onCallStateChanged(state, incomingNumber);
}
}
For your sistuation the best I can think of is to use PhoneStateListener. It contains onCallStateChanged handler. One of the arguments is a String containing the incoming phone number.
Source:
http://developer.android.com/reference/android/telephony/PhoneStateListener.html
Ctrl + F and type in "Incoming" and you will find everything you need to know.
EDIT: To make sure you're app starts on the startup of your phone, just add a BroadcastReciever. How to start an Application on startup?
Register a BroadcastReceiver in your manifest that listens to ACTION_PHONE_STATE_CHANGED.
Broadcast intent action indicating that the call state (cellular) on
the device has changed.
The EXTRA_STATE extra indicates the new call state. If the new state
is RINGING, a second extra EXTRA_INCOMING_NUMBER provides the incoming
phone number as a String.
Requires the READ_PHONE_STATE permission.
This was a sticky broadcast in version 1.0, but it is no longer
sticky. Instead, use getCallState() to synchronously query the current
call state.
This way you don't need the user to launch your app before receiving a call.
I want to show the connection process on the screen when my device is connecting to the wifi network. SUPPLICANT_STATE_CHANGED_ACTION is provided by WifiManager but i don't know how to use it. Can anyone help me please?
You can indeed use the broadcasted intents for SUPPLICANT_STATE_CHANGED_ACTION:
The app needs the permission in its Manifest file:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Then register for the system broadcast:
MyWifiStateReceiver handler = new MyWifiStateReceiver();
context.registerReceiver(handler, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
the registerReceiver() needs an instance of a class implementing BroadcastReceiver as its first argument. In that code you can act on the Wifi state changes by overriding the onReceive method. For example
public class MyWifiStateReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION))
{
SupplicantState state = (SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
switch(state)
{
case COMPLETED:
case DISCONNECTED:
...
}
}
}
}
For the possible Wifi state values, see http://developer.android.com/reference/android/net/wifi/SupplicantState.html
I don't know of a callback method that lets you know when the wifi status has changed. I polled the information using a Handler running in the background.
Add the handler to your class.
private WifiStatusHandler wifiStatusHandler = new WifiStatusHandler();
Start it by calling
wifiStatusHandler.start();
The code I used is below.
/**
* Checks for wifi status updates.
*/
private class WifiStatusHandler extends Handler {
private boolean running = false;
public void handleMessage(Message message) {
if (running) {
//check wifi status here
WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
int curWifiState = wifiMgr.getWifiState();
SupplicantState info = wifiMgr.getConnectionInfo().getSupplicantState();
WifiInfo curWifi = wifiMgr.getConnectionInfo();
Log.i(TAG,"WIFI STATE = " + info.toString());
//update the TextView etc.
sleep();
}
}
private void sleep() {
removeMessages(0);
sendMessageDelayed(obtainMessage(0), REFRESH_DELAY);
}
public synchronized void start() {
running = true;
removeMessages(0);
sendMessageDelayed(obtainMessage(0), 0);
}
public synchronized void stop() {
running = false;
}
}