Added answer/hangup buttons to incoming call notifications

This commit is contained in:
Sylvain Berfini 2018-11-16 15:07:47 +01:00
parent 15af61c83a
commit 82a81e5d5d
11 changed files with 183 additions and 143 deletions

View file

@ -31,7 +31,8 @@ Group changes to describe their impact on the project, as follows:
- Support of H265 codec. - Support of H265 codec.
- Use TextureView instead of GL2JNIView, easier to use and will fix issues. - Use TextureView instead of GL2JNIView, easier to use and will fix issues.
- Send SMS to invite your friends in using Linphone. - Send SMS to invite your friends in using Linphone.
- Reply to received chat message in notification - Reply to received chat message in notification.
- Answer or hangup incoming call in notification.
## [4.0.1] - 2018-06-26 ## [4.0.1] - 2018-06-26

View file

@ -504,7 +504,7 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou
if (call != null) { if (call != null) {
call.enableCamera(enable); call.enableCamera(enable);
if (mServiceContext.getResources().getBoolean(R.bool.enable_call_notification)) if (mServiceContext.getResources().getBoolean(R.bool.enable_call_notification))
LinphoneService.instance().refreshIncallIcon(mLc.getCurrentCall()); LinphoneService.instance().displayCallNotification(mLc.getCurrentCall());
} }
} }

View file

@ -82,17 +82,12 @@ public final class LinphoneService extends Service {
*/ */
public static final String START_LINPHONE_LOGS = " ==== Phone information dump ===="; public static final String START_LINPHONE_LOGS = " ==== Phone information dump ====";
public static final int IC_LEVEL_ORANGE = 0; public static final int IC_LEVEL_ORANGE = 0;
/*private static final int IC_LEVEL_GREEN=1;
private static final int IC_LEVEL_RED=2;*/
//public static final int IC_LEVEL_OFFLINE=3;
private static LinphoneService instance; private static LinphoneService instance;
private final static int NOTIF_ID = 1; private final static int NOTIF_ID = 1;
private final static int INCALL_NOTIF_ID = 2;
private final static int CUSTOM_NOTIF_ID = 4; private final static int CUSTOM_NOTIF_ID = 4;
private final static int MISSED_NOTIF_ID = 5; private final static int MISSED_NOTIF_ID = 5;
private final static int SAS_NOTIF_ID = 6;
public static boolean isReady() { public static boolean isReady() {
return instance != null && instance.mTestDelayElapsed; return instance != null && instance.mTestDelayElapsed;
@ -114,9 +109,7 @@ public final class LinphoneService extends Service {
private NotificationManager mNM; private NotificationManager mNM;
private Notification mNotif; private Notification mNotif;
private Notification mIncallNotif;
private Notification mCustomNotif; private Notification mCustomNotif;
private Notification mSasNotif;
private PendingIntent mNotifContentIntent; private PendingIntent mNotifContentIntent;
private String mNotificationTitle; private String mNotificationTitle;
private boolean mDisableRegistrationStatus; private boolean mDisableRegistrationStatus;
@ -131,7 +124,7 @@ public final class LinphoneService extends Service {
int numberOfUnreadMessage; int numberOfUnreadMessage;
} }
private HashMap<String, Notified> mChatNotifMap; private HashMap<String, Notified> mChatNotifMap, mCallNotifMap;
private int mLastNotificationId; private int mLastNotificationId;
public void setCurrentlyDisplayedChatRoom(String address) { public void setCurrentlyDisplayedChatRoom(String address) {
@ -327,6 +320,10 @@ public final class LinphoneService extends Service {
return; return;
} }
if (getResources().getBoolean(R.bool.enable_call_notification)) {
displayCallNotification(call);
}
if (state == Call.State.IncomingReceived) { if (state == Call.State.IncomingReceived) {
if (!LinphoneManager.getInstance().getCallGsmON()) if (!LinphoneManager.getInstance().getCallGsmON())
onIncomingReceived(); onIncomingReceived();
@ -335,7 +332,6 @@ public final class LinphoneService extends Service {
if (state == State.End || state == State.Released || state == State.Error) { if (state == State.End || state == State.Released || state == State.Error) {
if (LinphoneManager.isInstanciated() && LinphoneManager.getLc() != null && LinphoneManager.getLc().getCallsNb() == 0) { if (LinphoneManager.isInstanciated() && LinphoneManager.getLc() != null && LinphoneManager.getLc().getCallsNb() == 0) {
if (LinphoneActivity.isInstanciated() && LinphoneActivity.instance().getStatusFragment() != null) { if (LinphoneActivity.isInstanciated() && LinphoneActivity.instance().getStatusFragment() != null) {
removeSasNotification();
LinphoneActivity.instance().getStatusFragment().setisZrtpAsk(false); LinphoneActivity.instance().getStatusFragment().setisZrtpAsk(false);
} }
} }
@ -367,15 +363,6 @@ public final class LinphoneService extends Service {
Notification notif = Compatibility.createMissedCallNotification(instance, getString(R.string.missed_calls_notif_title), body, intent); Notification notif = Compatibility.createMissedCallNotification(instance, getString(R.string.missed_calls_notif_title), body, intent);
notifyWrapper(MISSED_NOTIF_ID, notif); notifyWrapper(MISSED_NOTIF_ID, notif);
} }
if (state == State.StreamsRunning) {
// Workaround bug current call seems to be updated after state changed to streams running
if (getResources().getBoolean(R.bool.enable_call_notification))
refreshIncallIcon(call);
} else {
if (getResources().getBoolean(R.bool.enable_call_notification))
refreshIncallIcon(LinphoneManager.getLc().getCurrentCall());
}
} }
@Override @Override
@ -387,10 +374,6 @@ public final class LinphoneService extends Service {
@Override @Override
public void onRegistrationStateChanged(Core lc, ProxyConfig cfg, RegistrationState state, String smessage) { public void onRegistrationStateChanged(Core lc, ProxyConfig cfg, RegistrationState state, String smessage) {
// if (instance == null) {
// Log.i("Service not ready, discarding registration state change to ",state.toString());
// return;
// }
if (!mDisableRegistrationStatus) { if (!mDisableRegistrationStatus) {
if (displayServiceNotification() && state == RegistrationState.Ok && LinphoneManager.getLc().getDefaultProxyConfig() != null && LinphoneManager.getLc().getDefaultProxyConfig().getState() == RegistrationState.Ok) { if (displayServiceNotification() && state == RegistrationState.Ok && LinphoneManager.getLc().getDefaultProxyConfig() != null && LinphoneManager.getLc().getDefaultProxyConfig().getState() == RegistrationState.Ok) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered); sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
@ -446,6 +429,7 @@ public final class LinphoneService extends Service {
super.onCreate(); super.onCreate();
mLastNotificationId = 8; // To not interfere with other notifs ids mLastNotificationId = 8; // To not interfere with other notifs ids
mChatNotifMap = new HashMap<>(); mChatNotifMap = new HashMap<>();
mCallNotifMap = new HashMap<>();
setupActivityMonitor(); setupActivityMonitor();
// In case restart after a crash. Main in LinphoneActivity // In case restart after a crash. Main in LinphoneActivity
@ -469,7 +453,7 @@ public final class LinphoneService extends Service {
} }
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.cancel(INCALL_NOTIF_ID); // in case of crash the icon is not removed mNM.cancelAll();
Compatibility.createNotificationChannels(this); Compatibility.createNotificationChannels(this);
Intent notifIntent = new Intent(this, incomingReceivedActivity); Intent notifIntent = new Intent(this, incomingReceivedActivity);
@ -521,85 +505,79 @@ public final class LinphoneService extends Service {
mOverlay = null; mOverlay = null;
} }
private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE} public void displayCallNotification(Call call) {
if (call == null) return;
private IncallIconState mCurrentIncallIconState = IncallIconState.IDLE; Address address = call.getRemoteAddress();
String addressAsString = address.asStringUriOnly();
Notified notif = mCallNotifMap.get(addressAsString);
private synchronized void setIncallIcon(IncallIconState state) { if (notif == null) {
if (state == mCurrentIncallIconState) return; notif = new Notified();
mCurrentIncallIconState = state; notif.notificationId = mLastNotificationId;
mLastNotificationId += 1;
mCallNotifMap.put(addressAsString, notif);
}
int notificationTextId = 0; int notificationTextId = 0;
int inconId = 0; int inconId = 0;
switch (call.getState()) {
switch (state) { case Released:
case IDLE: case End:
if (!displayServiceNotification()) { if (!displayServiceNotification()) {
stopForegroundCompat(INCALL_NOTIF_ID); stopForegroundCompat(notif.notificationId);
} else { } else {
mNM.cancel(INCALL_NOTIF_ID); mNM.cancel(notif.notificationId);
} }
return; mCallNotifMap.remove(addressAsString);
case INCALL:
inconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_active;
break; break;
case PAUSE: case Paused:
case PausedByRemote:
case Pausing:
inconId = R.drawable.topbar_call_notification; inconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_paused; notificationTextId = R.string.incall_notif_paused;
break; break;
case VIDEO: default:
if (call.getCurrentParams().videoEnabled()) {
inconId = R.drawable.topbar_videocall_notification; inconId = R.drawable.topbar_videocall_notification;
notificationTextId = R.string.incall_notif_video; notificationTextId = R.string.incall_notif_video;
} else {
inconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_active;
}
break; break;
default:
throw new IllegalArgumentException("Unknown state " + state);
} }
if (LinphoneManager.getLc().getCallsNb() == 0) {
return;
}
Call call = LinphoneManager.getLc().getCalls()[0];
Address address = call.getRemoteAddress();
LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address); LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address);
Uri pictureUri = contact != null ? contact.getPhotoUri() : null; Uri pictureUri = contact != null ? contact.getPhotoUri() : null;
Bitmap bm = null; Bitmap bm;
try { try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), pictureUri); bm = MediaStore.Images.Media.getBitmap(getContentResolver(), pictureUri);
} catch (Exception e) { } catch (Exception e) {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.avatar); bm = BitmapFactory.decodeResource(getResources(), R.drawable.avatar);
} }
String name = address.getDisplayName() == null ? address.getUsername() : address.getDisplayName(); String name = LinphoneUtils.getAddressDisplayName(address);
boolean showActions = call.getState() == State.IncomingReceived || call.getState() == State.IncomingEarlyMedia;
Intent notifIntent = new Intent(this, incomingReceivedActivity); Intent notifIntent = new Intent(this, incomingReceivedActivity);
notifIntent.putExtra("Notification", true); notifIntent.putExtra("Notification", true);
mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mIncallNotif = Compatibility.createInCallNotification(getApplicationContext(), mNotificationTitle, getString(notificationTextId), inconId, bm, name, mNotifContentIntent); Notification notification = Compatibility.createInCallNotification(getApplicationContext(), notif.notificationId, showActions, mNotificationTitle, getString(notificationTextId), inconId, bm, name, mNotifContentIntent);
if (!displayServiceNotification()) { if (!displayServiceNotification()) {
startForegroundCompat(INCALL_NOTIF_ID, mIncallNotif); startForegroundCompat(notif.notificationId, notification);
} else { } else {
notifyWrapper(INCALL_NOTIF_ID, mIncallNotif); notifyWrapper(notif.notificationId, notification);
} }
} }
public void refreshIncallIcon(Call currentCall) { public String getSipUriForCallNotificationId(int notificationId) {
Core lc = LinphoneManager.getLc(); for (String addr : mCallNotifMap.keySet()) {
if (currentCall != null) { if (mCallNotifMap.get(addr).notificationId == notificationId) {
if (currentCall.getCurrentParams().videoEnabled() && currentCall.cameraEnabled()) { return addr;
// checking first current params is mandatory
setIncallIcon(IncallIconState.VIDEO);
} else {
setIncallIcon(IncallIconState.INCALL);
} }
} else if (lc.getCallsNb() == 0) {
setIncallIcon(IncallIconState.IDLE);
} else if (lc.getConference() != null) {
setIncallIcon(IncallIconState.INCALL);
} else {
setIncallIcon(IncallIconState.PAUSE);
} }
return null;
} }
@Deprecated @Deprecated
@ -719,10 +697,6 @@ public final class LinphoneService extends Service {
notifyWrapper(NOTIF_ID, mNotif); notifyWrapper(NOTIF_ID, mNotif);
} }
public void removeSasNotification() {
mNM.cancel(SAS_NOTIF_ID);
}
private static final Class<?>[] mSetFgSign = new Class[]{boolean.class}; private static final Class<?>[] mSetFgSign = new Class[]{boolean.class};
private static final Class<?>[] mStartFgSign = new Class[]{ private static final Class<?>[] mStartFgSign = new Class[]{
int.class, Notification.class}; int.class, Notification.class};
@ -884,11 +858,7 @@ public final class LinphoneService extends Service {
// Make sure our notification is gone. // Make sure our notification is gone.
stopForegroundCompat(NOTIF_ID); stopForegroundCompat(NOTIF_ID);
mNM.cancel(INCALL_NOTIF_ID); mNM.cancelAll();
for (Notified notif : mChatNotifMap.values()) {
mNM.cancel(notif.notificationId);
}
// This will prevent the app from crashing if the service gets killed in background mode // This will prevent the app from crashing if the service gets killed in background mode
if (LinphoneActivity.isInstanciated()) { if (LinphoneActivity.isInstanciated()) {

View file

@ -187,7 +187,6 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList
public void onCallStateChanged(Core lc, final Call call, Call.State state, String message) { public void onCallStateChanged(Core lc, final Call call, Call.State state, String message) {
if (LinphoneManager.getLc().getCallsNb() == 0) { if (LinphoneManager.getLc().getCallsNb() == 0) {
if (status != null) { if (status != null) {
LinphoneService.instance().removeSasNotification();
status.setisZrtpAsk(false); status.setisZrtpAsk(false);
} }
finish(); finish();

View file

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import android.Manifest; import android.Manifest;
import android.app.KeyguardManager; import android.app.KeyguardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
@ -199,8 +200,9 @@ public class CallIncomingActivity extends LinphoneGenericActivity {
public void onCallStateChanged(Core lc, Call call, State state, String message) { public void onCallStateChanged(Core lc, Call call, State state, String message) {
if (call == mCall && State.End == state) { if (call == mCall && State.End == state) {
finish(); finish();
} } else if (state == State.Connected) {
if (state == State.StreamsRunning) { startActivity(new Intent(CallIncomingActivity.this, CallActivity.class));
} else if (state == State.StreamsRunning) {
Log.e("CallIncommingActivity - onCreate - State.StreamsRunning - speaker = " + LinphoneManager.getInstance().isSpeakerEnabled()); Log.e("CallIncommingActivity - onCreate - State.StreamsRunning - speaker = " + LinphoneManager.getInstance().isSpeakerEnabled());
// The following should not be needed except some devices need it (e.g. Galaxy S). // The following should not be needed except some devices need it (e.g. Galaxy S).
LinphoneManager.getInstance().enableSpeaker(LinphoneManager.getInstance().isSpeakerEnabled()); LinphoneManager.getInstance().enableSpeaker(LinphoneManager.getInstance().isSpeakerEnabled());

View file

@ -16,7 +16,11 @@ import android.view.ViewTreeObserver;
import org.linphone.R; import org.linphone.R;
import org.linphone.receivers.NotificationBroadcastReceiver; import org.linphone.receivers.NotificationBroadcastReceiver;
import static org.linphone.compatibility.Compatibility.INTENT_ANSWER_CALL_NOTIF_ACTION;
import static org.linphone.compatibility.Compatibility.INTENT_CALL_ID;
import static org.linphone.compatibility.Compatibility.INTENT_HANGUP_CALL_NOTIF_ACTION;
import static org.linphone.compatibility.Compatibility.INTENT_NOTIF_ID; import static org.linphone.compatibility.Compatibility.INTENT_NOTIF_ID;
import static org.linphone.compatibility.Compatibility.INTENT_REPLY_NOTIF_ACTION;
import static org.linphone.compatibility.Compatibility.KEY_TEXT_REPLY; import static org.linphone.compatibility.Compatibility.KEY_TEXT_REPLY;
/* /*
@ -42,12 +46,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
public class ApiTwentyFourPlus { public class ApiTwentyFourPlus {
public static Notification createRepliedNotification(Context context, String reply) { public static Notification createRepliedNotification(Context context, String reply) {
Notification repliedNotification = new Notification.Builder(context) return new Notification.Builder(context)
.setSmallIcon(R.drawable.topbar_chat_notification) .setSmallIcon(R.drawable.topbar_chat_notification)
.setContentText(context.getString(R.string.notification_replied_label).replace("%s", reply)) .setContentText(context.getString(R.string.notification_replied_label).replace("%s", reply))
.build(); .build();
return repliedNotification;
} }
public static Notification createMessageNotification(Context context, int notificationId, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) { public static Notification createMessageNotification(Context context, int notificationId, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
@ -62,7 +64,7 @@ public class ApiTwentyFourPlus {
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build(); RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build();
Intent replyIntent = new Intent(context, NotificationBroadcastReceiver.class); Intent replyIntent = new Intent(context, NotificationBroadcastReceiver.class);
replyIntent.setAction(context.getPackageName() + ".REPLY_ACTION"); replyIntent.setAction(INTENT_REPLY_NOTIF_ACTION);
replyIntent.putExtra(INTENT_NOTIF_ID, notificationId); replyIntent.putExtra(INTENT_NOTIF_ID, notificationId);
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context, PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context,
@ -71,10 +73,10 @@ public class ApiTwentyFourPlus {
Notification.Action action = new Notification.Action.Builder(R.drawable.chat_send_over, Notification.Action action = new Notification.Action.Builder(R.drawable.chat_send_over,
context.getString(R.string.notification_reply_label), replyPendingIntent) context.getString(R.string.notification_reply_label), replyPendingIntent)
.addRemoteInput(remoteInput) .addRemoteInput(remoteInput)
.setAllowGeneratedReplies(true)
.build(); .build();
Notification notif; return new Notification.Builder(context)
notif = new Notification.Builder(context)
.setContentTitle(title) .setContentTitle(title)
.setContentText(msg) .setContentText(msg)
.setSmallIcon(R.drawable.topbar_chat_notification) .setSmallIcon(R.drawable.topbar_chat_notification)
@ -91,7 +93,44 @@ public class ApiTwentyFourPlus {
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led))
.addAction(action) .addAction(action)
.build(); .build();
}
return notif; public static Notification createInCallNotification(Context context,
int callId, boolean showActions, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
Notification.Builder builder = new Notification.Builder(context)
.setContentTitle(contactName)
.setContentText(msg)
.setSmallIcon(iconID)
.setAutoCancel(false)
.setContentIntent(intent)
.setLargeIcon(contactIcon)
.setCategory(Notification.CATEGORY_CALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setPriority(Notification.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setColor(context.getColor(R.color.notification_color_led));
if (showActions) {
Intent hangupIntent = new Intent(context, NotificationBroadcastReceiver.class);
hangupIntent.setAction(INTENT_HANGUP_CALL_NOTIF_ACTION);
hangupIntent.putExtra(INTENT_CALL_ID, callId);
PendingIntent hangupPendingIntent = PendingIntent.getBroadcast(context,
callId, hangupIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent answerIntent = new Intent(context, NotificationBroadcastReceiver.class);
answerIntent.setAction(INTENT_ANSWER_CALL_NOTIF_ACTION);
answerIntent.putExtra(INTENT_CALL_ID, callId);
PendingIntent answerPendingIntent = PendingIntent.getBroadcast(context,
callId, answerIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(R.drawable.call_hangup, context.getString(R.string.notification_call_hangup_label), hangupPendingIntent);
builder.addAction(R.drawable.call_audio_start, context.getString(R.string.notification_call_answer_label), answerPendingIntent);
}
return builder.build();
} }
} }

View file

@ -17,7 +17,11 @@ import org.linphone.R;
import org.linphone.mediastream.Log; import org.linphone.mediastream.Log;
import org.linphone.receivers.NotificationBroadcastReceiver; import org.linphone.receivers.NotificationBroadcastReceiver;
import static org.linphone.compatibility.Compatibility.INTENT_ANSWER_CALL_NOTIF_ACTION;
import static org.linphone.compatibility.Compatibility.INTENT_CALL_ID;
import static org.linphone.compatibility.Compatibility.INTENT_HANGUP_CALL_NOTIF_ACTION;
import static org.linphone.compatibility.Compatibility.INTENT_NOTIF_ID; import static org.linphone.compatibility.Compatibility.INTENT_NOTIF_ID;
import static org.linphone.compatibility.Compatibility.INTENT_REPLY_NOTIF_ACTION;
import static org.linphone.compatibility.Compatibility.KEY_TEXT_REPLY; import static org.linphone.compatibility.Compatibility.KEY_TEXT_REPLY;
/* /*
@ -42,12 +46,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@TargetApi(26) @TargetApi(26)
public class ApiTwentySixPlus { public class ApiTwentySixPlus {
public static Notification createRepliedNotification(Context context, String reply) { public static Notification createRepliedNotification(Context context, String reply) {
Notification repliedNotification = new Notification.Builder(context, context.getString(R.string.notification_channel_id)) return new Notification.Builder(context, context.getString(R.string.notification_channel_id))
.setSmallIcon(R.drawable.topbar_chat_notification) .setSmallIcon(R.drawable.topbar_chat_notification)
.setContentText(context.getString(R.string.notification_replied_label).replace("%s", reply)) .setContentText(context.getString(R.string.notification_replied_label).replace("%s", reply))
.build(); .build();
return repliedNotification;
} }
public static void createServiceChannel(Context context) { public static void createServiceChannel(Context context) {
@ -93,7 +95,7 @@ public class ApiTwentySixPlus {
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build(); RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build();
Intent replyIntent = new Intent(context, NotificationBroadcastReceiver.class); Intent replyIntent = new Intent(context, NotificationBroadcastReceiver.class);
replyIntent.setAction(context.getPackageName() + ".REPLY_ACTION"); replyIntent.setAction(INTENT_REPLY_NOTIF_ACTION);
replyIntent.putExtra(INTENT_NOTIF_ID, notificationId); replyIntent.putExtra(INTENT_NOTIF_ID, notificationId);
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context, PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context,
@ -102,10 +104,10 @@ public class ApiTwentySixPlus {
Notification.Action action = new Notification.Action.Builder(R.drawable.chat_send_over, Notification.Action action = new Notification.Action.Builder(R.drawable.chat_send_over,
context.getString(R.string.notification_reply_label), replyPendingIntent) context.getString(R.string.notification_reply_label), replyPendingIntent)
.addRemoteInput(remoteInput) .addRemoteInput(remoteInput)
.setAllowGeneratedReplies(true)
.build(); .build();
Notification notif; return new Notification.Builder(context, context.getString(R.string.notification_channel_id))
notif = new Notification.Builder(context, context.getString(R.string.notification_channel_id))
.setContentTitle(title) .setContentTitle(title)
.setContentText(msg) .setContentText(msg)
.setSmallIcon(R.drawable.topbar_chat_notification) .setSmallIcon(R.drawable.topbar_chat_notification)
@ -122,15 +124,12 @@ public class ApiTwentySixPlus {
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led))
.addAction(action) .addAction(action)
.build(); .build();
return notif;
} }
public static Notification createInCallNotification(Context context, public static Notification createInCallNotification(Context context,
String title, String msg, int iconID, Bitmap contactIcon, int callId, boolean showActions, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
String contactName, PendingIntent intent) {
Notification notif = new Notification.Builder(context, context.getString(R.string.notification_service_channel_id)) Notification.Builder builder = new Notification.Builder(context, context.getString(R.string.notification_service_channel_id))
.setContentTitle(contactName) .setContentTitle(contactName)
.setContentText(msg) .setContentText(msg)
.setSmallIcon(iconID) .setSmallIcon(iconID)
@ -142,17 +141,35 @@ public class ApiTwentySixPlus {
.setPriority(Notification.PRIORITY_HIGH) .setPriority(Notification.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setShowWhen(true) .setShowWhen(true)
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led));
.build();
return notif; if (showActions) {
Intent hangupIntent = new Intent(context, NotificationBroadcastReceiver.class);
hangupIntent.setAction(INTENT_HANGUP_CALL_NOTIF_ACTION);
hangupIntent.putExtra(INTENT_CALL_ID, callId);
PendingIntent hangupPendingIntent = PendingIntent.getBroadcast(context,
callId, hangupIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent answerIntent = new Intent(context, NotificationBroadcastReceiver.class);
answerIntent.setAction(INTENT_ANSWER_CALL_NOTIF_ACTION);
answerIntent.putExtra(INTENT_CALL_ID, callId);
PendingIntent answerPendingIntent = PendingIntent.getBroadcast(context,
callId, answerIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(R.drawable.call_hangup, context.getString(R.string.notification_call_hangup_label), hangupPendingIntent);
builder.addAction(R.drawable.call_audio_start, context.getString(R.string.notification_call_answer_label), answerPendingIntent);
}
return builder.build();
} }
public static Notification createNotification(Context context, String title, String message, int icon, int level, Bitmap largeIcon, PendingIntent intent, boolean isOngoingEvent,int priority) { public static Notification createNotification(Context context, String title, String message, int icon, int level,
Notification notif; Bitmap largeIcon, PendingIntent intent, boolean isOngoingEvent,int priority) {
if (largeIcon != null) { if (largeIcon != null) {
notif = new Notification.Builder(context, context.getString(R.string.notification_service_channel_id)) return new Notification.Builder(context, context.getString(R.string.notification_service_channel_id))
.setContentTitle(title) .setContentTitle(title)
.setContentText(message) .setContentText(message)
.setSmallIcon(icon, level) .setSmallIcon(icon, level)
@ -166,7 +183,7 @@ public class ApiTwentySixPlus {
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led))
.build(); .build();
} else { } else {
notif = new Notification.Builder(context, context.getString(R.string.notification_service_channel_id)) return new Notification.Builder(context, context.getString(R.string.notification_service_channel_id))
.setContentTitle(title) .setContentTitle(title)
.setContentText(message) .setContentText(message)
.setSmallIcon(icon, level) .setSmallIcon(icon, level)
@ -179,16 +196,10 @@ public class ApiTwentySixPlus {
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led))
.build(); .build();
} }
return notif;
}
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, ViewTreeObserver.OnGlobalLayoutListener keyboardListener) {
viewTreeObserver.removeOnGlobalLayoutListener(keyboardListener);
} }
public static Notification createMissedCallNotification(Context context, String title, String text, PendingIntent intent) { public static Notification createMissedCallNotification(Context context, String title, String text, PendingIntent intent) {
Notification notif = new Notification.Builder(context, context.getString(R.string.notification_channel_id)) return new Notification.Builder(context, context.getString(R.string.notification_channel_id))
.setContentTitle(title) .setContentTitle(title)
.setContentText(text) .setContentText(text)
.setSmallIcon(R.drawable.call_status_missed) .setSmallIcon(R.drawable.call_status_missed)
@ -203,12 +214,10 @@ public class ApiTwentySixPlus {
.setShowWhen(true) .setShowWhen(true)
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led))
.build(); .build();
return notif;
} }
public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) { public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) {
Notification notif = new Notification.Builder(context, context.getString(R.string.notification_channel_id)) return new Notification.Builder(context, context.getString(R.string.notification_channel_id))
.setContentTitle(title) .setContentTitle(title)
.setContentText(text) .setContentText(text)
.setSmallIcon(R.drawable.linphone_logo) .setSmallIcon(R.drawable.linphone_logo)
@ -224,8 +233,6 @@ public class ApiTwentySixPlus {
.setColorized(true) .setColorized(true)
.setColor(context.getColor(R.color.notification_color_led)) .setColor(context.getColor(R.color.notification_color_led))
.build(); .build();
return notif;
} }
public static void startService(Context context, Intent intent) { public static void startService(Context context, Intent intent) {

View file

@ -39,6 +39,10 @@ import org.linphone.mediastream.Version;
public class Compatibility { public class Compatibility {
public static final String KEY_TEXT_REPLY = "key_text_reply"; public static final String KEY_TEXT_REPLY = "key_text_reply";
public static final String INTENT_NOTIF_ID = "NOTIFICATION_ID"; public static final String INTENT_NOTIF_ID = "NOTIFICATION_ID";
public static final String INTENT_CALL_ID = "CALL_ID";
public static final String INTENT_REPLY_NOTIF_ACTION = "org.linphone.REPLY_ACTION";
public static final String INTENT_HANGUP_CALL_NOTIF_ACTION = "org.linphone.HANGUP_CALL_ACTION";
public static final String INTENT_ANSWER_CALL_NOTIF_ACTION = "org.linphone.ANSWER_CALL_ACTION";
public static void createNotificationChannels(Context context) { public static void createNotificationChannels(Context context) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) { if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
@ -94,9 +98,11 @@ public class Compatibility {
return null; return null;
} }
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) { public static Notification createInCallNotification(Context context, int callId, boolean showActions, String title, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) { if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
return ApiTwentySixPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent); return ApiTwentySixPlus.createInCallNotification(context, callId, showActions, msg, iconID, contactIcon, contactName, intent);
} else if (Version.sdkAboveOrEqual(Version.API24_NOUGAT_70)) {
return ApiTwentyFourPlus.createInCallNotification(context, callId, showActions, msg, iconID, contactIcon, contactName, intent);
} else if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) { } else if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
return ApiTwentyOnePlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent); return ApiTwentyOnePlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) { } else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {

View file

@ -463,7 +463,6 @@ public class StatusFragment extends Fragment {
} }
isZrtpAsk = false; isZrtpAsk = false;
ZRTPdialog.dismiss(); ZRTPdialog.dismiss();
LinphoneService.instance().removeSasNotification();
} }
}); });
@ -476,7 +475,6 @@ public class StatusFragment extends Fragment {
} }
isZrtpAsk = false; isZrtpAsk = false;
ZRTPdialog.dismiss(); ZRTPdialog.dismiss();
LinphoneService.instance().removeSasNotification();
} }
}); });
ZRTPdialog.show(); ZRTPdialog.show();

View file

@ -31,18 +31,21 @@ import org.linphone.LinphoneManager;
import org.linphone.LinphoneService; import org.linphone.LinphoneService;
import org.linphone.compatibility.Compatibility; import org.linphone.compatibility.Compatibility;
import org.linphone.core.Address; import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.core.ChatMessage; import org.linphone.core.ChatMessage;
import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoom;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.ProxyConfig; import org.linphone.core.ProxyConfig;
import org.linphone.core.Reason;
public class NotificationBroadcastReceiver extends BroadcastReceiver { public class NotificationBroadcastReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (intent.getAction() == Compatibility.INTENT_REPLY_NOTIF_ACTION) {
String reply = getMessageText(intent).toString(); String reply = getMessageText(intent).toString();
if (reply != null) { if (reply == null) return;
Notification replied = Compatibility.createRepliedNotification(context, reply); Notification replied = Compatibility.createRepliedNotification(context, reply);
if (replied != null) { if (replied == null) return;
int notifId = intent.getIntExtra(Compatibility.INTENT_NOTIF_ID, 0); int notifId = intent.getIntExtra(Compatibility.INTENT_NOTIF_ID, 0);
String remoteSipAddr = LinphoneService.instance().getSipUriForNotificationId(notifId); String remoteSipAddr = LinphoneService.instance().getSipUriForNotificationId(notifId);
@ -61,6 +64,19 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver {
msg.send(); msg.send();
LinphoneService.instance().sendNotification(replied, notifId); LinphoneService.instance().sendNotification(replied, notifId);
} else if (intent.getAction() == Compatibility.INTENT_ANSWER_CALL_NOTIF_ACTION || intent.getAction() == Compatibility.INTENT_HANGUP_CALL_NOTIF_ACTION) {
int callId = intent.getIntExtra(Compatibility.INTENT_CALL_ID, 0);
String remoteAddr = LinphoneService.instance().getSipUriForCallNotificationId(callId);
Core core = LinphoneManager.getLc();
if (core == null) return;
Call call = core.findCallFromUri(remoteAddr);
if (call == null) return;
if (intent.getAction() == Compatibility.INTENT_ANSWER_CALL_NOTIF_ACTION) {
call.accept();
} else {
call.decline(Reason.None);
} }
} }
} }

View file

@ -18,6 +18,8 @@
<!-- Notifications --> <!-- Notifications -->
<string name="notification_reply_label">Reply</string> <string name="notification_reply_label">Reply</string>
<string name="notification_replied_label">Sent reply: %s</string> <string name="notification_replied_label">Sent reply: %s</string>
<string name="notification_call_hangup_label">Hangup</string>
<string name="notification_call_answer_label">Answer</string>
<!-- Common --> <!-- Common -->
<string name="username">Username</string> <string name="username">Username</string>