* #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