TelephonyManager getstate() returns zero in android - java

In my application, I want to put a log for the state when someone picks up the call. The getState() on the switch statement must return the correct state of the call, but it always returns zero. Here is my onRecieve() method:
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){
incomingFlag = false;
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i(TAG, "call OUT:"+phoneNumber);
TelephonyManager tm =
(TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
Log.e("log state", String.valueOf(tm.getCallState()));
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
incomingFlag = true;
incoming_number = intent.getStringExtra("incoming_number");
Log.i(TAG, "RINGING :"+ incoming_number);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(incomingFlag){
Log.i(TAG, "incoming ACCEPT :"+ incoming_number);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if(incomingFlag){
Log.i(TAG, "incoming IDLE");
}
break;
default:
Log.e("ds","Error");
}
}
manifest file :
<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=".BroadCast" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
Permissions :
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name = "android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
The onCreate() method mentioned above is in a seperate class I created called BroadCast, and I call it by creating a new instance of it.
Please let me know if more details are required.

Try to use a BroadcastReceiver to handle the incoming call.
In your onResume, set up the receiver
IntentFilter filter2 = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter2.setPriority(99999);
this.registerReceiver(incomingCallReceiver, filter2);
and handle it such as
BroadcastReceiver incomingCallReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
if (bundle == null) return;
// Incoming call
// Get the state
String state = bundle.getString(TelephonyManager.EXTRA_STATE);
// Process the states
if ((state != null) && (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))) {
// Ringing State
}
if ((state != null) && (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE))) {
// Idle State
}
if ((state != null) && (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK))) {
// Offhook State
}
}
};

Related

How to get the Real time when TelephonyManager.CALL_STATE_OFFHOOK is the state from onCallStateChanged method of PhoneStateListener

I am making a code for making phone calls. Everything successful except that I am unable to get the system time when TelephonyManager.CALL_STATE_OFFHOOK state from the onCallStateChanged(int state, String incomingNumber).
Similarly, I want to get the system time when TelephonyManager.CALL_STATE_IDLE state is arrived. Once I get both the values in the Mainactivity I can get the difference and based its value I can start some other activity.
For example, if the time difference between TelephonyManager.CALL_STATE_IDLE state and TelephonyManager.CALL_STATE_IDLE state is less than 30 second, then I can assume that the call is not attended and I can start another call(or to another number). I am able to do all these inside the onCallStateChanged Method of PhoneStateListener class. But unable to pass this values to Mainactivity either by variables or Methods etc. This is the code for invoking call and it is working fine
Intent myIntentCall = new Intent(Intent.ACTION_CALL, Uri.parse("tel:0123456789"));
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions();
}
else
{
startActivity(myIntentCall);
}
private void requestPermissions () {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 1);
}
From the below piece of code, I expect the updated value of _seconds to the Mainactivity class by accessing PhoneReceiver._seconds statement. But always it remain 0. But I get the correct value for _seconds in the PhoneReceiver class. The code is given below
public class PhoneReceiver extends PhoneStateListener {
Context context;
static boolean _callStarted = false;
long _callStartTime;
long _callEndTime;
long _callDuration;
long _minutes;
static long _seconds;
public PhoneReceiver(Context context) {
this.context = context;
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if ((state == TelephonyManager.CALL_STATE_OFFHOOK) && !_callStarted) {
_callStarted = !_callStarted;
_callStartTime = new Date().getTime();
Toast.makeText(context, "Stage 1: " + "Off Hook -> Boolean: "+_callStarted, Toast.LENGTH_LONG).show();
}
if ((state == TelephonyManager.CALL_STATE_IDLE) && _callStarted)
{
_callEndTime = new Date().getTime();
_callDuration = _callEndTime - _callStartTime;
_minutes = (_callDuration / 1000) / 60;
_seconds = (_callDuration / 1000) % 60;
Toast.makeText(context, "Stage 2: " + "IDLE State->Boolean: "+_callStarted, Toast.LENGTH_LONG).show();
}
}
}
Android Manifest.xml is given below
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.callerApppackage.callerapp">
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
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>
<!-- put this here so that even if the app is not running,
your app can be woken up if there is a change in phone
state -->
<receiver android:name=".PhoneStateReceiver">
<intent-filter>
<action
android:name=
"android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
PhonestateReciver Class is given below
public class PhoneStateReceiver extends BroadcastReceiver {
TelephonyManager manager;
PhoneReceiver myPhoneStateListener;
static boolean alreadyListening = false;
#Override
public void onReceive(Context context, Intent intent) {
myPhoneStateListener = new PhoneReceiver(context);
manager = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
//---do not add the listener more than once---
if (!alreadyListening) {
manager.listen(myPhoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
alreadyListening = true;
}
}
}
I hope I made it clear Thanking you all in advance for earlier reply.

boot_completed not working on Android 10 Q API level 29

I have an application that starts an Intent after the boot that works from Android 6 to Android 9 API level 28.
But this code does not work on Android 10 API level 29, Broadcast simply does not receive any events and does not run onReceive on MyClassBroadcastReceiver after the boot. Is there any extra permission on Android 10 or configuration that needs to be done?
Dry part of the example: Manifest:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.softniels.autostartonboot">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
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>
<service
android:name="com.softniels.autostartonboot.ForegroundService"
android:label="My Service">
<intent-filter>
<action android:name="com.softniels.autostartonboot.ForegroundService" />
</intent-filter>
</service>
<receiver
android:name=".StartMyServiceAtBootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
</application>
Here the part that doesn't run on Android 10.
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i("onReceive", "call onReceive ACTION_BOOT_COMPLETED");
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
I know that this may be old but I have faced the same problem and according to this:
https://developer.android.com/guide/components/activities/background-starts
The easiest solution I came up with was simply adding
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And setting up the receiver:
<receiver
android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
To the manifest.
Receiver code:
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
// Intent n = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
// n.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
// Intent.FLAG_ACTIVITY_CLEAR_TASK);
// context.startActivity(n);
Intent myIntent = new Intent(context, MainActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
}
}
Both options work. The only downside I see is that it takes rather a while for app to load (can be up to 10 seconds from my testings)
Leaving this here for other people if they encounter this as well.
This only applies to android 10 and up. There is a need to request "Display over other apps" permission
This requires drawing overlay, which can be done with:
if (!Settings.canDrawOverlays(getApplicationContext())) {
Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
Uri uri = Uri.fromParts("package", getPackageName(), null);
myIntent.setData(uri);
startActivityForResult(myIntent, REQUEST_OVERLAY_PERMISSIONS);
return;
}
Guess I found a 'solution' for me.
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
Log.e(TAG, "launching from special > API 28 (" + Build.VERSION.SDK_INT + ")"); // You have to schedule a Service
JobServiceScheduler jobServiceScheduler = new JobServiceScheduler(context);
boolean result = jobServiceScheduler.scheduleMainService(20L); // Time you will wait to launch
} else {
Log.e(TAG, "launching from normal < API 29"); // You can still launch an Activity
try {
Intent intentMain = new Intent(context, YourActivity.class);
intentMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT < 28) {
context.startService(intentMain);
} else {
context.startForegroundService(intentMain);
}
} catch (ActivityNotFoundException ex) {
Log.e(TAG, "ActivityNotFoundException" + ex.getLocalizedMessage());
}
}
}
boolean scheduleMainService(Long segundos) {
ComponentName serviceComponent = new ComponentName(context, YourService.class);
JobInfo.Builder builder = getCommonBuilder(serviceComponent, YOUR_SERVICE_JOB_ID);
builder.setMinimumLatency(TimeUnit.SECONDS.toMillis(segundos / 2)); // wait at least
builder.setOverrideDeadline(TimeUnit.SECONDS.toMillis(segundos)); // maximum delay
PersistableBundle extras = new PersistableBundle();
extras.putLong("time", segundos);
builder.setExtras(extras);
JobScheduler jobScheduler = getJobScheduler(context);
if (jobScheduler != null) {
jobScheduler.schedule(builder.build());
return true;
} else {
return false;
}
}
context.startActivity() is not launching, I solved it the following way:
private void restartApp( Context mContext) {
try {
long restartTime = 1000*5;
Intent intents = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intents, PendingIntent.FLAG_ONE_SHOT);
AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I solved it with this permission in the manifest:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And in the main activity :
if (!Settings.canDrawOverlays(getApplicationContext())) {
startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
}
The correct import for Settings is:android.provider
The first time the app boots the permission will be prompted for controlling which apps can draw on top of other apps, the next device will start the application will boot up using the typical broadcast receiver.
Here is the doc

My onReceive method get called multiple and trigger onCreate from my MainActivity (Wear)

I am fairly new to android. I am trying to send data from my tablet to my phone using a WearableListenerService. This part works well, I can see through logs that the data is sent. The problem is that I receive the data from the tablet in the Listener class and I have to transmit it to Mainactivity in order to update my Views. To do this I use a LocalBroadcaster and I implemented the onReceive method in my MainActivity. So when I give the order to send the data from the phone the onReceive gets called multiple time most of the time between 2 or 3 times and furthermore the activity is recreated because onCreate is triggered by this method (I don't know if this behavior is expected).
Here is the code:
DataLayerListenerService.java (Listener)
public class DataLayerListenerService extends WearableListenerService {
// Tag for Logcat
private static final String TAG = "DataLayerService";
private int notificationId = 001;
private String notif;
// Member for the Wear API handle
GoogleApiClient mGoogleApiClient;
#Override
public void onCreate() {
super.onCreate();
// Start the Wear API connection
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
}
//#Override
public void onDataChanged(DataEventBuffer dataEvents) {
Log.v(TAG, "onDataChanged: " + dataEvents);
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
Log.e(TAG, "DataItem Changed: " + event.getDataItem().toString() + "\n"
+ DataMapItem.fromDataItem(event.getDataItem()).getDataMap());
String path = event.getDataItem().getUri().getPath();
switch (path) {
case DataLayerCommons.NOTIFICATION_PATH:
Log.v(TAG, "Data Changed for NOTIF_PATH: " + event.getDataItem().toString());
DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
notif = dataMapItem.getDataMap().getString(DataLayerCommons.NOTIFICATION_KEY);
Intent intent = new Intent(NOTIFICATION_RECEIVED);
intent.putExtra(NOTIFICATION_RECEIVED, notif);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
break;
case DataLayerCommons.COUNT_PATH:
Log.v(TAG, "Data Changed for COUNT_PATH: " + event.getDataItem() + "\n"
+ "Count data = " + DataMapItem.fromDataItem(event.getDataItem())
.getDataMap().getInt(DataLayerCommons.COUNT_KEY));
break;
default:
Log.v(TAG, "Data Changed for unrecognized path: " + path);
break;
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
Log.v(TAG, "DataItem Deleted: " + event.getDataItem().toString());
}
}
}
}
Main Activity
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
public static final String NOTIFICATION_RECEIVED = "NOTIFICATION_RECEIVED";
private String notif="";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG,"OnCreate");
setContentView(R.layout.main_activity);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter(NOTIFICATION_RECEIVED));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "Got message!");
notif = intent.getStringExtra(NOTIFICATION_RECEIVED);
TextView warnView = findViewById(R.id.warningView);
warnView.setText(notif);
}
};
}
AndroidManifest.xml
<uses-feature android:name="android.hardware.type.watch" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat">
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="false" />
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<service android:name=".DataLayerListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:host="*"
android:pathPrefix="/notification"
android:scheme="wear" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<data
android:host="*"
android:pathPrefix="/start-activity"
android:scheme="wear" />
</intent-filter>
</service>
<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>
<intent-filter>
<action android:name="com.example.android.wearable.datalayer.EXAMPLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
Thanks for the help
I would suggest using Application class to store your Activity instead of BroadcastReceiver registering.
What I mean:
in Application class create a variable that stores your activity:
class MyApp extends Application {
public static MyActivity activity;
}
to link save into this variable current activity at onCreate and release while onDestroy.
Somehow:
public MyActivity extends Activity {
void onCreate() {
MyApp.activity = this;
}
void onDestroy() {
MyApp.activity = null;
}
void redraw() {
//redraw
}
}
inside the service do something like this:
class MyService extends WearableListenerService {
void onDataChanged() {
if (MyApp.activity != null) {
MyApp.activity.redraw()
}
}
}
do not forget to set application in the manifest:
<application
android:name=".MyApp"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat">

Android Broadcast receiver for call not working? (Marshmallow)

I am trying to display toast after receiving an call, I have implemented all necessary things needed to register broadcast receiver but it is not displaying toast. I am trying to run this program on Marshmallow device
MyCallReceiver.java -
package com.suhas.callreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
public class MyCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
// This code will execute when the phone has an incoming call
// get the phone number
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Toast.makeText(context, "Call from:" +incomingNumber, Toast.LENGTH_LONG).show();
Log.d("MyTrack call", "call receive");
} else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE))
{
Toast.makeText(context, "Detected call hangup event", Toast.LENGTH_LONG).show();
}
else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK)) {
// This code will execute when the call is disconnected
}
}
}
AndroidManifest.xml -
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.suhas.msgmanager">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
android:icon="#mipmap/msgis"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.suhas.msgmanager.MyDialog" android:launchMode="singleTask"
android:theme="#android:style/Theme.Translucent" />
<service android:name="com.example.suhas.msgmanager.ChatHeadService"></service>
<receiver android:name=".MyCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<activity android:name=".AddMessageActivity">
</activity>
</application>
</manifest>
I have one MainActivity with one default label saying Hello World.
In Case of Marshmallow Version, We have a concept called Runtime permission which is to be made inside Activity in order to work with the permission.
Runtime permission provides a way to ask user for particular permission at runtime while he runs activity for first time.
This are two things you have to specify :
//specify any constant number for permission
public final static int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 11;
// Specify following bit of code in OnCreate method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
}
}
//specify this method which will popup window asking user for permission at runtime
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_PHONE_STATE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
}
return;
}
}
}
this will provide a way to work with Marshmallow devices
You have given wrong package name in the receiver.
You should define receiver as below:
<receiver android:name="com.suhas.callreceiver.MyCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
In target API 23 or higher as per the Marshmallow the applications needs run time permission or manual in your device setting>> apps>> select your app>> permission
this link can help you
I successfully implemented in our App. Get the reference from here.
Call Receive Method
public class CallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Log.w("intent " , intent.getAction().toString());
TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener customPhoneListener = new MyPhoneStateListener();
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
Bundle bundle = intent.getExtras();
String phone_number = bundle.getString("incoming_number");
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
// String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
state = TelephonyManager.CALL_STATE_RINGING;
}
if (phone_number == null || "".equals(phone_number)) {
return;
}
customPhoneListener.onCallStateChanged(context, state, phone_number);
Toast.makeText(context, "Phone Number " + phone_number , Toast.LENGTH_SHORT).show();
}}
Listener Method
public class MyPhoneStateListener extends PhoneStateListener {
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;
public void onCallStateChanged(Context context, int state, String phoneNumber){
if(lastState == state){
//No change, debounce extras
return;
}
System.out.println("Number inside onCallStateChange : " + phoneNumber);
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
Toast.makeText(context, "Incoming Call Ringing " + phoneNumber, Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
Toast.makeText(context, "Outgoing Call Started " + phoneNumber, Toast.LENGTH_SHORT).show();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
//Went to idle- this is the end of a call. What type depends on previous state(s)
if(lastState == TelephonyManager.CALL_STATE_RINGING){
//Ring but no pickup- a miss
Toast.makeText(context, "Ringing but no pickup" + phoneNumber + " Call time " + callStartTime +" Date " + new Date() , Toast.LENGTH_SHORT).show();
}
else if(isIncoming){
Toast.makeText(context, "Incoming " + phoneNumber + " Call time " + callStartTime , Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(context, "outgoing " + phoneNumber + " Call time " + callStartTime +" Date " + new Date() , Toast.LENGTH_SHORT).show();
}
break;
}
lastState = state;
}} }
Get the reference for full solution

Can someone help me with Android RemoteControlClient?

I'm trying to get the RemoteControlClient set up so my app's music can be controlled by the widget that pops up on the lock screen (like SoundCloud, Google Play Music, and other music/video apps work). I'm not sure what's wrong with my code and why it isn't correctly hooking, but here's what I have so far...
A class called MusicService that tries to handle the updates to the RemoteControlClient
public class MusicService extends Service
{
public static final String ACTION_PLAY = "com.stfi.music.action.PLAY";
private RemoteController controller = null;
#Override
public void onCreate()
{
super.onCreate();
System.out.println("Creating the service.");
if(controller == null)
{
controller = new RemoteController();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
String action = intent.getAction();
System.out.println("Got an action of " + action);
/* Logic to get my Song cur */
controller.register(this);
controller.updateMetaData(cur);
return START_STICKY;
}
#Override
public void onDestroy()
{
super.onDestroy();
System.out.println("Destorying MusicService");
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
This uses a class I have called RemoteController which houses my RemoteControlClient.
public class RemoteController {
private RemoteControlClient remoteControlClient;
private Bitmap dummyAlbumArt;
public void register(Context context)
{
if (remoteControlClient == null)
{
System.out.println("Trying to register it.");
dummyAlbumArt = BitmapFactory.decodeResource(context.getResources(), R.drawable.dummy_album_art);
AudioManager audioManager = (AudioManager) context.getSystemService(context.AUDIO_SERVICE);
ComponentName myEventReceiver = new ComponentName(context.getPackageName(), MediaButtonReceiver.class.getName());
audioManager.registerMediaButtonEventReceiver(myEventReceiver);
// build the PendingIntent for the remote control client
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(myEventReceiver);
// create and register the remote control client
PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0);
remoteControlClient = new RemoteControlClient(mediaPendingIntent);
remoteControlClient.setTransportControlFlags(RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
| RemoteControlClient.FLAG_KEY_MEDIA_NEXT
| RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS
| RemoteControlClient.FLAG_KEY_MEDIA_PLAY
| RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
);
audioManager.registerRemoteControlClient(remoteControlClient);
}
}
/**
* Update the state of the remote control.
*/
public void updateState(boolean isPlaying)
{
if(remoteControlClient != null)
{
if (isPlaying)
{
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
}
else
{
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
}
}
}
/**
* Updates the state of the remote control to "stopped".
*/
public void stop()
{
if (remoteControlClient != null)
{
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED);
}
}
public void updateMetaData(Song song)
{
if (remoteControlClient != null && song != null)
{
System.out.println("Updating metadata");
MetadataEditor editor = remoteControlClient.editMetadata(true);
editor.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, dummyAlbumArt);
editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, (long)1000);
editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, "Artist");
editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, "Title");
editor.apply();
updateState(true);
}
}
/**
* Release the remote control.
*/
public void release() {
remoteControlClient = null;
}
}
Every time I want to update the widget, I call startService(new Intent(MusicService.ACTION_PLAY));. It looks like it correctly creates the service, and it always gets to the point where it says "Updating metadata", but for some reason when I lock my screen and unlock it, I don't see any widget on my lock screen.
Below is the important parts of my manifest as well, seeing as that could somehow cause the issue...
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stfi"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />
<application
android:hardwareAccelerated="true"
android:allowBackup="true"
android:icon="#drawable/stfi"
android:label="#string/app_name"
android:largeHeap="true"
android:theme="#style/MyActionBarTheme" >
<meta-data
android:name="android.app.default_searchable"
android:value=".activities.SearchActivity" />
<activity
android:name=".StartingToFeelIt"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
...other activities listed
<service
android:name=".helpers.MyNotificationService"
android:enabled="true"
android:label="MyNotificationServiceLabel" >
</service>
<service
android:name=".music.MusicService"
android:exported="false" >
<intent-filter>
<action android:name="com.stfi.music.action.PLAY" />
</intent-filter>
<intent-filter>
<action android:name="com.example.android.musicplayer.action.URL" />
<data android:scheme="http" />
</intent-filter>
</service>
<receiver
android:name=".music.MediaButtonReceiver"
android:exported="false" >
</receiver>
</application>
Right now my MediaButtonReceiver doesn't really do much of anything. I'm just trying to get the hooks set up. If you want, this is my MediaButtonReceiver class...
public class MediaButtonReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
System.out.println("Receiving something.");
if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON))
{
final KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event != null && event.getAction() == KeyEvent.ACTION_UP)
{
if (event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)
{
System.out.println("You clicked pause.");
}
else if(event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY)
{
System.out.println("You clicked play.");
}
else if (event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_NEXT)
{
System.out.println("You clicked next.");
}
else if (event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PREVIOUS)
{
System.out.println("You clicked previous.");
}
}
}
}
}
if you can't see remoteControlClient on lock screen you must implement audio focus. You can look here

Categories