Do not longer start incoming call activity from Service, instead use fullscreen intent in incoming call notification

This commit is contained in:
Sylvain Berfini 2019-08-28 12:35:13 +02:00
parent d1b921f4f0
commit 9776c4cd50
9 changed files with 122 additions and 85 deletions

View file

@ -23,6 +23,7 @@ Group changes to describe their impact on the project, as follows:
## Changed ## Changed
- Call statistics are now available for each call & conference - Call statistics are now available for each call & conference
- Added our own devices in LIME encrypted chatrooms' security view - Added our own devices in LIME encrypted chatrooms' security view
- No longer display incoming call activity from Service, instead use incoming call notification with full screen intent
## [4.1.0] - 2019-05-03 ## [4.1.0] - 2019-05-03

View file

@ -47,6 +47,8 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Needed to get the current Do Not Disturb policy --> <!-- Needed to get the current Do Not Disturb policy -->
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" /> <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<!-- Needed for full screen intent in notifications -->
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<supports-screens <supports-screens
android:anyDensity="true" android:anyDensity="true"

View file

@ -154,7 +154,9 @@ public final class LinphoneService extends Service {
if (state == Call.State.IncomingReceived if (state == Call.State.IncomingReceived
|| state == State.IncomingEarlyMedia) { || state == State.IncomingEarlyMedia) {
if (!mLinphoneManager.getCallGsmON()) onIncomingReceived(); // Now we rely on the fullscreen intent of the call incoming
// notification
// if (!mLinphoneManager.getCallGsmON()) onIncomingReceived();
} else if (state == State.OutgoingInit) { } else if (state == State.OutgoingInit) {
onOutgoingStarted(); onOutgoingStarted();
} else if (state == State.End } else if (state == State.End

View file

@ -119,6 +119,7 @@ class ApiTwentyFourPlus {
.addAction(getCallDeclineAction(context, callId)); .addAction(getCallDeclineAction(context, callId));
if (showAnswerAction) { if (showAnswerAction) {
builder.setFullScreenIntent(intent, true);
builder.addAction(getCallAnswerAction(context, callId)); builder.addAction(getCallAnswerAction(context, callId));
} }

View file

@ -75,28 +75,36 @@ class ApiTwentyOnePlus {
public static Notification createInCallNotification( public static Notification createInCallNotification(
Context context, Context context,
boolean isIncoming,
String msg, String msg,
int iconID, int iconID,
Bitmap contactIcon, Bitmap contactIcon,
String contactName, String contactName,
PendingIntent intent) { PendingIntent intent) {
return new Notification.Builder(context) Notification.Builder builder =
.setContentTitle(contactName) new Notification.Builder(context)
.setContentText(msg) .setContentTitle(contactName)
.setSmallIcon(iconID) .setContentText(msg)
.setAutoCancel(false) .setSmallIcon(iconID)
.setContentIntent(intent) .setAutoCancel(false)
.setLargeIcon(contactIcon) .setContentIntent(intent)
.setCategory(Notification.CATEGORY_CALL) .setLargeIcon(contactIcon)
.setVisibility(Notification.VISIBILITY_PUBLIC) .setCategory(Notification.CATEGORY_CALL)
.setPriority(Notification.PRIORITY_HIGH) .setVisibility(Notification.VISIBILITY_PUBLIC)
.setLights( .setPriority(Notification.PRIORITY_HIGH)
ContextCompat.getColor(context, R.color.notification_led_color), .setOngoing(true)
context.getResources().getInteger(R.integer.notification_ms_on), .setLights(
context.getResources().getInteger(R.integer.notification_ms_off)) ContextCompat.getColor(context, R.color.notification_led_color),
.setShowWhen(true) context.getResources().getInteger(R.integer.notification_ms_on),
.build(); context.getResources().getInteger(R.integer.notification_ms_off))
.setShowWhen(true);
if (isIncoming) {
builder.setFullScreenIntent(intent, true);
}
return builder.build();
} }
public static Notification createNotification( public static Notification createNotification(

View file

@ -143,7 +143,7 @@ class ApiTwentySixPlus {
public static Notification createInCallNotification( public static Notification createInCallNotification(
Context context, Context context,
int callId, int callId,
boolean showAnswerAction, boolean isIncoming,
String msg, String msg,
int iconID, int iconID,
Bitmap contactIcon, Bitmap contactIcon,
@ -153,7 +153,10 @@ class ApiTwentySixPlus {
Notification.Builder builder = Notification.Builder builder =
new Notification.Builder( new Notification.Builder(
context, context,
context.getString(R.string.notification_service_channel_id)) isIncoming
? context.getString(R.string.notification_channel_id)
: context.getString(
R.string.notification_service_channel_id))
.setContentTitle(contactName) .setContentTitle(contactName)
.setContentText(msg) .setContentText(msg)
.setSmallIcon(iconID) .setSmallIcon(iconID)
@ -162,14 +165,16 @@ class ApiTwentySixPlus {
.setLargeIcon(contactIcon) .setLargeIcon(contactIcon)
.setCategory(Notification.CATEGORY_CALL) .setCategory(Notification.CATEGORY_CALL)
.setVisibility(Notification.VISIBILITY_PUBLIC) .setVisibility(Notification.VISIBILITY_PUBLIC)
.setPriority(Notification.PRIORITY_HIGH) .setPriority(
isIncoming ? Notification.PRIORITY_HIGH : Notification.PRIORITY_LOW)
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setShowWhen(true) .setShowWhen(true)
.setOngoing(true) .setOngoing(true)
.setColor(context.getColor(R.color.notification_led_color)) .setColor(context.getColor(R.color.notification_led_color))
.addAction(ApiTwentyFourPlus.getCallDeclineAction(context, callId)); .addAction(ApiTwentyFourPlus.getCallDeclineAction(context, callId));
if (showAnswerAction) { if (isIncoming) {
builder.setFullScreenIntent(intent, true);
builder.addAction(ApiTwentyFourPlus.getCallAnswerAction(context, callId)); builder.addAction(ApiTwentyFourPlus.getCallAnswerAction(context, callId));
} }
return builder.build(); return builder.build();

View file

@ -73,14 +73,6 @@ public class Compatibility {
return ApiTwentyOnePlus.createSimpleNotification(context, title, text, intent); return ApiTwentyOnePlus.createSimpleNotification(context, title, text, intent);
} }
public static Notification createMissedCallNotification(
Context context, String title, String text, PendingIntent intent) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
return ApiTwentySixPlus.createMissedCallNotification(context, title, text, intent);
}
return ApiTwentyOnePlus.createMissedCallNotification(context, title, text, intent);
}
public static Notification createMessageNotification( public static Notification createMessageNotification(
Context context, Context context,
Notifiable notif, Notifiable notif,
@ -109,10 +101,18 @@ public class Compatibility {
return null; return null;
} }
public static Notification createMissedCallNotification(
Context context, String title, String text, PendingIntent intent) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
return ApiTwentySixPlus.createMissedCallNotification(context, title, text, intent);
}
return ApiTwentyOnePlus.createMissedCallNotification(context, title, text, intent);
}
public static Notification createInCallNotification( public static Notification createInCallNotification(
Context context, Context context,
int callId, int callId,
boolean showAnswerAction, boolean isIncoming,
String msg, String msg,
int iconID, int iconID,
Bitmap contactIcon, Bitmap contactIcon,
@ -120,27 +120,13 @@ public class Compatibility {
PendingIntent intent) { PendingIntent intent) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) { if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
return ApiTwentySixPlus.createInCallNotification( return ApiTwentySixPlus.createInCallNotification(
context, context, callId, isIncoming, msg, iconID, contactIcon, contactName, intent);
callId,
showAnswerAction,
msg,
iconID,
contactIcon,
contactName,
intent);
} else if (Version.sdkAboveOrEqual(Version.API24_NOUGAT_70)) { } else if (Version.sdkAboveOrEqual(Version.API24_NOUGAT_70)) {
return ApiTwentyFourPlus.createInCallNotification( return ApiTwentyFourPlus.createInCallNotification(
context, context, callId, isIncoming, msg, iconID, contactIcon, contactName, intent);
callId,
showAnswerAction,
msg,
iconID,
contactIcon,
contactName,
intent);
} }
return ApiTwentyOnePlus.createInCallNotification( return ApiTwentyOnePlus.createInCallNotification(
context, msg, iconID, contactIcon, contactName, intent); context, isIncoming, msg, iconID, contactIcon, contactName, intent);
} }
public static Notification createNotification( public static Notification createNotification(

View file

@ -29,15 +29,15 @@ public class Notifiable {
private String mGroupTitle; private String mGroupTitle;
private String mLocalIdentity; private String mLocalIdentity;
private String mMyself; private String mMyself;
private int iconId; private int mIconId;
private int textId; private int mTextId;
public Notifiable(int id) { public Notifiable(int id) {
mNotificationId = id; mNotificationId = id;
mMessages = new ArrayList<>(); mMessages = new ArrayList<>();
mIsGroup = false; mIsGroup = false;
iconId = 0; mIconId = 0;
textId = 0; mTextId = 0;
} }
public int getNotificationId() { public int getNotificationId() {
@ -89,18 +89,29 @@ public class Notifiable {
} }
public int getIconResourceId() { public int getIconResourceId() {
return iconId; return mIconId;
} }
public void setIconResourceId(int id) { public void setIconResourceId(int id) {
iconId = id; mIconId = id;
} }
public int getTextResourceId() { public int getTextResourceId() {
return textId; return mTextId;
} }
public void setTextResourceId(int id) { public void setTextResourceId(int id) {
textId = id; mTextId = id;
}
public String toString() {
return "Id: "
+ mNotificationId
+ ", local identity: "
+ mLocalIdentity
+ ", myself: "
+ mMyself
+ ", isGrouped: "
+ mIsGroup;
} }
} }

View file

@ -54,6 +54,7 @@ import org.linphone.core.Reason;
import org.linphone.core.tools.Log; import org.linphone.core.tools.Log;
import org.linphone.history.HistoryActivity; import org.linphone.history.HistoryActivity;
import org.linphone.settings.LinphonePreferences; import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.DeviceUtils;
import org.linphone.utils.FileUtils; import org.linphone.utils.FileUtils;
import org.linphone.utils.ImageUtils; import org.linphone.utils.ImageUtils;
import org.linphone.utils.LinphoneUtils; import org.linphone.utils.LinphoneUtils;
@ -114,6 +115,8 @@ public class NotificationsManager {
true); true);
if (isServiceNotificationDisplayed()) { if (isServiceNotificationDisplayed()) {
Log.i(
"[Notifications Manager] Background service mode enabled, displaying notification");
startForeground(); startForeground();
} }
@ -219,6 +222,7 @@ public class NotificationsManager {
// When a message is received by a push, it will create a LinphoneService // When a message is received by a push, it will create a LinphoneService
// but it might be getting killed quite quickly after that // but it might be getting killed quite quickly after that
// causing the notification to be missed by the user... // causing the notification to be missed by the user...
Log.i("[Notifications Manager] Getting destroyed, clearing Service & Call notifications");
if (mCurrentForegroundServiceNotification > 0) { if (mCurrentForegroundServiceNotification > 0) {
mNM.cancel(mCurrentForegroundServiceNotification); mNM.cancel(mCurrentForegroundServiceNotification);
@ -239,16 +243,19 @@ public class NotificationsManager {
} }
public void startForeground() { public void startForeground() {
Log.i("[Notifications Manager] Starting Service as foreground");
LinphoneService.instance().startForeground(SERVICE_NOTIF_ID, mServiceNotification); LinphoneService.instance().startForeground(SERVICE_NOTIF_ID, mServiceNotification);
mCurrentForegroundServiceNotification = SERVICE_NOTIF_ID; mCurrentForegroundServiceNotification = SERVICE_NOTIF_ID;
} }
private void startForeground(Notification notification, int id) { private void startForeground(Notification notification, int id) {
Log.i("[Notifications Manager] Starting Service as foreground while in call");
LinphoneService.instance().startForeground(id, notification); LinphoneService.instance().startForeground(id, notification);
mCurrentForegroundServiceNotification = id; mCurrentForegroundServiceNotification = id;
} }
public void stopForeground() { public void stopForeground() {
Log.i("[Notifications Manager] Stopping Service as foreground");
LinphoneService.instance().stopForeground(true); LinphoneService.instance().stopForeground(true);
mCurrentForegroundServiceNotification = 0; mCurrentForegroundServiceNotification = 0;
} }
@ -256,6 +263,8 @@ public class NotificationsManager {
public void removeForegroundServiceNotificationIfPossible() { public void removeForegroundServiceNotificationIfPossible() {
if (mCurrentForegroundServiceNotification == SERVICE_NOTIF_ID if (mCurrentForegroundServiceNotification == SERVICE_NOTIF_ID
&& !isServiceNotificationDisplayed()) { && !isServiceNotificationDisplayed()) {
Log.i(
"[Notifications Manager] Linphone has started after device boot, stopping Service as foreground");
stopForeground(); stopForeground();
} }
} }
@ -268,9 +277,15 @@ public class NotificationsManager {
} }
public void sendNotification(int id, Notification notif) { public void sendNotification(int id, Notification notif) {
Log.i("[Notifications Manager] Notifying " + id);
mNM.notify(id, notif); mNM.notify(id, notif);
} }
public void dismissNotification(int notifId) {
Log.i("[Notifications Manager] Dismissing " + notifId);
mNM.cancel(notifId);
}
public void resetMessageNotifCount(String address) { public void resetMessageNotifCount(String address) {
Notifiable notif = mChatNotifMap.get(address); Notifiable notif = mChatNotifMap.get(address);
if (notif != null) { if (notif != null) {
@ -312,6 +327,7 @@ public class NotificationsManager {
mLastNotificationId += 1; mLastNotificationId += 1;
mChatNotifMap.put(conferenceAddress, notif); mChatNotifMap.put(conferenceAddress, notif);
} }
Log.i("[Notifications Manager] Creating group chat message notifiable " + notif);
notifMessage.setSenderBitmap(bm); notifMessage.setSenderBitmap(bm);
notif.addMessage(notifMessage); notif.addMessage(notifMessage);
@ -367,6 +383,7 @@ public class NotificationsManager {
mLastNotificationId += 1; mLastNotificationId += 1;
mChatNotifMap.put(fromSipUri, notif); mChatNotifMap.put(fromSipUri, notif);
} }
Log.i("[Notifications Manager] Creating chat message notifiable " + notif);
notifMessage.setSenderBitmap(bm); notifMessage.setSenderBitmap(bm);
notif.addMessage(notifMessage); notif.addMessage(notifMessage);
@ -409,6 +426,7 @@ public class NotificationsManager {
body = body =
mContext.getString(R.string.missed_calls_notif_body) mContext.getString(R.string.missed_calls_notif_body)
.replace("%i", String.valueOf(missedCallCount)); .replace("%i", String.valueOf(missedCallCount));
Log.i("[Notifications Manager] Creating missed calls notification");
} else { } else {
Address address = call.getRemoteAddress(); Address address = call.getRemoteAddress();
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address); LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
@ -420,6 +438,7 @@ public class NotificationsManager {
body = address.asStringUriOnly(); body = address.asStringUriOnly();
} }
} }
Log.i("[Notifications Manager] Creating missed call notification");
} }
Notification notif = Notification notif =
@ -434,18 +453,17 @@ public class NotificationsManager {
public void displayCallNotification(Call call) { public void displayCallNotification(Call call) {
if (call == null) return; if (call == null) return;
Intent callNotifIntent; Class callNotifIntentClass = CallActivity.class;
if (call.getState() == Call.State.IncomingReceived if (call.getState() == Call.State.IncomingReceived
|| call.getState() == Call.State.IncomingEarlyMedia) { || call.getState() == Call.State.IncomingEarlyMedia) {
callNotifIntent = new Intent(mContext, CallIncomingActivity.class); callNotifIntentClass = CallIncomingActivity.class;
} else if (call.getState() == Call.State.OutgoingInit } else if (call.getState() == Call.State.OutgoingInit
|| call.getState() == Call.State.OutgoingProgress || call.getState() == Call.State.OutgoingProgress
|| call.getState() == Call.State.OutgoingRinging || call.getState() == Call.State.OutgoingRinging
|| call.getState() == Call.State.OutgoingEarlyMedia) { || call.getState() == Call.State.OutgoingEarlyMedia) {
callNotifIntent = new Intent(mContext, CallOutgoingActivity.class); callNotifIntentClass = CallOutgoingActivity.class;
} else {
callNotifIntent = new Intent(mContext, CallActivity.class);
} }
Intent callNotifIntent = new Intent(mContext, callNotifIntentClass);
callNotifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); callNotifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent pendingIntent =
@ -467,6 +485,8 @@ public class NotificationsManager {
case Released: case Released:
case End: case End:
if (mCurrentForegroundServiceNotification == notif.getNotificationId()) { if (mCurrentForegroundServiceNotification == notif.getNotificationId()) {
Log.i(
"[Notifications Manager] Call ended, stopping notification used to keep service alive");
// Call is released, remove service notification to allow for an other call to // Call is released, remove service notification to allow for an other call to
// be service notification // be service notification
stopForeground(); stopForeground();
@ -507,39 +527,59 @@ public class NotificationsManager {
&& notif.getTextResourceId() == notificationTextId) { && notif.getTextResourceId() == notificationTextId) {
// Notification hasn't changed, do not "update" it to avoid blinking // Notification hasn't changed, do not "update" it to avoid blinking
return; return;
} else if (notif.getTextResourceId() == R.string.incall_notif_incoming) {
// If previous notif was incoming call, as we will switch channels, dismiss it first
dismissNotification(notif.getNotificationId());
} }
notif.setIconResourceId(iconId); notif.setIconResourceId(iconId);
notif.setTextResourceId(notificationTextId); notif.setTextResourceId(notificationTextId);
Log.i(
"[Notifications Manager] Call notification notifiable is "
+ notif
+ ", pending intent "
+ callNotifIntentClass);
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 = ImageUtils.getRoundBitmapFromUri(mContext, pictureUri); Bitmap bm = ImageUtils.getRoundBitmapFromUri(mContext, pictureUri);
String name = LinphoneUtils.getAddressDisplayName(address); String name = LinphoneUtils.getAddressDisplayName(address);
boolean isIncoming = callNotifIntentClass == CallIncomingActivity.class;
boolean showAnswerAction =
call.getState() == Call.State.IncomingReceived
|| call.getState() == Call.State.IncomingEarlyMedia;
Notification notification = Notification notification =
Compatibility.createInCallNotification( Compatibility.createInCallNotification(
mContext, mContext,
notif.getNotificationId(), notif.getNotificationId(),
showAnswerAction, isIncoming,
mContext.getString(notificationTextId), mContext.getString(notificationTextId),
iconId, iconId,
bm, bm,
name, name,
pendingIntent); pendingIntent);
if (!isServiceNotificationDisplayed()) { // Don't use incoming call notification as foreground service notif !
if (!isServiceNotificationDisplayed() && !isIncoming) {
if (call.getCore().getCallsNb() == 0) { if (call.getCore().getCallsNb() == 0) {
Log.i(
"[Notifications Manager] Foreground service mode is disabled, stopping call notification used to keep it alive");
stopForeground(); stopForeground();
} else { } else {
if (mCurrentForegroundServiceNotification == 0) { if (mCurrentForegroundServiceNotification == 0) {
startForeground(notification, notif.getNotificationId()); if (DeviceUtils.isAppUserRestricted(mContext)) {
Log.w(
"[Notifications Manager] App has been restricted, can't use call notification to keep service alive !");
sendNotification(notif.getNotificationId(), notification);
} else {
Log.i(
"[Notifications Manager] Foreground service mode is disabled, using call notification to keep it alive");
startForeground(notification, notif.getNotificationId());
}
} else { } else {
sendNotification(notif.getNotificationId(), notification); sendNotification(notif.getNotificationId(), notification);
} }
} }
} else {
sendNotification(notif.getNotificationId(), notification);
} }
} }
@ -552,25 +592,6 @@ public class NotificationsManager {
return null; return null;
} }
/*public void displayInappNotification(String message) {
Intent notifIntent = new Intent(mContext, InAppPurchaseActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(
mContext, IN_APP_NOTIF_ID, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notif =
Compatibility.createSimpleNotification(
mContext,
mContext.getString(R.string.inapp_notification_title),
message,
pendingIntent);
sendNotification(IN_APP_NOTIF_ID, notif);
}*/
public void dismissNotification(int notifId) {
mNM.cancel(notifId);
}
private void createNotification( private void createNotification(
ChatRoom cr, ChatRoom cr,
LinphoneContact contact, LinphoneContact contact,