* #36758: refactor of navigation in app
diff --git a/src/org/sflphone/utils/MediaManager.java b/src/org/sflphone/utils/MediaManager.java
index 82d7554..c42d6c4 100644
--- a/src/org/sflphone/utils/MediaManager.java
+++ b/src/org/sflphone/utils/MediaManager.java
@@ -14,11 +14,14 @@
private SipService mService;
private SettingsContentObserver mSettingsContentObserver;
AudioManager mAudioManager;
+ private Ringer ringer;
public MediaManager(SipService aService) {
mService = aService;
mSettingsContentObserver = new SettingsContentObserver(mService, new Handler());
mAudioManager = (AudioManager) aService.getSystemService(Context.AUDIO_SERVICE);
+
+ ringer = new Ringer(aService);
}
public void startService() {
@@ -63,4 +66,30 @@
public void RouteToInternalSpeaker() {
mAudioManager.setSpeakerphoneOn(false);
}
+
+
+ /**
+ * Start ringing announce for a given contact.
+ * It will also focus audio for us.
+ * @param remoteContact the contact to ring for. May resolve the contact ringtone if any.
+ */
+ synchronized public void startRing(String remoteContact) {
+
+ if(!ringer.isRinging()) {
+ ringer.ring(remoteContact, "USELESS");
+ }else {
+ Log.d(TAG, "Already ringing ....");
+ }
+
+ }
+
+ /**
+ * Stop all ringing. <br/>
+ * Warning, this will not unfocus audio.
+ */
+ synchronized public void stopRing() {
+ if(ringer.isRinging()) {
+ ringer.stopRing();
+ }
+ }
}
diff --git a/src/org/sflphone/utils/Ringer.java b/src/org/sflphone/utils/Ringer.java
new file mode 100644
index 0000000..075f790
--- /dev/null
+++ b/src/org/sflphone/utils/Ringer.java
@@ -0,0 +1,153 @@
+package org.sflphone.utils;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Vibrator;
+import android.util.Log;
+
+
+/**
+ * Ringer manager for the Phone app.
+ */
+public class Ringer {
+ private static final String THIS_FILE = "Ringer";
+
+ private static final int VIBRATE_LENGTH = 1000; // ms
+ private static final int PAUSE_LENGTH = 1000; // ms
+
+ // Uri for the ringtone.
+ Uri customRingtoneUri;
+
+ Vibrator vibrator;
+ VibratorThread vibratorThread;
+ Context context;
+
+ public Ringer(Context aContext) {
+ context = aContext;
+ vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ }
+
+ /**
+ * Starts the ringtone and/or vibrator.
+ *
+ */
+ public void ring(String remoteContact, String defaultRingtone) {
+ Log.d(THIS_FILE, "==> ring() called...");
+
+ synchronized (this) {
+
+ AudioManager audioManager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
+ //Save ringtone at the begining in case we raise vol
+// ringtone = getRingtone(remoteContact, defaultRingtone);
+
+ //No ring no vibrate
+ int ringerMode = audioManager.getRingerMode();
+ if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+ Log.d(THIS_FILE, "skipping ring and vibrate because profile is Silent");
+ return;
+ }
+
+ // Vibrate
+ int vibrateSetting = audioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
+ Log.d(THIS_FILE, "v=" + vibrateSetting + " rm=" + ringerMode);
+ if (vibratorThread == null &&
+ (vibrateSetting == AudioManager.VIBRATE_SETTING_ON ||
+ ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
+ vibratorThread = new VibratorThread();
+ Log.d(THIS_FILE, "Starting vibrator...");
+ vibratorThread.start();
+ }
+
+ // Vibrate only
+ if (ringerMode == AudioManager.RINGER_MODE_VIBRATE ||
+ audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0 ) {
+ Log.d(THIS_FILE, "skipping ring because profile is Vibrate OR because volume is zero");
+ return;
+ }
+
+ }
+ }
+
+ /**
+ * @return true if we're playing a ringtone and/or vibrating
+ * to indicate that there's an incoming call.
+ * ("Ringing" here is used in the general sense. If you literally
+ * need to know if we're playing a ringtone or vibrating, use
+ * isRingtonePlaying() or isVibrating() instead.)
+ */
+ public boolean isRinging() {
+ return (vibratorThread != null);
+ }
+
+ /**
+ * Stops the ringtone and/or vibrator if any of these are actually
+ * ringing/vibrating.
+ */
+ public void stopRing() {
+ synchronized (this) {
+ Log.d(THIS_FILE, "==> stopRing() called...");
+
+ stopVibrator();
+ }
+ }
+
+
+ private void stopVibrator() {
+
+ if (vibratorThread != null) {
+ vibratorThread.interrupt();
+ try {
+ vibratorThread.join(250); // Should be plenty long (typ.)
+ } catch (InterruptedException e) {
+ } // Best efforts (typ.)
+ vibratorThread = null;
+ }
+ }
+
+ public void updateRingerMode() {
+
+ AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ synchronized (this) {
+ int ringerMode = audioManager.getRingerMode();
+ // Silent : stop everything
+ if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+ stopRing();
+ return;
+ }
+
+ // Vibrate
+ int vibrateSetting = audioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
+ // If not already started restart it
+ if (vibratorThread == null && (vibrateSetting == AudioManager.VIBRATE_SETTING_ON || ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
+ vibratorThread = new VibratorThread();
+ vibratorThread.start();
+ }
+
+ // Vibrate only
+ if (ringerMode == AudioManager.RINGER_MODE_VIBRATE || audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0) {
+ return;
+ }
+
+ }
+ }
+
+ private class VibratorThread extends Thread {
+ public void run() {
+ try {
+ while (true) {
+ vibrator.vibrate(VIBRATE_LENGTH);
+ Thread.sleep(VIBRATE_LENGTH + PAUSE_LENGTH);
+ }
+ } catch (InterruptedException ex) {
+ Log.d(THIS_FILE, "Vibrator thread interrupt");
+ } finally {
+ vibrator.cancel();
+ }
+ Log.d(THIS_FILE, "Vibrator thread exiting");
+ }
+ }
+
+}
diff --git a/src/org/sflphone/utils/SipNotifications.java b/src/org/sflphone/utils/SipNotifications.java
index 7ec35e4..0086c1e 100644
--- a/src/org/sflphone/utils/SipNotifications.java
+++ b/src/org/sflphone/utils/SipNotifications.java
@@ -33,8 +33,8 @@
package org.sflphone.utils;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Random;
import org.sflphone.R;
import org.sflphone.client.HomeActivity;
@@ -43,7 +43,6 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
@@ -55,21 +54,17 @@
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
-import android.util.Log;
public class SipNotifications {
private final NotificationManager notificationManager;
private final Context context;
- private Builder inCallNotification;
- private Builder missedCallNotification;
- private Builder messageNotification;
- private Builder messageVoicemail;
- private boolean resolveContacts = true;
public static final String NOTIF_CREATION = "notif_creation";
public static final String NOTIF_DELETION = "notif_deletion";
+ private final int NOTIFICATION_ID = new Random().nextInt(1000);
+
public static final int REGISTER_NOTIF_ID = 1;
public static final int CALL_NOTIF_ID = REGISTER_NOTIF_ID + 1;
public static final int CALLLOG_NOTIF_ID = REGISTER_NOTIF_ID + 2;
@@ -90,86 +85,10 @@
}
- // Foreground api
-
- private static final Class<?>[] SET_FG_SIG = new Class[] { boolean.class };
- private static final Class<?>[] START_FG_SIG = new Class[] { int.class, Notification.class };
- private static final Class<?>[] STOP_FG_SIG = new Class[] { boolean.class };
private static final String THIS_FILE = "Notifications";
- private Method mSetForeground;
- 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 void invokeMethod(Method method, Object[] args) {
- try {
- method.invoke(context, args);
- } catch (InvocationTargetException e) {
- // Should not happen.
- Log.w(THIS_FILE, "Unable to invoke method", e);
- } catch (IllegalAccessException e) {
- // Should not happen.
- Log.w(THIS_FILE, "Unable to invoke method", e);
- }
- }
-
- /**
- * This is a wrapper around the new startForeground method, using the older APIs if it is not available.
- */
- private 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;
- }
-
- // Fall back on the old API.
- mSetForegroundArgs[0] = Boolean.TRUE;
- invokeMethod(mSetForeground, mSetForegroundArgs);
- notificationManager.notify(id, notification);
- }
-
- /**
- * This is a wrapper around the new stopForeground method, using the older APIs if it is not available.
- */
- private 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;
- }
-
- // Fall back on the old API. Note to cancel BEFORE changing the
- // foreground state, since we could be killed at that point.
- notificationManager.cancel(id);
- mSetForegroundArgs[0] = Boolean.FALSE;
- invokeMethod(mSetForeground, mSetForegroundArgs);
- }
-
- private boolean isServiceWrapper = false;
-
public void onServiceCreate() {
- try {
- mStartForeground = context.getClass().getMethod("startForeground", START_FG_SIG);
- mStopForeground = context.getClass().getMethod("stopForeground", STOP_FG_SIG);
- isServiceWrapper = true;
- return;
- } catch (NoSuchMethodException e) {
- // Running on an older platform.
- mStartForeground = mStopForeground = null;
- }
- try {
- mSetForeground = context.getClass().getMethod("setForeground", SET_FG_SIG);
- } catch (NoSuchMethodException e) {
- throw new IllegalStateException("OS doesn't have Service.startForeground OR Service.setForeground!");
- }
- isServiceWrapper = true;
+
}
public void onServiceDestroy() {
@@ -178,77 +97,6 @@
cancelCalls();
}
- // Announces
-
- // // Register
- // public synchronized void notifyRegisteredAccounts(ArrayList<SipProfileState> activeAccountsInfos, boolean showNumbers) {
- // if (!isServiceWrapper) {
- // Log.e(THIS_FILE, "Trying to create a service notification from outside the service");
- // return;
- // }
- // int icon = R.drawable.ic_stat_sipok;
- // CharSequence tickerText = context.getString(R.string.service_ticker_registered_text);
- // long when = System.currentTimeMillis();
- //
- //
- // Builder nb = new NotificationCompat.Builder(context);
- // nb.setSmallIcon(icon);
- // nb.setTicker(tickerText);
- // nb.setWhen(when);
- // Intent notificationIntent = new Intent(SipManager.ACTION_SIP_DIALER);
- // notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- //
- // RegistrationNotification contentView = new RegistrationNotification(context.getPackageName());
- // contentView.clearRegistrations();
- // if(!Compatibility.isCompatible(9)) {
- // contentView.setTextsColor(notificationPrimaryTextColor);
- // }
- // contentView.addAccountInfos(context, activeAccountsInfos);
- //
- // // notification.setLatestEventInfo(context, contentTitle,
- // // contentText, contentIntent);
- // nb.setOngoing(true);
- // nb.setOnlyAlertOnce(true);
- // nb.setContentIntent(contentIntent);
- // nb.setContent(contentView);
- //
- // Notification notification = nb.build();
- // notification.flags |= Notification.FLAG_NO_CLEAR;
- // // We have to re-write content view because getNotification setLatestEventInfo implicitly
- // notification.contentView = contentView;
- // if (showNumbers) {
- // // This only affects android 2.3 and lower
- // notification.number = activeAccountsInfos.size();
- // }
- // startForegroundCompat(REGISTER_NOTIF_ID, notification);
- // }
-
- /**
- * Format the remote contact name for the call info
- *
- * @param callInfo
- * the callinfo to format
- * @return the name to display for the contact
- */
- private String formatRemoteContactString(String remoteContact) {
- String formattedRemoteContact = remoteContact;
- // TODO
- return formattedRemoteContact;
- }
-
- /**
- * Format the notification title for a call info
- *
- * @param title
- * @param callInfo
- * @return
- */
- private String formatNotificationTitle(int title, long accId) {
- // TODO
- return null;
- }
-
// Calls
public void showNotificationForCall(SipCall callInfo) {
// TODO
@@ -258,12 +106,6 @@
// TODO
}
- private static String viewingRemoteFrom = null;
-
- public void setViewingMessageFrom(String remoteFrom) {
- viewingRemoteFrom = remoteFrom;
- }
-
protected static CharSequence buildTickerMessage(Context context, String address, String body) {
String displayAddress = address;
@@ -283,15 +125,6 @@
return spanText;
}
- // Cancels
- public final void cancelRegisters() {
- if (!isServiceWrapper) {
- Log.e(THIS_FILE, "Trying to cancel a service notification from outside the service");
- return;
- }
- stopForegroundCompat(REGISTER_NOTIF_ID);
- }
-
public final void cancelCalls() {
notificationManager.cancel(CALL_NOTIF_ID);
}
@@ -309,11 +142,6 @@
}
public final void cancelAll() {
- // Do not cancel calls notification since it's possible that there is
- // still an ongoing call.
- if (isServiceWrapper) {
- cancelRegisters();
- }
cancelMessages();
cancelMissedCalls();
cancelVoicemails();
@@ -333,7 +161,7 @@
nb.setContentTitle(context.getString(R.string.notif_missed_call_title));
nb.setContentText(context.getString(R.string.notif_missed_call_content, sipCall.getContact().getmDisplayName()));
Intent notificationIntent = new Intent(context, HomeActivity.class);
- notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// notification.setLatestEventInfo(context, contentTitle,
@@ -348,4 +176,29 @@
// startForegroundCompat(CALL_NOTIF_ID, notification);
notificationManager.notify(CALL_NOTIF_ID, notification);
}
+
+ public void makeNotification(HashMap<String, SipCall> calls) {
+ if (calls.size() == 0) {
+ return;
+ }
+ Intent notificationIntent = new Intent(context, HomeActivity.class);
+ PendingIntent contentIntent = PendingIntent.getActivity(context, 007, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.cancel(NOTIFICATION_ID); // clear previous notifications.
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+
+ builder.setContentIntent(contentIntent).setOngoing(true).setSmallIcon(R.drawable.ic_launcher)
+ .setContentTitle(calls.size() + " ongoing calls").setTicker("Pending calls").setWhen(System.currentTimeMillis()).setAutoCancel(false);
+ builder.setPriority(NotificationCompat.PRIORITY_MAX);
+ Notification n = builder.build();
+
+ nm.notify(NOTIFICATION_ID, n);
+ }
+
+ public void removeNotification() {
+ NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.cancel(NOTIFICATION_ID);
+ }
}
\ No newline at end of file