I wrote a simple class that extends BroadcastReceiver to handle an incoming call and get the caller's number. Now I want to display that number in a popup window or something similar. I've tried to display an alert dialog or open an activity but my app crashed. Then I read that it's not a good idea to start dialog from a BroadcastReceiver class. I need you to advice me how to correctly display the caller's number on the screen when there's an incoming call. This is my Broadcast Receiver class:
package com.example.nrsearch;
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 CallReceiver extends BroadcastReceiver {
public CallReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
Log.i("CallReceiverBroadcast", "onReceive() is called. ");
TelephonyManager teleMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener psl = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.i("CallReceiverBroadcast", "onCallStateChanged() is called. ");
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Log.i("CallReceiverBroadcast", "Incoming call caught. Caller's number is " + incomingNumber + ".");
}
}
};
teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);
}
}
I created a IncomingCallService service that extends from BroadcastReceiver to handle an incoming call and get the caller's number. Now I displayed that Incoming caller number in a popup window like TrueCaller. Its working fine me. Hope it should helpful for you. Please try and let me know. Thanks
CallReceiver.java
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 CallReceiver extends BroadcastReceiver {
static String IncomingNumber;
#Override
public void onReceive(final Context context, Intent intent) {
TelephonyManager teleMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener psl = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
IncomingNumber = incomingNumber;
Log.i("CallReceiverBroadcast", "Incoming call caught. Caller's number is " + incomingNumber + ".");
Intent i = new Intent(context, IncomingCallService.class);
context.startService(i);
case TelephonyManager.CALL_STATE_IDLE:
Log.i("CallReceiverBroadcast", "CALL_STATE_IDLE");
IncomingCallService.clearView(context);
// Call Disconnected
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i("CallReceiverBroadcast", "CALL_STATE_OFFHOOK");
IncomingCallService.clearView(context);
// Call Answer Mode
break;
}
}
};
teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);
}
}
IncomingCallService.java:
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
public class IncomingCallService extends Service {
static View view = null;
static WindowManager wm;
static LayoutInflater inflater;
static WindowManager.LayoutParams params;
private static TextView txtIncomingnumber;
static boolean processingAction = false;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onCreate();
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, 350,
WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.TOP;
params.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.activity_main,null);
wm.addView(view, params);
txtIncomingnumber = (TextView)view.findViewById(R.id.txtIncomingnumber);
txtIncomingnumber.setText("You have Incoming Call from " + CallReceiver.IncomingNumber);
return START_STICKY;
}
public static void clearView(Context context) {
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
if(view != null) {
if(view.isEnabled()){
wm.removeView(view);
view = null;
}
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:background="#0090FF"
android:padding="10dp"
android:keepScreenOn="true" >
<TextView
android:id="#+id/txtIncomingnumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:text="Incoming Call Number"
android:textColor="#fff" />
</RelativeLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stackoverflow"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" ></uses-permission>
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".CallReceiver" >
<intent-filter android:priority="99999">
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
<activity
android:name="com.stackoverflow.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".IncomingCallService">
</service>
</application>
</manifest>
If you want to show a dialog from inside your onReceive of the BroadcastReceiver, you have to start a transparent activity with an alert dialog and NEVER called setContentView(). The activity will have an transparent view and only the alert dialog will show..
Your Broadcast Receiver onReceive
#Override
public void onReceive(Context context, Intent intent) {
Log.i("CallReceiverBroadcast", "onReceive() is called. ");
TelephonyManager teleMgr =(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener psl = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.i("CallReceiverBroadcast", "onCallStateChanged() is called. ");
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Log.i("CallReceiverBroadcast", "Incoming call caught. Caller's number is " +incomingNumber + ".");
//start activity which has dialog
Intent i=new Intent(context,DialogActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
};
teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);
}
And your DiaLogActivity
public class DialogActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//dont call setcontent view
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?").setCancelable(
false).setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
}).setNegativeButton("No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
Related
The problem in my work is if I give the android.intent.action.PHONE_STATE intent from the shell it works but does not get the phone number. But the main problem is that when I call my phone it does not get any effect. What is the problem when I call my phone with another phone when the app is closed, why not receive this call?
Here is AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="homework.contactor">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".ServiceReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
</manifest>
Here is the Receiver Code:
package homework.contactor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
class MyPhoneStateListener extends PhoneStateListener {
public static Boolean phoneRinging = false;
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.d("DEBUG", "IDLE");
phoneRinging = false;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d("DEBUG", "OFFHOOK");
phoneRinging = false;
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.d("DEBUG", "RINGING");
phoneRinging = true;
break;
}
}
}
public class ServiceReceiver extends BroadcastReceiver {
TelephonyManager telephony;
public void onReceive(Context context, Intent intent) {
MyPhoneStateListener phoneListener = new MyPhoneStateListener();
telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
public void onDestroy() {
telephony.listen(null, PhoneStateListener.LISTEN_NONE);
}
}
Check this code, it is working for me
public class ServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
Toast.makeText(MainActivity.this, "" + incomingNumber, Toast.LENGTH_SHORT).show();
}
}, PhoneStateListener.LISTEN_CALL_STATE);
}
}
How to use ussdinterceptor service in android is question which is asked a lot. and the responses for it are poor.
this is my response.
first the service it self.
classes for the package com.example.ussdcodes
BootReceiver.java
package com.example.ussdcodes;
//import com.example.ussdcodes.R;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d("USSDService", context.getString(R.string.service_started));
context.startService(new Intent(context,USSDDumbExtendedNetworkService.class));
}
}
USSDDumbExtendedNetworkService.java
package com.example.ussdcodes;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.IBinder;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.util.Log;
import com.android.internal.telephony.IExtendedNetworkService;
//import com.android.internal.telephony.IExtendedNetworkService;
import com.example.ussdcodes.R;
/**
* Service implements IExtendedNetworkService interface.
* USSDDumbExtendedNetworkService
* Service must have name "com.android.ussd.IExtendedNetworkService" of the intent declared
* in the Android manifest file so com.android.phone.PhoneUtils class bind
* to this service after system rebooted.
* Please note service is loaded after system reboot!
* Your application must check is system rebooted.
* #see Util#syslogHasLine(String, String, String, boolean)
*/
public class USSDDumbExtendedNetworkService extends Service {
public static final String TAG = "CommandusUSSDExtNetSvc";
public static final String LOG_STAMP = "*USSDTestExtendedNetworkService bind successfully*";
public static final String URI_SCHEME = "ussdcodes";
public static final String URI_AUTHORITY = "android.com";
public static final String URI_PATH = "/";
public static final String URI_PAR = "return";
public static final String URI_PARON = "on";
public static final String URI_PAROFF = "off";
public static final String MAGIC_ON = ":ON;)";
public static final String MAGIC_OFF = ":OFF;(";
public static final String MAGIC_RETVAL = ":RETVAL;(";
public static final String RESULT = "result";
private static boolean mActive = true;
private static CharSequence mRetVal = null;
private Context mContext = null;
private String msgUssdRunning = "USSD running...";
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_INSERT.equals(intent.getAction())) {
mContext = context;
if (mContext != null) {
msgUssdRunning = mContext.getString(R.string.USSD_run);
mActive = true;
Log.d(TAG, "activate");
}
} else if (Intent.ACTION_DELETE.equals(intent.getAction())) {
mContext = null;
mActive = false;
Log.d(TAG, "deactivate");
}
}
};
private final IExtendedNetworkService.Stub mBinder = new IExtendedNetworkService.Stub() {
#Override
public void setMmiString(String number) throws RemoteException {
Log.d(TAG, "setMmiString: " + number);
Intent intent =new Intent("com.example.ussdcodes.setmmistring") ;
intent.putExtra("ussdCode", number);
sendBroadcast(intent);
}
#Override
public CharSequence getMmiRunningText() throws RemoteException {
Log.d(TAG, "getMmiRunningText: " + msgUssdRunning);
return msgUssdRunning;
}
#Override
public CharSequence getUserMessage(CharSequence text)
throws RemoteException {
/* if (MAGIC_ON.contentEquals(text)) {
mActive = true;
Log.d(TAG, "control: ON");
return text;
} else {
if (MAGIC_OFF.contentEquals(text)) {
mActive = false;
Log.d(TAG, "control: OFF");
return text;
} else {
if (MAGIC_RETVAL.contentEquals(text)) {
mActive = false;
Log.d(TAG, "control: return");
return mRetVal;
}
}
}
if (!mActive) {
Log.d(TAG, "getUserMessage deactivated: " + text);
return text;
} */
String s = text.toString();
// store s to the !
Uri uri = new Uri.Builder()
.scheme(URI_SCHEME)
.authority(URI_AUTHORITY)
.path(URI_PATH)
.appendQueryParameter(URI_PAR, text.toString())
.build();
// Intent intent =new Intent(Intent.ACTION_GET_CONTENT, uri) ;
// Intent intent =new Intent("com.example.ussdcodes", uri) ;
Intent intent =new Intent("com.example.ussdcodes.getusermsg") ;
intent.putExtra("result", s);
sendBroadcast(intent);
mActive = false;
mRetVal = text;
Log.d(TAG, "getUserMessage: " + text + "=" + s);
return null;
}
#Override
public void clearMmiString() throws RemoteException {
Log.d(TAG, "clearMmiString");
}
};
/**
* Put stamp to the system log when PhoneUtils bind to the service
* after Android has rebooted. Application must call {#link Util#syslogHasLine(String, String, String, boolean)} to
* check is phone rebooted or no. Without reboot phone application does not bind tom this service!
*/
#Override
public IBinder onBind(Intent intent) {
// Do not localize!
Log.i(TAG, LOG_STAMP);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_INSERT);
filter.addAction(Intent.ACTION_DELETE);
filter.addDataScheme(URI_SCHEME);
filter.addDataAuthority(URI_AUTHORITY, null);
filter.addDataPath(URI_PATH, PatternMatcher.PATTERN_LITERAL);
registerReceiver(mReceiver, filter);
return mBinder;
}
public IBinder asBinder() {
Log.d(TAG, "asBinder");
return mBinder;
}
}
the aidl for com.android.internal.telephony
IExtendedNetworkService.aidl
package com.android.internal.telephony;
/**
* Interface used to interact with extended MMI/USSD network service.
*/
interface IExtendedNetworkService {
/**
* Set a MMI/USSD command to ExtendedNetworkService for further process.
* This should be called when a MMI command is placed from panel.
* #param number the dialed MMI/USSD number.
*/
void setMmiString(String number);
/**
* return the specific string which is used to prompt MMI/USSD is running
*/
CharSequence getMmiRunningText();
/**
* Get specific message which should be displayed on pop-up dialog.
* #param text original MMI/USSD message response from framework
* #return specific user message correspond to text. null stands for no pop-up dialog need to show.
*/
CharSequence getUserMessage(CharSequence text);
/**
* Clear pre-set MMI/USSD command.
* This should be called when user cancel a pre-dialed MMI command.
*/
void clearMmiString();
}
the manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ussdcodes"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name="com.example.ussdcodes.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".USSDDumbExtendedNetworkService" >
<intent-filter android:icon="#drawable/ic_launcher">
<action android:name="com.android.ussd.IExtendedNetworkService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application>
</manifest>
now the activity that uses the service (don't forgot to reboot the phone after installing the service)
MainActivity.java
package com.example.usingussdservice;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity {
UssdMsg ussdMsg = new UssdMsg();
UssdsetMmi ussdsetMmi = new UssdsetMmi();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ussdMsg.setMainActivityHandler(this);
ussdsetMmi.setMainActivityHandler(this);
// com.example.ussdcodes
IntentFilter fltr_ussdmsg = new IntentFilter("com.example.ussdcodes.getusermsg");
registerReceiver(ussdMsg,fltr_ussdmsg);
IntentFilter fltr_setmmistring = new IntentFilter("com.example.ussdcodes.setmmistring");
registerReceiver(ussdsetMmi,fltr_setmmistring);
}
public void onClick(View v) {
sendUssd( ) ;
}
public void sendUssd( )
{
//codeToSend=*600*1*#
String codeToSend ;
codeToSend = "tel:" + Uri.encode("*") + "600"+ Uri.encode("*")+"1"+ Uri.encode("#");
// codeToSend = "tel:" + codeUssd ;
startActivityForResult(new Intent("android.intent.action.CALL",
Uri.parse(codeToSend)), 1);
}
}
UssdMsg.java
package com.example.usingussdservice;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;
public class UssdMsg extends BroadcastReceiver {
// Get the object of SmsManager
MainActivity mainActivity = null;
void setMainActivityHandler(MainActivity mainActivity ){
this.mainActivity=mainActivity;
}
public void onReceive(Context context, Intent intent) {
setMainActivityHandler(mainActivity);
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"inside UssdMsg.onReceive", duration);
toast.show();
Bundle bundle = intent.getExtras();
if (bundle != null) {
String string = bundle.getString("result");
Toast toast2 = Toast.makeText(context,
"result="+string, duration);
toast2.show();
}
}
}
UssdsetMmi.java
package com.example.usingussdservice;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;
public class UssdsetMmi extends BroadcastReceiver {
// Get the object of SmsManager
MainActivity mainActivity = null;
void setMainActivityHandler(MainActivity mainActivity ){
this.mainActivity=mainActivity;
}
final SmsManager sms = SmsManager.getDefault();
public void onReceive(Context context, Intent intent) {
setMainActivityHandler(mainActivity);
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"inside UssdsetMmi.onReceive", duration);
toast.show();
Bundle bundle = intent.getExtras();
if (bundle != null) {
String string = bundle.getString("ussdCode");
Toast toast2 = Toast.makeText(context,
"ussdCode="+string, duration);
toast2.show();
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.usingussdservice"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="35dp"
android:layout_marginTop="34dp"
android:onClick="onClick"
android:text="send ussd code" />
</RelativeLayout>
I Could not figure out what is wrong with below code. I also checked about registering receiver twice. But that's also not the case. or may be I am missing something.
Could any please help. I really need it. :(
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
/**
*
* #author Bharat
*
*/
public class CallNotifierService extends Service
{
private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
private CallBr br_call;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public void onDestroy()
{
Log.d("service", "destroy");
this.unregisterReceiver(this.br_call);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUT);
filter.addAction(ACTION_IN);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
return START_NOT_STICKY;
}
public class CallBr extends BroadcastReceiver
{
Bundle bundle;
String state;
String inCall, outCall;
public boolean wasRinging = false;
public boolean answered = false;
public boolean outgoing = false;
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(ACTION_IN))
{
if ((bundle = intent.getExtras()) != null)
{
state = bundle.getString(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
wasRinging = true;
Toast.makeText(context, "Incoming Call : " + inCall, Toast.LENGTH_LONG).show();
}
else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
if (wasRinging == true)
{
answered = true;
Toast.makeText(context, "Answered", Toast.LENGTH_LONG).show();
}
}
else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE))
{
wasRinging = false;
Toast.makeText(context, "Disconnected", Toast.LENGTH_LONG).show();
}
}
}
else if (intent.getAction().equals(ACTION_OUT))
{
if ((bundle = intent.getExtras()) != null)
{
outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "Outgoing Call : " + outCall, Toast.LENGTH_LONG).show();
outgoing = true;
}
}
}
}
}
Below is the activity I am calling it from
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.roaming);
Intent intent = new Intent(this, CallNotifierService.class);
startService(intent);
}
.
.
.
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ind.cosmos.main"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-sdk
android:minSdkVersion="22"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<!-- android:theme="#style/AppTheme"> -->
<activity
android:name="ind.cosmos.main.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="ind.cosmos.callRecord.CallNotifierService" />
</application>
As Bharat said it's better so handle it in code. Below is a trick to do so, found here, thanks to Michael Marvick who has given detail description as well.
public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "PHONE STATE";
private static String mLastState;
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (!state.equals(mLastState)) {
mLastState = state;
Log.e(TAG, state);
}
}
}
Actually .. there is nothing wrong with the code. its System who triggers this. some time its 2 times.. other times it touches 4 times.
So the best we can do it handle it in the code itself.
I have the same behavior, and there is no issue in your code. android.intent.action.PHONE_STATE can be received few times, but Intent's bundle is always different, for example:
D/App(2001): Bundle{ state => OFFHOOK; subscription => 1; }Bundle
D/App(2001): Bundle{ incoming_number => 555555555; state => OFFHOOK; subscription => 9223372036854775807; }Bundle
Before making this as duplicate:: I see a lot of threads supporting this, but none of them works in waking up or turning the screen on when the screen is completely turned off (or in sleep mode).
My aim: when the USB is connected or the device is plugged in to AC power the screen has to turn off (that is happening), and when the power/ USB is unplugged the screen has to turn on back to the app. (not working).
Note: If the screen is dimmed out to the lowest instead of turning it off we can turn the brightness on back when required, but that is not what I want.
The links that is suppoting this questions are:
1. wake-android-device-up
2. is-there-a-way-to-force-an-android-device-to-stay-awake
3. android-how-to-turn-screen-on-and-off-programmatically
4. turning-on-screen-programmatically
5. how-to-unlock-the-screen-when-broadcastreceiver-is-called
Here is the code that I am using It successfully turns the screen OFF, but will not Turn it on. You can also download the code project from : Download Here
Class Name: MainActivity
package com.power.screenmode;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.WindowManager;
import android.widget.TextView;
import com.power.screenmode.BackgroundService.PowerUtil;
public class MainActivity extends Activity {
private TextView txt_PowerConnected;
private boolean isChargerConnected = false;
private Context mContext;
private WindowManager.LayoutParams params ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
firstLoad();
initViews();
doTask();
startService();
}
#Override
protected void onResume() {
// powerMethod();
super.onResume();
}
private void firstLoad(){
mContext = MainActivity.this;
}
private void initViews(){
setContentView(R.layout.activity_main);
txt_PowerConnected = (TextView)findViewById(R.id.txt_PowerConnected);
}
private void doTask(){
isChargerConnected = PowerUtil.isConnected(mContext);
params = getWindow().getAttributes();
if(isChargerConnected){
txt_PowerConnected.setText("Charger Connected");
turnScreenOFF();
System.out.println("Power Connected - doTask");
}else{
txt_PowerConnected.setText("Charger Not Connected");
turnScreenON();
System.out.println("Power Disconnected - doTask");
}
}
private void startService(){
try {
Intent service = new Intent(this, BackgroundService.class);
startService(service);
Log.i("SCREEN_MODE", "background service calling");
} catch (Exception e) {
e.printStackTrace();
}
// register the receiver to listen to battery change
this.registerReceiver(this.receiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
private void turnScreenOFF(){
params = getWindow().getAttributes();
/** Turn OFF: */
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.screenBrightness = 0.0f; // 0.1f to turn the brightness to lowest
getWindow().setAttributes(params);
}
private void turnScreenON(){
params = getWindow().getAttributes();
/** Turn ON: */
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.screenBrightness = 1.0f;
getWindow().setAttributes(params);
// I have tried the below method also but it didn't work\\\
// powerMethod();
}
private void powerMethod(){
KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
final KeyguardManager.KeyguardLock kl = km.newKeyguardLock("MyKeyguardLock");
kl.disableKeyguard();
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
wakeLock.acquire();
if(wakeLock.isHeld()){
wakeLock.release();
}
}
BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
if (plugged == BatteryManager.BATTERY_PLUGGED_AC ||plugged == BatteryManager.BATTERY_PLUGGED_USB ){
System.out.println("Charger connected -- receiver");
turnScreenOFF();
} else{
System.out.println("Charger Disconnected -- receiver");
turnScreenON();
}
}
};
}
The Background service class:
/**
*
*/
package com.power.screenmode;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.WindowManager;
/**
* #author Prasildas
*
*/
public class BackgroundService extends Service {
public static final int INITDELAY_TASK = 0;
public static final int INTERVAL_TASK1 = 1;
private ScheduledExecutorService scheduler;
public static ScheduledFuture<?> schedule_Background;
private Handler tableUpdateHandler;
WindowManager.LayoutParams params ;
#Override
public void onCreate() {
super.onCreate();
Log.i("SCREEN_MODE", "Started");
tableUpdateHandler = new Handler();
scheduler = Executors.newScheduledThreadPool(2);
schedule_Background = scheduler.scheduleAtFixedRate(task_CheckScreenMode, INITDELAY_TASK, INTERVAL_TASK1, TimeUnit.SECONDS);
Log.i("SCREEN_MODE", "Created background service --> Live Mode");
}
/**
* To stop the background check
*/
public void stopBackgroundTask() {
if (schedule_Background != null) {
schedule_Background.cancel(true);
}
}
/** The background task in the service -- Shaking the cart with the badge numbers updating
*/
private Runnable task_CheckScreenMode = new Runnable() {
#Override
public void run() {
tableUpdateHandler.post(new Runnable() {
#Override
public void run() {
try {
PowerUtil.isConnected(getApplicationContext());
Log.i("SCREEN_MODE", "background running powerutil");
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
public static class PowerUtil {
public static boolean isConnected(Context context) {
Intent intent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(final Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.i("SCREEN_MODE", "background service task 1 destroyed");
super.onDestroy();
}
}
The Manifest File:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.power.screenmode"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.power.screenmode.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.power.screenmode.BackgroundService" >
</service>
</application>
</manifest>
I would like to bring up a Toast and vibrate when call status is Idle.
I added this in the manifest file:
<receiver android:name="IncomingCallInterceptor">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
And this is IncomingCallInterceptor
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Vibrator;
import android.telephony.TelephonyManager;
import android.widget.Toast;
import android.app.Activity;
public class IncomingCallInterceptor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String msg = "Phone state changed to " + state;
if (TelephonyManager.EXTRA_STATE_RINGING.equals(state))
{
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
msg += ". Incoming number is " + incomingNumber;
}
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
if(msg == "IDLE")
{
ok() ;
}
}
public void ok()
{
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(3000);
}
}
}
And I received this error:
Description Resource Path Location Type
The method getSystemService(String) is undefined for the type IncomingCallInterceptor IncomingCallInterceptor.java line 39 Java Problem
Make Sure You Have Added VIBRATE permission in manifest as:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="...">
<uses-permission android:name="android.permission.VIBRATE"/>
<application android:label="...">
...
</application>
</manifest>
change Your Code as:
public class IncomingCallInterceptor extends BroadcastReceiver {
private Context contextc;
#Override
public void onReceive(Context context, Intent intent)
{
this.contextc=context;
//YOUR CODE HERE
public void ok()
{
Vibrator v = (Vibrator)contextc.getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(3000);
}