Cleaned LinphoneService a bit, moved all notifications related code to another class

This commit is contained in:
Sylvain Berfini 2018-11-20 17:10:05 +01:00
parent 886b5a36c0
commit 1e6fb279c0
22 changed files with 595 additions and 525 deletions

View file

@ -294,7 +294,7 @@
<activity android:name=".activities.LinphoneGenericActivity"/>
<receiver
android:name=".receivers.NotificationBroadcastReceiver"
android:name=".notifications.NotificationBroadcastReceiver"
android:enabled="true"
android:exported="false" />

View file

@ -504,7 +504,7 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou
if (call != null) {
call.enableCamera(enable);
if (mServiceContext.getResources().getBoolean(R.bool.enable_call_notification))
LinphoneService.instance().displayCallNotification(mLc.getCurrentCall());
LinphoneService.instance().getNotificationManager().displayCallNotification(mLc.getCurrentCall());
}
}
@ -1075,16 +1075,16 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou
if (!mServiceContext.getResources().getBoolean(R.bool.disable_chat_message_notification) && !message.isOutgoing()) {
if (cr.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
if (contact != null) {
LinphoneService.instance().displayMessageNotification(cr.getPeerAddress().asStringUriOnly(), contact.getFullName(), contact.getThumbnailUri(), textMessage, cr.getLocalAddress().asString());
LinphoneService.instance().getNotificationManager().displayMessageNotification(cr.getPeerAddress().asStringUriOnly(), contact.getFullName(), contact.getThumbnailUri(), textMessage, cr.getLocalAddress());
} else {
LinphoneService.instance().displayMessageNotification(cr.getPeerAddress().asStringUriOnly(), from.getUsername(), null, textMessage, cr.getLocalAddress().asString());
LinphoneService.instance().getNotificationManager().displayMessageNotification(cr.getPeerAddress().asStringUriOnly(), from.getUsername(), null, textMessage, cr.getLocalAddress());
}
} else {
String subject = cr.getSubject();
if (contact != null) {
LinphoneService.instance().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asStringUriOnly(), contact.getFullName(), contact.getThumbnailUri(), textMessage, cr.getLocalAddress().asString());
LinphoneService.instance().getNotificationManager().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asStringUriOnly(), contact.getFullName(), contact.getThumbnailUri(), textMessage, cr.getLocalAddress());
} else {
LinphoneService.instance().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asStringUriOnly(), from.getUsername(), null, textMessage, cr.getLocalAddress().asString());
LinphoneService.instance().getNotificationManager().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asStringUriOnly(), from.getUsername(), null, textMessage, cr.getLocalAddress());
}
}
}

View file

@ -23,31 +23,22 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.view.WindowManager;
import org.linphone.activities.LinphoneActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.core.Call.State;
import org.linphone.core.Core;
@ -58,14 +49,12 @@ import org.linphone.core.ProxyConfig;
import org.linphone.core.RegistrationState;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.notifications.NotificationsManager;
import org.linphone.receivers.BluetoothManager;
import org.linphone.receivers.KeepAliveReceiver;
import org.linphone.ui.LinphoneOverlay;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Linphone service, reacting to Incoming calls, ...<br />
@ -81,14 +70,9 @@ public final class LinphoneService extends Service {
* setLatestEventInfo and startActivity() which needs a context.
*/
public static final String START_LINPHONE_LOGS = " ==== Phone information dump ====";
public static final int IC_LEVEL_ORANGE = 0;
private static LinphoneService instance;
private final static int NOTIF_ID = 1;
private final static int CUSTOM_NOTIF_ID = 4;
private final static int MISSED_NOTIF_ID = 5;
public static boolean isReady() {
return instance != null && instance.mTestDelayElapsed;
}
@ -106,38 +90,28 @@ public final class LinphoneService extends Service {
// private boolean mTestDelayElapsed; // add a timer for testing
private boolean mTestDelayElapsed = true; // no timer
private NotificationManager mNM;
private Notification mNotif;
private Notification mCustomNotif;
private PendingIntent mNotifContentIntent;
private String mNotificationTitle;
private boolean mDisableRegistrationStatus;
private CoreListenerStub mListener;
public static int notifcationsPriority = (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41) ? Notification.PRIORITY_MIN : 0);
private WindowManager mWindowManager;
private LinphoneOverlay mOverlay;
private Application.ActivityLifecycleCallbacks activityCallbacks;
private class Notified {
int notificationId;
int numberOfUnreadMessage;
private NotificationsManager mNotificationManager;
public NotificationsManager getNotificationManager() {
return mNotificationManager;
}
private HashMap<String, Notified> mChatNotifMap, mCallNotifMap;
private int mLastNotificationId;
private String incomingReceivedActivityName;
private Class<? extends Activity> incomingReceivedActivity = LinphoneActivity.class;
public Class<? extends Activity> getIncomingReceivedActivity() {
return incomingReceivedActivity;
}
public void setCurrentlyDisplayedChatRoom(String address) {
if (address != null) {
resetMessageNotifCount(address);
}
}
private void resetMessageNotifCount(String address) {
Notified notif = mChatNotifMap.get(address);
if (notif != null) {
notif.numberOfUnreadMessage = 0;
mNM.cancel(notif.notificationId);
mNotificationManager.resetMessageNotifCount(address);
}
}
@ -169,8 +143,6 @@ public final class LinphoneService extends Service {
}
}
;
private InactivityChecker mLastChecker;
@Override
@ -275,31 +247,6 @@ public final class LinphoneService extends Service {
getApplication().registerActivityLifecycleCallbacks(activityCallbacks = new ActivityMonitor());
}
public boolean displayServiceNotification() {
return LinphonePreferences.instance().getServiceNotificationVisibility();
}
public void showServiceNotification() {
startForegroundCompat(NOTIF_ID, mNotif);
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc == null) return;
ProxyConfig lpc = lc.getDefaultProxyConfig();
if (lpc != null) {
if (lpc.getState() == RegistrationState.Ok) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
} else {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_register_failure);
}
} else {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
}
}
public void hideServiceNotification() {
stopForegroundCompat(NOTIF_ID);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
@ -309,9 +256,10 @@ public final class LinphoneService extends Service {
return START_REDELIVER_INTENT;
}
LinphoneManager.createAndStart(LinphoneService.this);
LinphoneManager.createAndStart(this);
instance = this; // instance is ready once linphone manager has been created
mNotificationManager = new NotificationsManager(this);
LinphoneManager.getLc().addListener(mListener = new CoreListenerStub() {
@Override
public void onCallStateChanged(Core lc, Call call, Call.State state, String message) {
@ -321,7 +269,7 @@ public final class LinphoneService extends Service {
}
if (getResources().getBoolean(R.bool.enable_call_notification)) {
displayCallNotification(call);
mNotificationManager.displayCallNotification(call);
}
if (state == Call.State.IncomingReceived) {
@ -339,58 +287,23 @@ public final class LinphoneService extends Service {
}
if (state == State.End && call.getCallLog().getStatus() == Call.Status.Missed) {
int missedCallCount = LinphoneManager.getLcIfManagerNotDestroyedOrNull().getMissedCallsCount();
String body;
if (missedCallCount > 1) {
body = getString(R.string.missed_calls_notif_body).replace("%i", String.valueOf(missedCallCount));
} else {
Address address = call.getRemoteAddress();
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
if (c != null) {
body = c.getFullName();
} else {
body = address.getDisplayName();
if (body == null) {
body = address.asStringUriOnly();
}
}
}
Intent missedCallNotifIntent = new Intent(LinphoneService.this, incomingReceivedActivity);
missedCallNotifIntent.putExtra("GoToHistory", true);
PendingIntent intent = PendingIntent.getActivity(LinphoneService.this, 0, missedCallNotifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notif = Compatibility.createMissedCallNotification(instance, getString(R.string.missed_calls_notif_title), body, intent);
notifyWrapper(MISSED_NOTIF_ID, notif);
mNotificationManager.displayMissedCallNotification(call);
}
}
@Override
public void onGlobalStateChanged(Core lc, GlobalState state, String message) {
if (!mDisableRegistrationStatus && state == GlobalState.On && displayServiceNotification()) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
}
//TODO global state if ON
}
@Override
public void onRegistrationStateChanged(Core lc, ProxyConfig cfg, RegistrationState state, String smessage) {
if (!mDisableRegistrationStatus) {
if (displayServiceNotification() && state == RegistrationState.Ok && LinphoneManager.getLc().getDefaultProxyConfig() != null && LinphoneManager.getLc().getDefaultProxyConfig().getState() == RegistrationState.Ok) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
}
if (displayServiceNotification() && (state == RegistrationState.Failed || state == RegistrationState.Cleared) && (LinphoneManager.getLc().getDefaultProxyConfig() == null || !(LinphoneManager.getLc().getDefaultProxyConfig().getState() == RegistrationState.Ok))) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_register_failure);
}
if (displayServiceNotification() && state == RegistrationState.None) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
}
}
//TODO registration status
}
});
if (displayServiceNotification() || (Version.sdkAboveOrEqual(Version.API26_O_80) && intent.getBooleanExtra("ForceStartForeground", false))) {
startForegroundCompat(NOTIF_ID, mNotif);
if (Version.sdkAboveOrEqual(Version.API26_O_80) && intent.getBooleanExtra("ForceStartForeground", false)) {
mNotificationManager.startForeground();
}
if (!Version.sdkAboveOrEqual(Version.API26_O_80)
@ -426,13 +339,8 @@ public final class LinphoneService extends Service {
@Override
public void onCreate() {
super.onCreate();
mLastNotificationId = 8; // To not interfere with other notifs ids
mChatNotifMap = new HashMap<>();
mCallNotifMap = new HashMap<>();
setupActivityMonitor();
// In case restart after a crash. Main in LinphoneActivity
mNotificationTitle = getString(R.string.service_name);
// Needed in order for the two next calls to succeed, libraries must have been loaded first
LinphonePreferences.instance().setContext(getBaseContext());
@ -445,27 +353,6 @@ public final class LinphoneService extends Service {
dumpDeviceInformation();
dumpInstalledLinphoneInformation();
//Disable service notification for Android O
if ((Version.sdkAboveOrEqual(Version.API26_O_80))) {
LinphonePreferences.instance().setServiceNotificationVisibility(false);
mDisableRegistrationStatus = true;
}
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.cancelAll();
Compatibility.createNotificationChannels(this);
Intent notifIntent = new Intent(this, incomingReceivedActivity);
notifIntent.putExtra("Notification", true);
mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
} catch (Exception e) {
}
mNotif = Compatibility.createNotification(this, mNotificationTitle, "", R.drawable.linphone_notification_icon, R.mipmap.ic_launcher, bm, mNotifContentIntent, true, notifcationsPriority);
incomingReceivedActivityName = LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived();
try {
incomingReceivedActivity = (Class<? extends Activity>) Class.forName(incomingReceivedActivityName);
@ -473,13 +360,6 @@ public final class LinphoneService extends Service {
Log.e(e);
}
try {
mStartForeground = getClass().getMethod("startForeground", mStartFgSign);
mStopForeground = getClass().getMethod("stopForeground", mStopFgSign);
} catch (NoSuchMethodException e) {
Log.e(e, "Couldn't find startForeground or stopForeground");
}
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
}
@ -504,249 +384,6 @@ public final class LinphoneService extends Service {
mOverlay = null;
}
public void displayCallNotification(Call call) {
if (call == null) return;
Address address = call.getRemoteAddress();
String addressAsString = address.asStringUriOnly();
Notified notif = mCallNotifMap.get(addressAsString);
if (notif == null) {
notif = new Notified();
notif.notificationId = mLastNotificationId;
mLastNotificationId += 1;
mCallNotifMap.put(addressAsString, notif);
}
if (!displayServiceNotification()) {
if (call.getCore().getCallsNb() == 0) {
hideServiceNotification();
} else {
showServiceNotification();
}
}
int notificationTextId;
int iconId;
switch (call.getState()) {
case Released:
case End:
mNM.cancel(notif.notificationId);
mCallNotifMap.remove(addressAsString);
return;
case Paused:
case PausedByRemote:
case Pausing:
iconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_paused;
break;
default:
if (call.getCurrentParams().videoEnabled()) {
iconId = R.drawable.topbar_videocall_notification;
notificationTextId = R.string.incall_notif_video;
} else {
iconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_active;
}
break;
}
LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address);
Uri pictureUri = contact != null ? contact.getPhotoUri() : null;
Bitmap bm;
try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), pictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.avatar);
}
String name = LinphoneUtils.getAddressDisplayName(address);
boolean showAnswerAction = call.getState() == State.IncomingReceived || call.getState() == State.IncomingEarlyMedia;
Intent notifIntent = new Intent(this, incomingReceivedActivity);
notifIntent.putExtra("Notification", true);
mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = Compatibility.createInCallNotification(getApplicationContext(), notif.notificationId, showAnswerAction, mNotificationTitle, getString(notificationTextId), iconId, bm, name, mNotifContentIntent);
notifyWrapper(notif.notificationId, notification);
}
public String getSipUriForCallNotificationId(int notificationId) {
for (String addr : mCallNotifMap.keySet()) {
if (mCallNotifMap.get(addr).notificationId == notificationId) {
return addr;
}
}
return null;
}
@Deprecated
public void addNotification(Intent onClickIntent, int iconResourceID, String title, String message) {
addCustomNotification(onClickIntent, iconResourceID, title, message, true);
}
public void addCustomNotification(Intent onClickIntent, int iconResourceID, String title, String message, boolean isOngoingEvent) {
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
} catch (Exception e) {
}
mCustomNotif = Compatibility.createNotification(this, title, message, iconResourceID, 0, bm, notifContentIntent, isOngoingEvent, notifcationsPriority);
mCustomNotif.defaults |= Notification.DEFAULT_VIBRATE;
mCustomNotif.defaults |= Notification.DEFAULT_SOUND;
mCustomNotif.defaults |= Notification.DEFAULT_LIGHTS;
notifyWrapper(CUSTOM_NOTIF_ID, mCustomNotif);
}
public void displayGroupChatMessageNotification(String subject, String conferenceAddress, String fromName, Uri fromPictureUri, String message, String localIdentity) {
Intent notifIntent = new Intent(this, LinphoneActivity.class);
notifIntent.putExtra("GoToChat", true);
notifIntent.putExtra("ChatContactSipUri", conferenceAddress);
notifIntent.putExtra("LocalIdentity", localIdentity);
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notified notif = mChatNotifMap.get(conferenceAddress);
if (notif != null) {
notif.numberOfUnreadMessage += 1;
} else {
notif = new Notified();
notif.numberOfUnreadMessage = 1;
notif.notificationId = mLastNotificationId;
mLastNotificationId += 1;
mChatNotifMap.put(conferenceAddress, notif);
}
Bitmap bm;
if (fromPictureUri != null) {
try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), fromPictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.chat_group_avatar);
}
} else {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.topbar_avatar);
}
Notification notification = Compatibility.createMessageNotification(getApplicationContext(), notif.notificationId, notif.numberOfUnreadMessage, subject,
getString(R.string.group_chat_notif).replace("%1", fromName).replace("%2", message), bm, notifContentIntent);
notifyWrapper(notif.notificationId, notification);
}
public void displayMessageNotification(String fromSipUri, String fromName, Uri fromPictureUri, String message, String localIdentity) {
Intent notifIntent = new Intent(this, LinphoneActivity.class);
notifIntent.putExtra("GoToChat", true);
notifIntent.putExtra("ChatContactSipUri", fromSipUri);
notifIntent.putExtra("LocalIdentity", localIdentity);
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (fromName == null) {
fromName = fromSipUri;
}
Notified notif = mChatNotifMap.get(fromSipUri);
if (notif != null) {
notif.numberOfUnreadMessage += 1;
} else {
notif = new Notified();
notif.numberOfUnreadMessage = 1;
notif.notificationId = mLastNotificationId;
mLastNotificationId += 1;
mChatNotifMap.put(fromSipUri, notif);
}
Bitmap bm;
if (fromPictureUri != null) {
try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), fromPictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.topbar_avatar);
}
} else {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.topbar_avatar);
}
Notification notification = Compatibility.createMessageNotification(getApplicationContext(), notif.notificationId, notif.numberOfUnreadMessage, fromName, message, bm, notifContentIntent);
notifyWrapper(notif.notificationId, notification);
}
public void sendNotification(Notification notif, int notificationId) {
notifyWrapper(notificationId, notif);
}
public String getSipUriForNotificationId(int notificationId) {
for (String addr : mChatNotifMap.keySet()) {
if (mChatNotifMap.get(addr).notificationId == notificationId) {
return addr;
}
}
return null;
}
public void displayInappNotification(String message) {
Intent notifIntent = new Intent(this, LinphoneActivity.class);
notifIntent.putExtra("GoToInapp", true);
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mNotif = Compatibility.createSimpleNotification(getApplicationContext(), getString(R.string.inapp_notification_title), message, notifContentIntent);
notifyWrapper(NOTIF_ID, mNotif);
}
private static final Class<?>[] mSetFgSign = new Class[]{boolean.class};
private static final Class<?>[] mStartFgSign = new Class[]{
int.class, Notification.class};
private static final Class<?>[] mStopFgSign = new Class[]{boolean.class};
private Method mStartForeground;
private Method mStopForeground;
private Object[] mSetForegroundArgs = new Object[1];
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private String incomingReceivedActivityName;
private Class<? extends Activity> incomingReceivedActivity = LinphoneActivity.class;
void invokeMethod(Method method, Object[] args) {
try {
method.invoke(this, args);
} catch (InvocationTargetException e) {
// Should not happen.
Log.w(e, "Unable to invoke method");
} catch (IllegalAccessException e) {
// Should not happen.
Log.w(e, "Unable to invoke method");
}
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mStopForeground, mStopForegroundArgs);
return;
}
}
private void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder();
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
@ -775,38 +412,6 @@ public final class LinphoneService extends Service {
}
}
private synchronized void sendNotification(int level, int textId) {
String text = getString(textId);
if (text.contains("%s") && LinphoneManager.getLc() != null) {
// Test for null lc is to avoid a NPE when Android mess up badly with the String resources.
ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig();
String id = lpc != null ? lpc.getIdentityAddress().asString() : "";
text = String.format(text, id);
}
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
} catch (Exception e) {
}
mNotif = Compatibility.createNotification(this, mNotificationTitle, text, R.drawable.status_level, 0, bm, mNotifContentIntent, true, notifcationsPriority);
notifyWrapper(NOTIF_ID, mNotif);
}
/**
* Wrap notifier to avoid setting the linphone icons while the service
* is stopping. When the (rare) bug is triggered, the linphone icon is
* present despite the service is not running. To trigger it one could
* stop linphone as soon as it is started. Transport configured with TLS.
*/
private synchronized void notifyWrapper(int id, Notification notification) {
if (instance != null && notification != null) {
mNM.notify(id, notification);
} else {
Log.i("Service not ready, discarding notification");
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
@ -849,8 +454,7 @@ public final class LinphoneService extends Service {
LinphoneManager.destroy();
// Make sure our notification is gone.
stopForegroundCompat(NOTIF_ID);
mNM.cancelAll();
mNotificationManager.destroy();
// This will prevent the app from crashing if the service gets killed in background mode
if (LinphoneActivity.isInstanciated()) {

View file

@ -698,10 +698,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
changeCurrentFragment(FragmentsAvailable.CREATE_CHAT, extras);
}
public void goToChat(String sipUri, Bundle shareInfos, String localIdentity) {
public void goToChat(String sipUri, Bundle shareInfos) {
Bundle extras = new Bundle();
extras.putString("SipUri", sipUri);
extras.putString("LocalIdentity", localIdentity);
if (shareInfos != null) {
if (shareInfos.getString("fileSharedUri") != null)
@ -1382,9 +1381,6 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
if (!LinphoneService.instance().displayServiceNotification()) {
lc.refreshRegisters();
}
}
if (isTablet()) {
@ -1483,12 +1479,11 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
Bundle extras = intent.getExtras();
if (extras != null && extras.getBoolean("GoToChat", false)) {
String sipUri = extras.getString("ChatContactSipUri");
String localIdentity = extras.getString("LocalIdentity");
intent.putExtra("DoNotGoToCallActivity", true);
if (sipUri == null) {
goToChatList();
} else {
goToChat(sipUri, extras, localIdentity);
goToChat(sipUri, extras);
}
} else if (extras != null && extras.getBoolean("GoToHistory", false)) {
intent.putExtra("DoNotGoToCallActivity", true);
@ -1496,7 +1491,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
} else if (extras != null && extras.getBoolean("GoToInapp", false)) {
intent.putExtra("DoNotGoToCallActivity", true);
displayInapp();
} else if (extras != null && extras.getBoolean("Notification", false)) {
} else if (extras != null && extras.getBoolean("Notifiable", false)) {
if (LinphoneManager.getLc().getCallsNb() > 0) {
startIncallActivity();
}
@ -1840,9 +1835,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
LinphonePreferences.instance().setInappPopupTime(String.valueOf(newDate));
}
if (isTrialAccount) {
LinphoneService.instance().displayInappNotification(String.format(getString(R.string.inapp_notification_trial_expire), date));
LinphoneService.instance().getNotificationManager().displayInappNotification(String.format(getString(R.string.inapp_notification_trial_expire), date));
} else {
LinphoneService.instance().displayInappNotification(String.format(getString(R.string.inapp_notification_account_expire), date));
LinphoneService.instance().getNotificationManager().displayInappNotification(String.format(getString(R.string.inapp_notification_account_expire), date));
}
}

View file

@ -213,7 +213,7 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), mShareInfos, cr.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), mShareInfos);
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
@ -468,7 +468,7 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen
if (createEncryptedChatRoom && lpc != null && lpc.getConferenceFactoryUri() != null) {
mChatRoom = lc.findOneToOneChatRoom(lpc.getIdentityAddress(), ca.getAddress(), true);
if (mChatRoom != null) {
LinphoneActivity.instance().goToChat(mChatRoom.getPeerAddress().asStringUriOnly(), mShareInfos, mChatRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mChatRoom.getPeerAddress().asStringUriOnly(), mShareInfos);
} else {
mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject), !createEncryptedChatRoom, createEncryptedChatRoom);
mChatRoom.addListener(mChatRoomCreationListener);
@ -487,11 +487,11 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen
participants[0] = ca.getAddress();
mChatRoom.addParticipants(participants);
} else {
LinphoneActivity.instance().goToChat(mChatRoom.getPeerAddress().asStringUriOnly(), mShareInfos, mChatRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mChatRoom.getPeerAddress().asStringUriOnly(), mShareInfos);
}
} else {
ChatRoom chatRoom = lc.getChatRoom(ca.getAddress());
LinphoneActivity.instance().goToChat(chatRoom.getPeerAddress().asStringUriOnly(), mShareInfos, chatRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(chatRoom.getPeerAddress().asStringUriOnly(), mShareInfos);
}
}
} else {

View file

@ -161,7 +161,7 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
mChatRoomsAdapter.toggleSelection(position);
} else {
ChatRoom room = (ChatRoom) mChatRoomsAdapter.getItem(position);
LinphoneActivity.instance().goToChat(room.getPeerAddress().asString(), null, room.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(room.getPeerAddress().asString(), null);
}
}
@ -183,7 +183,7 @@ public class ChatListFragment extends Fragment implements ContactsUpdatedListene
ChatRoomsAdapter adapter = (ChatRoomsAdapter) mChatRoomsList.getAdapter();
if (adapter != null && adapter.getItemCount() > 0) {
ChatRoom room = (ChatRoom) adapter.getItem(0);
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null, room.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null);
} else {
LinphoneActivity.instance().displayEmptyFragment();
}

View file

@ -106,7 +106,7 @@ public class DevicesFragment extends Fragment {
@Override
public void onClick(View view) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChat(mRoomUri, null, mRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mRoomUri, null);
} else {
LinphoneActivity.instance().onBackPressed();
}

View file

@ -951,11 +951,11 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con
if (LinphoneActivity.instance().isOnBackground()) {
if (!getResources().getBoolean(R.bool.disable_chat_message_notification)) {
if (contact != null) {
LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(),
contact.getFullName(), contact.getThumbnailUri(), getString(R.string.message_cant_be_decrypted_notif), cr.getLocalAddress().asString());
LinphoneService.instance().getNotificationManager().displayMessageNotification(from.asStringUriOnly(),
contact.getFullName(), contact.getThumbnailUri(), getString(R.string.message_cant_be_decrypted_notif), cr.getLocalAddress());
} else {
LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(),
from.getUsername(), null, getString(R.string.message_cant_be_decrypted_notif), cr.getLocalAddress().asString());
LinphoneService.instance().getNotificationManager().displayMessageNotification(from.asStringUriOnly(),
from.getUsername(), null, getString(R.string.message_cant_be_decrypted_notif), cr.getLocalAddress());
}
}
} else if (LinphoneManager.getLc().limeEnabled() == LimeState.Mandatory) {

View file

@ -159,7 +159,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
public void onClick(View view) {
if (mIsAlreadyCreatedGroup) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChat(mGroupChatRoomAddress.asStringUriOnly(), mShareInfos, mChatRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mGroupChatRoomAddress.asStringUriOnly(), mShareInfos);
} else {
getFragmentManager().popBackStack();
}
@ -185,7 +185,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
public void onClick(View view) {
if (mChatRoom != null) {
mChatRoom.leave();
LinphoneActivity.instance().goToChat(mGroupChatRoomAddress.asString(), null, mChatRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mGroupChatRoomAddress.asString(), null);
} else {
Log.e("Can't leave, chatRoom for address " + mGroupChatRoomAddress.asString() + " is null...");
}
@ -251,7 +251,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
// This will remove both the creation fragment and the group info fragment from the back stack
getFragmentManager().popBackStack();
getFragmentManager().popBackStack();
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), mShareInfos, cr.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), mShareInfos);
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
@ -322,7 +322,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener {
toAdd.toArray(participantsToAdd);
mChatRoom.addParticipants(participantsToAdd);
LinphoneActivity.instance().goToChat(mGroupChatRoomAddress.asString(), null, mChatRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mGroupChatRoomAddress.asString(), null);
}
}
});

View file

@ -85,7 +85,7 @@ public class ImdnFragment extends Fragment {
@Override
public void onClick(View view) {
if (LinphoneActivity.instance().isTablet()) {
LinphoneActivity.instance().goToChat(mRoomUri, null, mRoom.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(mRoomUri, null);
} else {
LinphoneActivity.instance().onBackPressed();
}

View file

@ -2,23 +2,22 @@ package org.linphone.compatibility;
import android.annotation.TargetApi;
import android.app.FragmentTransaction;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.view.ViewTreeObserver;
import org.linphone.R;
import org.linphone.receivers.NotificationBroadcastReceiver;
import org.linphone.notifications.Notifiable;
import org.linphone.notifications.NotifiableMessage;
import org.linphone.notifications.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_LOCAL_IDENTITY;
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;
@ -52,23 +51,17 @@ public class ApiTwentyFourPlus {
.build();
}
public static Notification createMessageNotification(Context context, int notificationId, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
String title;
if (msgCount == 1) {
title = msgSender;
} else {
title = context.getString(R.string.unread_messages).replace("%i", String.valueOf(msgCount));
}
public static Notification createMessageNotification(Context context, Notifiable notif, Bitmap contactIcon, PendingIntent intent) {
String replyLabel = context.getResources().getString(R.string.notification_reply_label);
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build();
Intent replyIntent = new Intent(context, NotificationBroadcastReceiver.class);
replyIntent.setAction(INTENT_REPLY_NOTIF_ACTION);
replyIntent.putExtra(INTENT_NOTIF_ID, notificationId);
replyIntent.putExtra(INTENT_NOTIF_ID, notif.getNotificationId());
replyIntent.putExtra(INTENT_LOCAL_IDENTITY, notif.getLocalIdentity());
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context,
notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notif.getNotificationId(), replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Action action = new Notification.Action.Builder(R.drawable.chat_send_over,
context.getString(R.string.notification_reply_label), replyPendingIntent)
@ -76,9 +69,13 @@ public class ApiTwentyFourPlus {
.setAllowGeneratedReplies(true)
.build();
Notification.MessagingStyle style = new Notification.MessagingStyle(notif.getMyself());
for (NotifiableMessage message : notif.getMessages()) {
style.addMessage(message.getMessage(), message.getTime(), message.getSender());
}
style.setConversationTitle(notif.getGroupTitle());
return new Notification.Builder(context)
.setContentTitle(title)
.setContentText(msg)
.setSmallIcon(R.drawable.topbar_chat_notification)
.setAutoCancel(true)
.setContentIntent(intent)
@ -87,10 +84,11 @@ public class ApiTwentyFourPlus {
.setCategory(Notification.CATEGORY_MESSAGE)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
.setNumber(msgCount)
.setNumber(notif.getMessages().size())
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setColor(context.getColor(R.color.notification_color_led))
.setStyle(style)
.addAction(action)
.build();
}

View file

@ -11,15 +11,16 @@ import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.view.ViewTreeObserver;
import org.linphone.R;
import org.linphone.mediastream.Log;
import org.linphone.receivers.NotificationBroadcastReceiver;
import org.linphone.notifications.Notifiable;
import org.linphone.notifications.NotifiableMessage;
import org.linphone.notifications.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_LOCAL_IDENTITY;
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;
@ -83,23 +84,17 @@ public class ApiTwentySixPlus {
notificationManager.createNotificationChannel(channel);
}
public static Notification createMessageNotification(Context context, int notificationId, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
String title;
if (msgCount == 1) {
title = msgSender;
} else {
title = context.getString(R.string.unread_messages).replace("%i", String.valueOf(msgCount));
}
public static Notification createMessageNotification(Context context, Notifiable notif, Bitmap contactIcon, PendingIntent intent) {
String replyLabel = context.getResources().getString(R.string.notification_reply_label);
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY).setLabel(replyLabel).build();
Intent replyIntent = new Intent(context, NotificationBroadcastReceiver.class);
replyIntent.setAction(INTENT_REPLY_NOTIF_ACTION);
replyIntent.putExtra(INTENT_NOTIF_ID, notificationId);
replyIntent.putExtra(INTENT_NOTIF_ID, notif.getNotificationId());
replyIntent.putExtra(INTENT_LOCAL_IDENTITY, notif.getLocalIdentity());
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context,
notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notif.getNotificationId(), replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Action action = new Notification.Action.Builder(R.drawable.chat_send_over,
context.getString(R.string.notification_reply_label), replyPendingIntent)
@ -107,9 +102,13 @@ public class ApiTwentySixPlus {
.setAllowGeneratedReplies(true)
.build();
Notification.MessagingStyle style = new Notification.MessagingStyle(notif.getMyself());
for (NotifiableMessage message : notif.getMessages()) {
style.addMessage(message.getMessage(), message.getTime(), message.getSender());
}
style.setConversationTitle(notif.getGroupTitle());
return new Notification.Builder(context, context.getString(R.string.notification_channel_id))
.setContentTitle(title)
.setContentText(msg)
.setSmallIcon(R.drawable.topbar_chat_notification)
.setAutoCancel(true)
.setContentIntent(intent)
@ -118,10 +117,11 @@ public class ApiTwentySixPlus {
.setCategory(Notification.CATEGORY_MESSAGE)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
.setNumber(msgCount)
.setNumber(notif.getMessages().size())
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setColor(context.getColor(R.color.notification_color_led))
.setStyle(style)
.addAction(action)
.build();
}

View file

@ -18,7 +18,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.app.AlarmManager;
import android.app.FragmentTransaction;
import android.app.Notification;
import android.app.PendingIntent;
@ -26,15 +25,11 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.Html;
import android.text.Spanned;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.TextView;
import org.linphone.mediastream.Version;
import org.linphone.notifications.Notifiable;
public class Compatibility {
public static final String KEY_TEXT_REPLY = "key_text_reply";
@ -43,6 +38,7 @@ public class Compatibility {
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 final String INTENT_LOCAL_IDENTITY = "LOCAL_IDENTITY";
public static void createNotificationChannels(Context context) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
@ -65,13 +61,13 @@ public class Compatibility {
return ApiTwentyOnePlus.createMissedCallNotification(context, title, text, intent);
}
public static Notification createMessageNotification(Context context, int notificationId, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
public static Notification createMessageNotification(Context context, Notifiable notif, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
return ApiTwentySixPlus.createMessageNotification(context, notificationId, msgCount, msgSender, msg, contactIcon, intent);
return ApiTwentySixPlus.createMessageNotification(context, notif, contactIcon, intent);
} else if (Version.sdkAboveOrEqual(Version.API24_NOUGAT_70)) {
return ApiTwentyFourPlus.createMessageNotification(context, notificationId, msgCount, msgSender, msg, contactIcon, intent);
return ApiTwentyFourPlus.createMessageNotification(context, notif, contactIcon, intent);
}
return ApiTwentyOnePlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
return ApiTwentyOnePlus.createMessageNotification(context, notif.getMessages().size(), msgSender, msg, contactIcon, intent);
}
public static Notification createRepliedNotification(Context context, String reply) {

View file

@ -85,7 +85,7 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
if (defaultProxyConfig != null) {
ChatRoom room = lc.findOneToOneChatRoom(defaultProxyConfig.getContact(), participant, isSecured);
if (room != null) {
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null, room.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null);
} else {
if (defaultProxyConfig.getConferenceFactoryUri() != null && (isSecured || !LinphonePreferences.instance().useBasicChatRoomFor1To1())) {
mWaitLayout.setVisibility(View.VISIBLE);
@ -96,7 +96,7 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
mChatRoom.addParticipants(participants);
} else {
room = lc.getChatRoom(participant);
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null, room.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null);
}
}
}
@ -144,7 +144,7 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), null, cr.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), null);
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();

View file

@ -30,7 +30,7 @@ public class FirebaseIdService extends FirebaseInstanceIdService {
public void onTokenRefresh() {
// Get updated InstanceID token.
final String refreshedToken = FirebaseInstanceId.getInstance().getToken();
android.util.Log.i("FirebaseIdService", "[Push Notification] Refreshed token: " + refreshedToken);
android.util.Log.i("FirebaseIdService", "[Push Notifiable] Refreshed token: " + refreshedToken);
LinphoneUtils.dispatchOnUIThread(new Runnable() {
@Override

View file

@ -36,10 +36,10 @@ public class FirebaseMessaging extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
android.util.Log.i("FirebaseMessaging", "[Push Notification] Received");
android.util.Log.i("FirebaseMessaging", "[Push Notifiable] Received");
if (!LinphoneService.isReady()) {
android.util.Log.i("FirebaseMessaging", "[Push Notification] Starting Service");
android.util.Log.i("FirebaseMessaging", "[Push Notifiable] Starting Service");
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
} else if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() == 0) {
LinphoneUtils.dispatchOnUIThread(new Runnable() {

View file

@ -109,7 +109,7 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {
if (newState == ChatRoom.State.Created) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), null, cr.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(cr.getPeerAddress().asStringUriOnly(), null);
} else if (newState == ChatRoom.State.CreationFailed) {
mWaitLayout.setVisibility(View.GONE);
LinphoneActivity.instance().displayChatRoomError();
@ -198,7 +198,7 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
Address participant = Factory.instance().createAddress(sipUri);
ChatRoom room = lc.findOneToOneChatRoom(lc.getDefaultProxyConfig().getContact(), participant, false);
if (room != null) {
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null, room.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null);
} else {
ProxyConfig lpc = lc.getDefaultProxyConfig();
if (lpc != null && lpc.getConferenceFactoryUri() != null && !LinphonePreferences.instance().useBasicChatRoomFor1To1()) {
@ -208,7 +208,7 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
mChatRoom.addParticipant(participant);
} else {
room = lc.getChatRoom(participant);
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null, room.getLocalAddress().asString());
LinphoneActivity.instance().goToChat(room.getPeerAddress().asStringUriOnly(), null);
}
}
} else if (id == R.id.add_contact) {

View file

@ -1362,9 +1362,9 @@ public class SettingsFragment extends PreferencesListFragment {
boolean value = (Boolean) newValue;
mPrefs.setServiceNotificationVisibility(value);
if (value) {
LinphoneService.instance().showServiceNotification();
LinphoneService.instance().getNotificationManager().startForeground();
} else {
LinphoneService.instance().hideServiceNotification();
LinphoneService.instance().getNotificationManager().stopForeground();
}
return true;
}

View file

@ -0,0 +1,86 @@
package org.linphone.notifications;
/*
Notifiable.java
Copyright (C) 2018 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import java.util.ArrayList;
import java.util.List;
public class Notifiable {
int mNotificationId;
List<NotifiableMessage> mMessages;
boolean mIsGroup;
String mGroupTitle;
String mLocalIdentity;
String mMyself;
public Notifiable(int id) {
mNotificationId = id;
mMessages = new ArrayList<>();
mIsGroup = false;
}
public int getNotificationId() {
return mNotificationId;
}
public void resetMessages() {
mMessages = new ArrayList<>();
}
public void addMessage(NotifiableMessage notifMessage) {
mMessages.add(notifMessage);
}
public List<NotifiableMessage> getMessages() {
return mMessages;
}
public boolean isGroup() {
return mIsGroup;
}
public void setIsGroup(boolean isGroup) {
mIsGroup = isGroup;
}
public String getGroupTitle() {
return mGroupTitle;
}
public void setGroupTitle(String title) {
mGroupTitle = title;
}
public String getMyself() {
return mMyself;
}
public void setMyself(String myself) {
mMyself = myself;
}
public String getLocalIdentity() {
return mLocalIdentity;
}
public void setLocalIdentity(String localIdentity) {
mLocalIdentity = localIdentity;
}
}

View file

@ -0,0 +1,44 @@
package org.linphone.notifications;
/*
NotifiableMessage.java
Copyright (C) 2018 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
public class NotifiableMessage {
String mMessage;
String mSender;
long mTime;
public NotifiableMessage(String message, String sender, long time) {
mMessage = message;
mSender = sender;
mTime = time;
}
public String getMessage() {
return mMessage;
}
public String getSender() {
return mSender;
}
public long getTime() {
return mTime;
}
}

View file

@ -1,4 +1,4 @@
package org.linphone.receivers;
package org.linphone.notifications;
/*
NotificationBroadcastReceiver.java
@ -29,48 +29,82 @@ import android.os.Bundle;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.activities.LinphoneActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatMessageListenerStub;
import org.linphone.core.ChatRoom;
import org.linphone.core.Core;
import org.linphone.core.ProxyConfig;
import org.linphone.core.Reason;
import org.linphone.mediastream.Log;
public class NotificationBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
public void onReceive(final Context context, Intent intent) {
final int notifId = intent.getIntExtra(Compatibility.INTENT_NOTIF_ID, 0);
final String localyIdentity = intent.getStringExtra(Compatibility.INTENT_LOCAL_IDENTITY);
if (intent.getAction() == Compatibility.INTENT_REPLY_NOTIF_ACTION) {
String reply = getMessageText(intent).toString();
if (reply == null) return;
Notification replied = Compatibility.createRepliedNotification(context, reply);
if (replied == null) return;
int notifId = intent.getIntExtra(Compatibility.INTENT_NOTIF_ID, 0);
String remoteSipAddr = LinphoneService.instance().getSipUriForNotificationId(notifId);
final String reply = getMessageText(intent).toString();
if (reply == null) {
Log.e("Couldn't get reply text");
onError(context, notifId);
return;
}
String remoteSipAddr = LinphoneService.instance().getNotificationManager().getSipUriForNotificationId(notifId);
Core core = LinphoneManager.getLc();
if (core == null) return;
ProxyConfig proxyConfig = core.getDefaultProxyConfig();
if (proxyConfig == null) return;
Address localAddr = proxyConfig.getIdentityAddress();
if (core == null) {
Log.e("Couldn't get Core instance");
onError(context, notifId);
return;
}
Address remoteAddr = core.interpretUrl(remoteSipAddr);
if (localAddr == null || remoteAddr == null) return;
if (remoteAddr == null) {
Log.e("Couldn't interpret remote address " + remoteSipAddr);
onError(context, notifId);
return;
}
Address localAddr = core.interpretUrl(localyIdentity);
if (localAddr == null) {
Log.e("Couldn't interpret local address " + localyIdentity);
onError(context, notifId);
return;
}
ChatRoom room = core.findChatRoom(remoteAddr, localAddr);
if (room == null) return;
if (room == null) {
Log.e("Couldn't find chat room for remote address " + remoteSipAddr + " and local address " + localyIdentity);
onError(context, notifId);
return;
}
room.markAsRead();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount());
}
ChatMessage msg = room.createMessage(reply);
msg.send();
LinphoneService.instance().sendNotification(replied, notifId);
msg.setListener(new ChatMessageListenerStub() {
@Override
public void onMsgStateChanged(ChatMessage msg, ChatMessage.State state) {
if (state == ChatMessage.State.Delivered) {
Notification replied = Compatibility.createRepliedNotification(context, reply);
LinphoneService.instance().getNotificationManager().sendNotification(notifId, replied);
} else if (state == ChatMessage.State.NotDelivered) {
Log.e("Couldn't send reply, message is not delivered");
onError(context, 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);
String remoteAddr = LinphoneService.instance().getNotificationManager().getSipUriForCallNotificationId(notifId);
Core core = LinphoneManager.getLc();
if (core == null) return;
@ -85,6 +119,11 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver {
}
}
private void onError(Context context, int notifId) {
Notification replyError = Compatibility.createRepliedNotification(context, context.getString(R.string.error));
LinphoneService.instance().getNotificationManager().sendNotification(notifId, replyError);
}
@TargetApi(20)
private CharSequence getMessageText(Intent intent) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);

View file

@ -0,0 +1,308 @@
package org.linphone.notifications;
/*
NotificationsManager.java
Copyright (C) 2018 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.LinphoneService;
import org.linphone.LinphoneUtils;
import org.linphone.R;
import org.linphone.activities.LinphoneActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Address;
import org.linphone.core.Call;
import org.linphone.mediastream.Version;
import java.util.HashMap;
import static android.content.Context.NOTIFICATION_SERVICE;
public class NotificationsManager {
private static final int SERVICE_NOTIF_ID = 1;
private static final int MISSED_CALLS_NOTIF_ID = 2;
private static final int IN_APP_NOTIF_ID = 3;
private Context mContext;
private NotificationManager mNM;
private HashMap<String, Notifiable> mChatNotifMap, mCallNotifMap;
private int mLastNotificationId;
private PendingIntent mPendingIntent;
private Notification mServiceNotification;
public NotificationsManager(Context context) {
mContext = context;
mChatNotifMap = new HashMap<>();
mCallNotifMap = new HashMap<>();
mNM = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
mNM.cancelAll();
mLastNotificationId = 5; // Do not conflict with hardcoded notifications ids !
Compatibility.createNotificationChannels(mContext);
Intent notifIntent = new Intent(mContext, LinphoneService.instance().getIncomingReceivedActivity());
notifIntent.putExtra("Notifiable", true);
mPendingIntent = PendingIntent.getActivity(mContext, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//Disable service notification for Android O
if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
LinphonePreferences.instance().setServiceNotificationVisibility(false);
}
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher);
} catch (Exception e) {
}
mServiceNotification = Compatibility.createNotification(mContext, mContext.getString(R.string.service_name), "",
R.drawable.linphone_notification_icon, R.mipmap.ic_launcher, bm, mPendingIntent, true,
Notification.PRIORITY_MIN);
if (isServiceNotificationDisplayed()) {
startForeground();
}
}
public void destroy() {
mNM.cancelAll();
}
public void startForeground() {
LinphoneService.instance().startForeground(SERVICE_NOTIF_ID, mServiceNotification);
}
public void stopForeground() {
LinphoneService.instance().stopForeground(true);
}
public void sendNotification(int id, Notification notif) {
mNM.notify(id, notif);
}
public void resetMessageNotifCount(String address) {
Notifiable notif = mChatNotifMap.get(address);
if (notif != null) {
notif.resetMessages();
mNM.cancel(notif.getNotificationId());
}
}
public boolean isServiceNotificationDisplayed() {
return LinphonePreferences.instance().getServiceNotificationVisibility();
}
public String getSipUriForNotificationId(int notificationId) {
for (String addr : mChatNotifMap.keySet()) {
if (mChatNotifMap.get(addr).getNotificationId() == notificationId) {
return addr;
}
}
return null;
}
public void displayGroupChatMessageNotification(String subject, String conferenceAddress, String fromName, Uri fromPictureUri, String message, Address localIdentity) {
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
notifIntent.putExtra("GoToChat", true);
notifIntent.putExtra("ChatContactSipUri", conferenceAddress);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notifiable notif = mChatNotifMap.get(conferenceAddress);
NotifiableMessage notifMessage = new NotifiableMessage(message, fromName, 0);
if (notif == null) {
notif = new Notifiable(mLastNotificationId);
mLastNotificationId += 1;
mChatNotifMap.put(conferenceAddress, notif);
}
notif.addMessage(notifMessage);
notif.setIsGroup(true);
notif.setGroupTitle(subject);
notif.setMyself(LinphoneUtils.getAddressDisplayName(localIdentity));
notif.setLocalIdentity(localIdentity.asString());
Bitmap bm;
if (fromPictureUri != null) {
try {
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), fromPictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_group_avatar);
}
} else {
bm = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.topbar_avatar);
}
Notification notification = Compatibility.createMessageNotification(mContext, notif, subject,
mContext.getString(R.string.group_chat_notif).replace("%1", fromName).replace("%2", message), bm, pendingIntent);
sendNotification(notif.getNotificationId(), notification);
}
public void displayMessageNotification(String fromSipUri, String fromName, Uri fromPictureUri, String message, Address localIdentity) {
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
notifIntent.putExtra("GoToChat", true);
notifIntent.putExtra("ChatContactSipUri", fromSipUri);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (fromName == null) {
fromName = fromSipUri;
}
Notifiable notif = mChatNotifMap.get(fromSipUri);
NotifiableMessage notifMessage = new NotifiableMessage(message, fromName, 0);
if (notif == null) {
notif = new Notifiable(mLastNotificationId);
mLastNotificationId += 1;
mChatNotifMap.put(fromSipUri, notif);
}
notif.addMessage(notifMessage);
notif.setIsGroup(false);
notif.setMyself(LinphoneUtils.getAddressDisplayName(localIdentity));
notif.setLocalIdentity(localIdentity.asString());
Bitmap bm;
if (fromPictureUri != null) {
try {
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), fromPictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.topbar_avatar);
}
} else {
bm = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.topbar_avatar);
}
Notification notification = Compatibility.createMessageNotification(mContext, notif, fromName, message, bm, pendingIntent);
sendNotification(notif.getNotificationId(), notification);
}
public void displayMissedCallNotification(Call call) {
Intent missedCallNotifIntent = new Intent(mContext, LinphoneService.instance().getIncomingReceivedActivity());
missedCallNotifIntent.putExtra("GoToHistory", true);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, missedCallNotifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
int missedCallCount = LinphoneManager.getLcIfManagerNotDestroyedOrNull().getMissedCallsCount();
String body;
if (missedCallCount > 1) {
body = mContext.getString(R.string.missed_calls_notif_body).replace("%i", String.valueOf(missedCallCount));
} else {
Address address = call.getRemoteAddress();
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
if (c != null) {
body = c.getFullName();
} else {
body = address.getDisplayName();
if (body == null) {
body = address.asStringUriOnly();
}
}
}
Notification notif = Compatibility.createMissedCallNotification(mContext, mContext.getString(R.string.missed_calls_notif_title), body, pendingIntent);
sendNotification(MISSED_CALLS_NOTIF_ID, notif);
}
public void displayCallNotification(Call call) {
if (call == null) return;
Address address = call.getRemoteAddress();
String addressAsString = address.asStringUriOnly();
Notifiable notif = mCallNotifMap.get(addressAsString);
if (notif == null) {
notif = new Notifiable(mLastNotificationId);
mLastNotificationId += 1;
mCallNotifMap.put(addressAsString, notif);
}
if (!isServiceNotificationDisplayed()) {
if (call.getCore().getCallsNb() == 0) {
stopForeground();
} else {
startForeground();
}
}
int notificationTextId;
int iconId;
switch (call.getState()) {
case Released:
case End:
mNM.cancel(notif.getNotificationId());
mCallNotifMap.remove(addressAsString);
return;
case Paused:
case PausedByRemote:
case Pausing:
iconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_paused;
break;
default:
if (call.getCurrentParams().videoEnabled()) {
iconId = R.drawable.topbar_videocall_notification;
notificationTextId = R.string.incall_notif_video;
} else {
iconId = R.drawable.topbar_call_notification;
notificationTextId = R.string.incall_notif_active;
}
break;
}
LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address);
Uri pictureUri = contact != null ? contact.getPhotoUri() : null;
Bitmap bm;
try {
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), pictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.avatar);
}
String name = LinphoneUtils.getAddressDisplayName(address);
boolean showAnswerAction = call.getState() == Call.State.IncomingReceived || call.getState() == Call.State.IncomingEarlyMedia;
Notification notification = Compatibility.createInCallNotification(mContext, notif.getNotificationId(),
showAnswerAction, mContext.getString(R.string.service_name),
mContext.getString(notificationTextId), iconId, bm, name, mPendingIntent);
sendNotification(notif.getNotificationId(), notification);
}
public String getSipUriForCallNotificationId(int notificationId) {
for (String addr : mCallNotifMap.keySet()) {
if (mCallNotifMap.get(addr).getNotificationId() == notificationId) {
return addr;
}
}
return null;
}
public void displayInappNotification(String message) {
Intent notifIntent = new Intent(mContext, LinphoneActivity.class);
notifIntent.putExtra("GoToInapp", true);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, 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);
}
}