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
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?
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);
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.
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);
}
}
}
}
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;
}
}