I have an app which plays audio. The thing is, when I get a call on my phone while I am interacting with the app, the audio continues to play. This becomes a problem because the audio makes it hard to understand what the person is saying. Is there any method that gets called when the user is talking on a call? That way I can mute my audio there. I have thoroughly researched the activity life cycle, but cannot find anything that will help me with this issue. I really appreciate all of your expert advice.
I have tried to put this code into my BaseActivity which gets extended by all other activities:
PhoneStateListener phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
//Incoming call: Pause music
TwentySeconds.stopTimer();
Intent i = new Intent(BaseActivity.this, FinishedBeforeTimer.class);
startActivity(i);
Toast.makeText(BaseActivity.this, "INCOMING CALL", Toast.LENGTH_SHORT).show();
} else if(state == TelephonyManager.CALL_STATE_IDLE) {
//Not in call: Play music
} else if(state == TelephonyManager.CALL_STATE_OFFHOOK) {
//A call is dialing, active or on hold
TwentySeconds.stopTimer();
Intent i = new Intent(BaseActivity.this, FinishedBeforeTimer.class);
startActivity(i);
Toast.makeText(BaseActivity.this, "DIALING", Toast.LENGTH_SHORT).show();
}
But then the strangest thing happens. When I call the my phone, the phone I am calling with says that I can't call my phone. I am confused as to what to do now, I really appreciate your time.
Thanks,
Rich
Related
I am trying to make a simple android app in which there is a toast message containing the number of the incoming call. I have stored the number in a string variable. When I display just the toast, it works fine but before the toast, if I add a simple if condition comparing the number to another string, the app quits. The required permissions are given. Can someone help me?
This Works:
public void onReceive(Context context, Intent intent) {
String incomingNumber = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
Toast.makeText(context, incomingNumber, Toast.LENGTH_LONG).show();
}
This Does not Work (App quits)
public void onReceive(Context context, Intent intent) {
String incomingNumber = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(incomingNumber.equals("+919999999999"))
{
Toast.makeText(context, "Call from Mom", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(context, incomingNumber, Toast.LENGTH_LONG).show();
}
}
It sounds a little silly but I just wrapped my "if" condition in a try-catch block and it solved the problem. I am not used to programming in JAVA so it took me a lot to figure out this simple thing. Thank You All for providing me with suggestions :)
I'm developing an app which detecting BLE signal from specific beacons continuously. The content of the signal will be changed if the batteries of these beacons are going to die. As a result, I can prompt the user that which beacon is going to die and he or she may need to change or recharge its battery.
I put the detection in Service and in general situation it just works perfectly. No matter the app is in foreground or background, the app will send a notification to the user with vibration and sound as long as the app detects abnormal signals. The following is the setting of Notification in my code:
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle(getResources().getString(R.string.app_name))
.setContentText(getResources().getString(R.string.app_name))
.setAutoCancel(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(contentIntent)
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
.setSound(sound)
.setVibrate(new long[]{INTERVAL_VIBRATE, INTERVAL_VIBRATE});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
builder.setPriority(Notification.PRIORITY_DEFAULT);
builder.setFullScreenIntent(contentIntent, true);
}
if (!TextUtils.isEmpty(message)) {
builder.setContentText(message);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
Here comes the problem:
When the user is talking on the phone he or she will receive notifications, as well as vibrations. But cannot receive notification sound, I would like to know if there is a way to accomplish this feature.
I finally figure out an alternative solution: use ToneGenerator to play sound.
In this case, when I use only Notification, the sound of the notification disappeared when I'm on phone, even though the vibration still works, I want to find an advanced way to prompt the user that he or she is needed to beware of something.
So, in my service, I add PhoneStateListener to monitor my phone state
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener phoneStateListener = createPhoneStateListener();
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
my createPhoneStateListener() method:
private PhoneStateListener createPhoneStateListener() {
return new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch(state){
case TelephonyManager.CALL_STATE_IDLE :
isUserSpeakingOnPhone = false;
break;
case TelephonyManager.CALL_STATE_RINGING :
isUserSpeakingOnPhone = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK :
isUserSpeakingOnPhone = true;
break;
}
super.onCallStateChanged(state, incomingNumber);
}
};
}
I use a boolean isUserSpeakingOnPhone to determine if I need to start an IntentService which called PlayToneService to generate tones and play at the same time when I need to push a notification:
if (isUserSpeakingOnPhone) {
Intent playTone = new Intent(this, PlayToneService.class);
startService(playTone);
}
PlayToneService.class:
public class PlayToneService extends IntentService {
public PlayToneService() {
super(PlayToneService.class.getName());
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
// play tone
try {
ToneGenerator toneGenerator= new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
toneGenerator.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200);
Thread.sleep(200);
toneGenerator.stopTone();
toneGenerator.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Then, when the user is speaking on phone and receives a notification, instead of a notfication sound, he/she will hear the "beep" sound from device's speaker. When the user is not speaking on phone, the notification sound will work as usual.
I am working on a messaging app, it sends user notification when he is on a different activtyon my app or is on another app but if the user is on MessagingActivity.java it just updates the chat history and does not send any notifications which is perfectly fine, but the problem arises when the user is on MessagingActivity.java meanwhile an email or something else happen user leaves the MessagingActivity.java open and checks that app if in the meantime a message comes user does not receive any notifications
public void parseRequest(Bundle extras) {
if (extras.containsKey("for") && extras.containsKey("recipientID")) {
if (Integer.parseInt(extras.getString("recipientID")) == M.getID(this)) {
switch (extras.getString("for")) {
case "chat":
if (isRunning("MessagingActivity")) {
Intent intent = new Intent("update_messages_list");
intent.putExtra("data", extras);
sendBroadcast(intent);
} else {
Intent resultIntent = new Intent(this, MessagingActivity.class);
resultIntent.putExtra("conversationID", Integer.parseInt(extras.getString("conversationID")));
resultIntent.putExtra("recipientID", Integer.parseInt(extras.getString("ownerID")));
M.showNotification(getApplicationContext(), resultIntent,
extras.getString("ownerUsername"),
extras.getString("message"),
Integer.parseInt(extras.getString("conversationID")));
}
Let me know how you are checking that your MessageActivity is Running i.e. functioning of isRunning("MessagingActivity") method. If you are setting any global boolean variable for checking this and making isRunning value false in onDestroy() method of that activity then, according to life cycle of Activity it is not called until your activity is finished i.e. in your case user just switching from MessageActivity to Mail .
I am by no means an expert, but you could just set a boolean variable by overriding the Activity's onPause() and onResume() events.
Simply set msgActivityActive to true in onResume(), false in onPause(), and change your call to:
if (isRunning("MessagingActivity") && msgActivityActive)
Can i use loops in READ_PHONE_STATE event?
I want to work loop when phone started ringing to end ringing.
also same the case of user start calling to disconnect the call.
This is my broadcast receiver class
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
while (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
//wate for user shaking the phone
//call ansered
}
while (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
//do something while phone answered
//I want to work something during the calling time
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE) {
//do some
}
}
}
You've already done all the necessary research, it's just probably not 'looping' that you want to do.
What you need is to start something when the phone rings, and stops when it stops ringing. Same for in-call.
To handle events while the phone is ringing, start doing something on CALL_STATE_RINGING, then wait for either CALL_STATE_OFFHOOK or CALL_STATE_IDLE to know when ringing has stopped.
Same for while the user is making a call: start something when your receiver receives CALL_STATE_OFFHOOK and stop when it receives CALL_STATE_IDLE.
I would have your BroadcastReceiver send a message (or call a function) in your UI thread to do what you need to do, then notify when call state has changed.
You don't need to be looping during those intervals. You just want to start/stop doing something at the right time. You can always put some backup security (eg: if phone rang and nothing happened for 3 mins, I stop doing something) to make sure you won't keep running things when you don't want to be.
You can detect when an incoming call is picked/dropped, and when an outgoing call is started/stopped so implement your "looping" logic in the associated callbacks. I've included comments in the code below:
public abstract class PhoneCallReceiver extends BroadcastReceiver {
static CallStartEndDetector listener;
#Override
public void onReceive(Context context, Intent intent) {
savedContext = context;
if(listener == null){
listener = new CallStartEndDetector();
}
TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
}
public class CallStartEndDetector extends PhoneStateListener {
int lastState = TelephonyManager.CALL_STATE_IDLE;
boolean isIncoming;
public PhonecallStartEndDetector() {}
//Incoming call- IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when hung up
//Outgoing call- from IDLE to OFFHOOK when dialed out, to IDLE when hunged up
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
if(lastState == state){
//No change
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
//incoming call started
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//Transition of ringing->offhook are pickups of incoming calls. Nothing down on them
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
//outgoing call started
}
break;
case TelephonyManager.CALL_STATE_IDLE:
//End of call(Idle). The type depends on the previous state(s)
if(lastState == TelephonyManager.CALL_STATE_RINGING){
// missed call
}
else if(isIncoming){
//incoming call ended
}
else{
//outgoing call ended
}
break;
}
lastState = state;
}
}
}
I'm making music player app with simple functionality. But when I listen music on my phone with Android 6, sometimes music stops playing until I turn on display again with power button. Then next song is playing, so it seems like it's problem with loading next song. I tried to write new app just to test it out, for this purpose I used this tutorial:
https://code.tutsplus.com/tutorials/background-audio-in-android-with-mediasessioncompat--cms-27030
To this example I added ArrayList with paths to songs. In mediaPlayer onCompletionListener I increase track counter and load new song to media player.
My code:
private void initMediaPlayer() {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setVolume(1.0f, 1.0f);
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
onTrackCompletion();
}
});
private void onTrackCompletion()
{
NextTrack();
Play();
}
private void NextTrack()
{
playlistPosition++;
if (playlistPosition == playlists.get(playlistCurrent).size){
playlistPosition = 0;
}
sendAction(ACTION_TRACK_NEXT);
if(mMediaPlayer.isPlaying()){
Pause();
}
loadSong();
Play();
}
private void loadSong()
{
String path = playlists.get(playlistCurrent).getPath(playlistPosition);
if(path == null || path == "")
{
return;
}
try
{
try
{
mMediaPlayer.setDataSource(path);
} catch( IllegalStateException e ) {
mMediaPlayer.release();
initMediaPlayer();
mMediaPlayer.setDataSource(path);
}
initMediaSessionMetadata();
} catch (IOException e) {
return;
}
try {
mMediaPlayer.prepare();
} catch (IOException e) {}
sendTrackData();
}
I don't know anymore why this doesn't work. In manifest I have WAKE_LOCK permission. I also set wake lock for Media player.
Edit:
Today I tried to move loading song into onPlayFromMediaId. I made broadcast from AutoActivity where is Media player to Main Activity and send back onPlayFromMediaId with path to song. But seems like this doesn't work either.I also find out that changing volume with buttons also wake up app.
Edit2:
I made many tests and added debug string in many places in code. And I found out that app stops at mediaplayer.prepare() until I trigger any action on phone (turn on display, volume up/down, click headset button). But I don't know how to fix this bug. I tried to use prepareAsync, but didn't help.
Unless you use foreground service, the system will kill your process and mediaplayer will stop.
below is a part from from a foreground service ( notification example).
builder.setContentTitle(aMessage) // required
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(this.getString(R.string.app_name)) // required
.setAutoCancel(false)
.setContentIntent(pendingIntent)
.setVibrate(new long[]{0L})
.setPriority(Notification.PRIORITY_HIGH);
int mId = 1489;
startForeground(mId, builder.build());
The above code is tested and working fine.