PhoneStateListener executing multiple times - android

When i try to detect incoming calls with PhoneStateListener, it executes multiple times.
This is my code. onCallStateChanged method is called multiple times.
public class CallHelper {
public String number;
private Context ctx;
private TelephonyManager tm;
private CallStateListener callStateListener;
private OutgoingReceiver outgoingReceiver;
SharedPreferences trackMeData;
public CallHelper(Context ctx) {
this.ctx = ctx;
number ="";
callStateListener = new CallStateListener();
outgoingReceiver = new OutgoingReceiver();
trackMeData = ctx.getSharedPreferences("LockedSIM", 0);
}
private class CallStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
number = incomingNumber;
sendsmstoph(number);
System.out.println("Incomgin");
Toast.makeText(ctx, "Incoming: " + incomingNumber,Toast.LENGTH_LONG).show();
break;
}
}
}

Using BroadcastReceiver with functionality of PhoneStateListener
In above line: The problem is that every time when the onReceive() method is called a new TelphoneManager instance is created and registers as a listener to Phoone State .
Solution :
I made every variable of the CallReceiverBroadcast class static ! and it solved the problem !! to an extent but still the service is called twice every time it means that some how there is 2 instance of the class registered as a listener but i don't know why. Although i can work around it through some condition but it is causing unnecessary overhead and Anyone having a better solution will be highly Appreciated .

package com.example.netlogger.Receiver;
import java.util.Date;
import com.example.netlogger.util.LocalDatabase;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.util.Log;import android.widget.Toast;
public class CallActionsReceiver extends BroadcastReceiver {
static ThePhoneStateListener phoneStateListener;
#Override
public void onReceive(Context arg0, Intent arg1) {
TelephonyManager manager = (TelephonyManager) arg0
.getSystemService(arg0.TELEPHONY_SERVICE);
if (phoneStateListener == null) {
phoneStateListener = new ThePhoneStateListener(arg0);
manager.listen(phoneStateListener,
android.telephony.PhoneStateListener.LISTEN_CALL_STATE);
}
}
}

Related

Why doesn't Mockito's when()... thenReturn() work with string constants from other classes

I'm trying to stub a getExtras() call on a mocked intent but it seems when()...thenReturn() doesn't work (returns NULL) when I use any of the TelephonyManager string constants. I've tried using dummy strings and it works so I know the test isn't working because of the when()...thenReturn() calls.
Here's my code
package metabrick.com.notrightnow;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import metabrick.com.notrightnow.CatchingMissedCallsFeature.MissedCallBroadcastReceiver;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
/*This class tests the logic of MissedallBroadcastReceiver class logic .i.e
* The logic of detecting a missed phone call*/
public class MissedCallBroadcastReceiverTest {
#Mock private Context context;
#Mock private Intent intent;
#Mock Bundle bundle ;
private MissedCallBroadcastReceiver missedCallBroadcastReceiver;
#Before
public void setUpMissedCallBroadcastReceiver(){
MockitoAnnotations.initMocks(this);
missedCallBroadcastReceiver = new MissedCallBroadcastReceiver();
}
#Test
public void onReceiveTest(){
when(intent.getStringExtra(anyString()))
.thenReturn(telephonyManager.EXTRA_STATE_RINGING);
when(intent.getExtras()).thenReturn(bundle);
when(bundle.getString("incoming_number")).thenReturn("905-456-4520");
//Calling onReceive
missedCallBroadcastReceiver.onReceive(context, intent);
//Verfy that attempt was made to retrieve the state of the phone
verify(intent).getStringExtra(TelephonyManager.EXTRA_STATE);
//verfy that an attempt was made to retrievr the number of the caller
verify(bundle).getString("incoming_number");
/*Testing a received call scenario */
when(intent.getStringExtra(anyString()))
.thenReturn(TelephonyManager.EXTRA_STATE_RINGING)
.thenReturn(TelephonyManager.EXTRA_STATE_OFFHOOK);
missedCallBroadcastReceiver.onReceive(context, intent);
//check that the callRinging variable is set to true
assertTrue(missedCallBroadcastReceiver.isCallRinging());
//check that the callReceived variable is set to true
assertTrue(missedCallBroadcastReceiver.isCallReceived());
/*Testing a missed call scenario */
when(intent.getStringExtra(anyString()))
.thenReturn(TelephonyManager.EXTRA_STATE_RINGING)
.thenReturn(TelephonyManager.EXTRA_STATE_IDLE);
missedCallBroadcastReceiver.onReceive(context, intent);
//check that the callReceived and ringing variables are set to false
assertFalse(missedCallBroadcastReceiver.isCallReceived());
assertFalse(missedCallBroadcastReceiver.isCallRinging());
// checking that the number gotten from the intent
assertSame("905-456-4520", missedCallBroadcastReceiver.getCallerNumber());
}
}
Here's the method under test
#Override
public void onReceive(Context context, Intent intent) {
//Getting the phone state
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state == null) return;
//Getting the caller's number
callerNumber = intent.getExtras().getString("incoming_number");
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) rang = true;
if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) callReceived = true;
//if the phone is idle
if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
if (ringing&&!callReceived){
ringing = false;
try{
Toast.makeText(context, "Missed call", Toast.LENGTH_LONG).show();
}catch (Exception e){
e.printStackTrace();
}
}
callReceived = false;
}
}
I've searched for a while now I can't find any answers and I don't know how else to stub the intent for these calls to getExtras(). Can anyone help me out?

How to get call state of outgoing android call

I am originating a call from Android Studio. The code is as follows:
I want to get the state of the call at any point. The link: https://developer.android.com/reference/android/telecom/Call.html
shows the state of the call can be obtained by using the Class call.. SO if I use Call.getState() I should be able to get the current state. But I get the compilation error:
Error:(28, 20) error: Call() is not public in Call; cannot be accessed from outside package. There are several call states defined in the enum: Dialing, Ringing, Connected, DIsconnected, Holding, etc.
When I run the code, it does make the call as I can see the screen of emulator making the call.
The developer guide does not provide any examples of using these classes.
Thank you for your help.
package com.example.ramesh.makeacall;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telecom.Call;
import android.telephony.*;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Call call;
call = new Call();
call();
}
private void call() {
try {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:5555551212"));
System.out.println("====before startActivity====");
startActivity(callIntent);
} catch (ActivityNotFoundException e) {
Log.e("helloAndroid","Call failed",e);
}
}
}
Try to use like this(Haven't tried it though) -
Call.Callback callback = new Call.Callback() {
#Override
public void onStateChanged(Call call, int state) {
super.onStateChanged(call, state);
if(state == Call.STATE_RINGING){
//you code goes here
}
}
};
public class MyPhoneStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
handleRinging(incomingNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
handleOffHook();
break;
case TelephonyManager.CALL_STATE_IDLE:
handleIdle();
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
and register statelistener :
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

How to block call in Android 4.2

My Note :as I have already clarified in my initial post, I don't think it's a duplicate,
I already tried these method and it doesn't work for me,
The code below seems only work for 2.2, it requires MODIFY_PHONE_STATE which is not permitted after Android 2.2****
This is not duplicated questions since i have already looked many other post here and it doesn't work for me
I follow the solution from the link below:
block phone call
TelephonyManager tm = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
Class<?> c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
But the code give me exception when run on real device(which is Android 4.2)
java.lang.NoSuchMethodException: getITelephony
So, does it still possible use this solution on Android 4.2, if not,does there exist other solutions i can try?
Thanks a lot in advance
Create a file named ITelephony.aidl it should contain these data:
package com.android.internal.telephony;
interface ITelephony
{
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
Create these folders under src
android > internal > telephony
Then Place the ITelephony.adl under telephony folder.
Copy this DeviceStateListener class and place it under any package on your project.
import android.content.Context;
import android.os.RemoteException;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import java.lang.reflect.Method;
public class DeviceStateListener extends PhoneStateListener {
private ITelephony telephonyService;
private Context context;
public DeviceStateListener(Context context) {
this.context = context;
initializeTelephonyService();
}
private void initializeTelephonyService() {
try {
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Class clase = Class.forName(telephonyManager.getClass().getName());
try{
Method method = clase.getDeclaredMethod("getITelephony");
}catch (NoSuchMethodException e){
e.printStackTrace();
}
method.setAccessible(true);
telephonyService = (ITelephony) method.invoke(telephonyManager);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onCallStateChanged(int state, final String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
boolean isNumberIsBlocked=false;
// You can check here if incomingNumber string is under your blacklisted numbers
if (isNumberIsBlocked) {
try {
// This is the main code that block the incoming call.
telephonyService.endCall();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
// You can run anything here lets say a notice to the user if a call is blocked
}
});
t.start();
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
}
}
}
Here is another important class "ServiceReceiver" place it also under any package of your project and resolve all possible imports.
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class ServiceReciever extends BroadcastReceiver
{
private static TelephonyManager telephony;
private static DeviceStateListener phoneListener;
private static boolean firstTime=true;
public ServiceReciever(Context context)
{
telephony=(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
phoneListener=new DeviceStateListener(context);
}
#Override
public void onReceive(Context context, Intent intent)
{
if(firstTime)
{
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
firstTime = false;
}
}
// You can use this in the future to stop the call blocker feature.
public void stopListening() {
telephony.listen(phoneListener, PhoneStateListener.LISTEN_NONE);
firstTime=true;
}
}
Copy this CallBlockerService class also and place it under any package of your project. It is an unkillable service that invokes the ServiceReceiver class.
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import com.katadigital.phone.callsmsblocker.callListener.ServiceReciever;
public class CallBlockerService extends Service {
public static final int notification_id = 111;
// ---------------------------------------
// Listening Services
// ---------------------------------------
private static ServiceReciever service;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
service = new ServiceReciever(getApplicationContext());
registerReceiver(service, new IntentFilter(
"android.intent.action.PHONE_STATE"));
System.out.println("Call blocker is running now");
}
#Override
public void onDestroy() {
service.stopListening();
unregisterReceiver(service);
service = null;
cancelStatusBarNotification();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public void cancelStatusBarNotification() {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(notification_id);
}
}
Place this AfterBootReceiver class beside our CallBlockerService. Its job is to restart the blocker service when the phone starts from shutdown.
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class AfterBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Intent serviceLauncher = new Intent(context, CallBlockerService.class);
context.startService(serviceLauncher);
}
}
Lastly place this on your AndroidManifest under tag.
<receiver android:name="com.callblocker.services.AfterBootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:name="com.callblocker.services.CallBlockerService" >
</service>
Replace "com.callblocker.services" with the folder location of the CallBlockerService and your AfterBootReceiver
I have tested this code until Android 4.4 KitKat. I hope you can follow the steps and it helps you with your problem.

How to read the number of incoming call on Android Device

This question was asked several times but none of the solutions are working for me. I am on kitkat(4.4.4)/Nexus5. Below are solutions I tried
1)Based on How to detect incoming calls, in an Android device? solution, I tried to retrieve the number from "extras". But intent.getExtras.getString always returns null
2)Based on Get phone number of present incoming and outgoing call solution, I tried to read from the log, but "cur.getString(0)", always returns null
I am NOT using TelephonyManager any where in my code (though few in above links seem to be using telephonymanager). I am using BroadcastReceiver. My code is below. I ended up trying above 2 solutions, because I am getting null value(callingNumber) in my callback below.
public class MyPhoneStateListener extends PhoneStateListener {
//blah blah
public void onCallStateChanged(int state, String callingNumber)
{
//callingNumber is always null, unfortunately
}
}
For me this work, try and tell me
import org.jivesoftware.smackx.xdata.Form;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
public class MyIncomingCallListenerService extends BroadcastReceiver {
private StringBuffer incomingCall = new StringBuffer();
#Override
public void onReceive(Context context, Intent intent) {
try {
TelephonyManager tmgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
tmgr.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch (Exception e) {
e.printStackTrace();
}
}
private class MyPhoneStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.d("MyPhoneListener",state+" incoming no:"+incomingNumber);
}
}
}
}

Android: Register for another activity's onstop

Anyone know if I can receive my main Activity's onStop, onPause and onResume callbacks inside another class / object?
I've got a broadcast receiver that lives inside another class (a WebView). I use the receiver to detect when the network goes down and switch to a local copy of my page with some useful content. I need to un-register the broadcast receiver when onStop/onPause are called and re-register it during onResume.
I can do this by hand (I added a couple public methods to a class that extends WebView to do just that) , but it'd be nice to have Android just call it for me.
edit: Sure, here's the class, I'd like it to be able to receive get a callback from Android when my main activity's onStop gets called without having to call startInternetMonitoring() / stopInternetMonitoring():
package com.glimmersoft.spent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebView;
/**
* #author Jer
*
*/
public class OfflineWebView extends WebView {
private BroadcastReceiver receiver;
private IntentFilter filter;
private Context myContext;
public OfflineWebView(Context context,AttributeSet attrs) {
super(context, attrs);
WebSettings webSettings = this.getSettings();
webSettings.setJavaScriptEnabled(true);
myContext = context;
}//END CLASS CONSTRUCTTOR
/**
* #param internetOn The URL to display in this OfflineWebView when there is an active Internet connection.
* #param internetOff The URL to display in this OfflineWebView if there is no active Internet connection.
*/
public void setPages(final String internetOn, final String internetOff){
final OfflineWebView finalThisRef = this;
filter = new IntentFilter();
filter.addAction(SpendConstants.ANDROID_CONNECTIVITY_CHANGED);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo()!=null&&cm.getActiveNetworkInfo().isConnected()){// TODO: THIS FAILES IF
finalThisRef.loadUrl(internetOn);
}else{
finalThisRef.loadUrl(internetOff);
}
}//END IF/ELSE
};
myContext.registerReceiver(receiver, filter);
}//END FUNCTION SETPAGES
public void startInternetMonitoring(){
myContext.registerReceiver(receiver, filter);
}//END METHOD STARTINTERNETMONITORING
public void stopInternetMonitoring(){
myContext.unregisterReceiver(receiver);
}//END METHOD STOPINTERNETMONITORING
}//END CLASS OfflineWebView
Thanks all!
Instead of putting your BroadcastReceiver inside your OfflineWebView, make it a static class you register maybe in a base Activity and have it a hold a reference to your OfflineWebView. When onReceive is called, you can then reference your OfflineWebView to load your online/offline content.
file: MyBaseActivity.java
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.webkit.WebView;
public class MyBaseActivity extends Activity {
private static final String ANDROID_CONNECTIVITY_CHANGED = "android.net.conn.CONNECTIVITY_CHANGE";
protected static final ConnectivityBroadcastReceiver sReceiver = new ConnectivityBroadcastReceiver();
private static final IntentFilter sFilter = new IntentFilter(ANDROID_CONNECTIVITY_CHANGED);
static class ConnectivityBroadcastReceiver extends BroadcastReceiver {
private String internetOnUrl = "your online url";
private String internetOffUrl = "your offline url";
WebView offlineWebView;
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
// only do your online/offline loading if we have a webview set
if (offlineWebView != null) {
if (cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnected()) {
offlineWebView.loadUrl(internetOnUrl);
} else {
offlineWebView.loadUrl(internetOffUrl);
}
}
}
}
#Override
public void onStart() {
super.onStart();
// register receiver
registerReceiver(sReceiver, sFilter);
}
#Override
public void onStop() {
super.onStop();
// unregister receiver
unregisterReceiver(sReceiver);
}
}
file: MyActivity.java
import android.R;
import android.os.Bundle;
import android.webkit.WebView;
public class MyActivity extends MyBaseActivity {
private WebView mWebView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load your content root
setContentView(R.layout.main_layout);
// find your webview
mWebView = (WebView)findViewById(R.id.webView);
}
#Override
public void onStart() {
super.onStart();
// set your webview in the OfflineBroadcastReceiver
sReceiver.offlineWebView = mWebView;
}
#Override
public void onStop() {
super.onStop();
// clear your webview from the OfflineBroadcastReceiver
sReceiver.offlineWebView = null;
}
}

Categories

Resources