* #32381: added proper screenlock (based on CSipSimple mechanism)
diff --git a/src/org/sflphone/client/CallActivity.java b/src/org/sflphone/client/CallActivity.java
index b018bbf..03485d6 100644
--- a/src/org/sflphone/client/CallActivity.java
+++ b/src/org/sflphone/client/CallActivity.java
@@ -46,6 +46,8 @@
 import org.sflphone.service.CallManagerCallBack;
 import org.sflphone.service.ISipService;
 import org.sflphone.service.SipService;
+import org.sflphone.utils.CallProximityManager;
+import org.sflphone.utils.CallProximityManager.ProximityDirector;
 import org.sflphone.views.CallPaneLayout;
 
 import android.app.Activity;
@@ -68,7 +70,7 @@
 import android.view.Window;
 import android.widget.Toast;
 
-public class CallActivity extends Activity implements CallInterface, CallFragment.Callbacks{
+public class CallActivity extends Activity implements CallInterface, CallFragment.Callbacks, ProximityDirector{
     static final String TAG = "CallActivity";
     private ISipService service;
 
@@ -82,6 +84,8 @@
 
     /* result code sent in case of call failure */
     public static int RESULT_FAILURE = -10;
+    
+    private CallProximityManager proximityManager;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -90,9 +94,7 @@
 
         receiver = new CallReceiver(this);
 
-        // mCallsFragment = new CallListFragment();
-
-        // getFragmentManager().beginTransaction().replace(R.id.calllist_pane, mCallsFragment).commit();
+        proximityManager = new CallProximityManager(this, this);
 
         slidingPaneLayout = (CallPaneLayout) findViewById(R.id.slidingpanelayout);
 
@@ -121,6 +123,7 @@
             }
         });
 
+        proximityManager.startTracking();
         Intent intent = new Intent(this, SipService.class);
         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
     }
@@ -182,6 +185,8 @@
     protected void onDestroy() {
         unregisterReceiver(receiver);
         unbindService(mConnection);
+        proximityManager.stopTracking();
+        proximityManager.release(0);
         super.onDestroy();
     }
 
@@ -268,9 +273,10 @@
 
         if (mCurrentCallFragment != null) {
             mCurrentCallFragment.changeCallState(callID, newState);
-            
         }
 
+        proximityManager.updateProximitySensorMode();
+        
         try {
             HashMap<String, SipCall> callMap = (HashMap<String, SipCall>) service.getCallList();
             HashMap<String, Conference> confMap = (HashMap<String, Conference>) service.getConferenceList();
@@ -399,4 +405,15 @@
     public void slideChatScreen() {
         slidingPaneLayout.openPane();
     }
+
+    @Override
+    public boolean shouldActivateProximity() {
+        return true;
+    }
+
+    @Override
+    public void onProximityTrackingChanged(boolean acquired) {
+        // TODO Stub de la méthode généré automatiquement
+        
+    }
 }
diff --git a/src/org/sflphone/fragments/CallFragment.java b/src/org/sflphone/fragments/CallFragment.java
index 858be93..08e27b3 100644
--- a/src/org/sflphone/fragments/CallFragment.java
+++ b/src/org/sflphone/fragments/CallFragment.java
@@ -31,6 +31,8 @@
 
 package org.sflphone.fragments;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -45,6 +47,7 @@
 import org.sflphone.model.Conference;
 import org.sflphone.model.SipCall;
 import org.sflphone.service.ISipService;
+import org.sflphone.utils.CallProximityManager;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -59,6 +62,7 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.os.Bundle;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -71,12 +75,11 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.ImageButton;
 import android.widget.TextView;
 
-public class CallFragment extends Fragment implements Callback, SensorEventListener {
+public class CallFragment extends Fragment implements Callback{
 
     static final String TAG = "CallFragment";
 
@@ -88,6 +91,8 @@
     private Conference conf;
 
     private TextView callStatusTxt;
+    private TextView codecNameTxt;
+
     private BubblesView view;
     private BubbleModel model;
 
@@ -98,10 +103,19 @@
     private SensorManager mSensorManager;
 
     private Sensor mSensor;
-    
+
     TransferDFragment editName;
 
-    private TextView codecNameTxt;
+    private PowerManager.WakeLock fullLock;
+    private PowerManager.WakeLock partialLock;
+    private PowerManager.WakeLock proximityLock;
+    
+    private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
+    private static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
+    
+    private Method wakelockParameterizedRelease;
+
+    
 
     @Override
     public void onCreate(Bundle savedBundle) {
@@ -115,6 +129,22 @@
         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
         this.setHasOptionsMenu(true);
 
+
+        
+//        PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
+//        fullLock = pm.newWakeLock(PowerManager.ON_AFTER_RELEASE | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
+//        partialLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+//        proximityLock = pm.newWakeLock(PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
+//        
+//        Method maybeRelease = null;
+//        try {
+//          maybeRelease = proximityLock.getClass().getDeclaredMethod("release", Integer.TYPE);
+//        } catch (NoSuchMethodException e) {
+//          Log.d("LockManager", "Parameterized WakeLock release not available on this device.");
+//        }
+//        wakelockParameterizedRelease = maybeRelease;
+        
+
     }
 
     /**
@@ -122,7 +152,6 @@
      */
     private static Callbacks sDummyCallbacks = new Callbacks() {
 
-
         @Override
         public ISipService getService() {
             return null;
@@ -137,7 +166,7 @@
         }
 
         @Override
-        public void slideChatScreen() {            
+        public void slideChatScreen() {
         }
     };
 
@@ -152,7 +181,7 @@
         public void startTimer();
 
         public void slideChatScreen();
-        
+
         public void replaceCurrentCallDisplayed();
     }
 
@@ -167,10 +196,10 @@
         // rootView.requestDisallowInterceptTouchEvent(true);
 
         mCallbacks = (Callbacks) activity;
-//        myself = SipCall.SipCallBuilder.buildMyselfCall(activity.getContentResolver(), "Me");
+        // myself = SipCall.SipCallBuilder.buildMyselfCall(activity.getContentResolver(), "Me");
 
     }
-    
+
     @Override
     public void onCreateOptionsMenu(Menu m, MenuInflater inf) {
         super.onCreateOptionsMenu(m, inf);
@@ -180,11 +209,11 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         super.onOptionsItemSelected(item);
-//        switch (item.getItemId()) {
-//        case R.id.menuitem_chat:
-//            mCallbacks.slideChatScreen();
-//            break;
-//        }
+        // switch (item.getItemId()) {
+        // case R.id.menuitem_chat:
+        // mCallbacks.slideChatScreen();
+        // break;
+        // }
 
         return true;
     }
@@ -193,7 +222,7 @@
     public void onDetach() {
         super.onDetach();
         mCallbacks = sDummyCallbacks;
-        mSensorManager.unregisterListener(this);
+//        mSensorManager.unregisterListener(this);
     }
 
     @Override
@@ -204,13 +233,13 @@
     @Override
     public void onResume() {
         super.onResume();
-        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
+//        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        mSensorManager.unregisterListener(this);
+//        mSensorManager.unregisterListener(this);
     }
 
     @Override
@@ -361,7 +390,7 @@
     private Bubble getBubbleFor(SipCall call, float x, float y) {
         Bubble contact_bubble = model.getBubble(call.getCallId());
         if (contact_bubble != null) {
-            ((BubbleContact)contact_bubble).setCall(call);
+            ((BubbleContact) contact_bubble).setCall(call);
             contact_bubble.attractor.set(x, y);
             return contact_bubble;
         }
@@ -371,16 +400,17 @@
         model.addBubble(contact_bubble);
         return contact_bubble;
     }
-    
+
     private Bubble getBubbleForUser(Conference conf, float x, float y) {
         Bubble contact_bubble = model.getBubble(conf.getId());
         if (contact_bubble != null) {
             contact_bubble.attractor.set(x, y);
-            ((BubbleUser)contact_bubble).setConference(conf);
+            ((BubbleUser) contact_bubble).setConference(conf);
             return contact_bubble;
         }
 
-        contact_bubble = new BubbleUser(getActivity(), CallContact.ContactBuilder.buildUserContact(getActivity().getContentResolver(), getResources().getString(R.string.me)), conf, x, y, BUBBLE_SIZE);
+        contact_bubble = new BubbleUser(getActivity(), CallContact.ContactBuilder.buildUserContact(getActivity().getContentResolver(), getResources()
+                .getString(R.string.me)), conf, x, y, BUBBLE_SIZE);
 
         model.addBubble(contact_bubble);
         return contact_bubble;
@@ -390,9 +420,9 @@
      * Should be called when a bubble is removed from the model
      */
     void bubbleRemoved(Bubble b) {
-//        if (b.associated_call == null) {
-//            return;
-//        }
+        // if (b.associated_call == null) {
+        // return;
+        // }
     }
 
     public void changeCallState(String callID, String newState) {
@@ -468,7 +498,7 @@
         editName = TransferDFragment.newInstance();
         Bundle b = new Bundle();
         try {
-            b.putParcelableArrayList("calls", (ArrayList<Conference>)mCallbacks.getService().getConcurrentCalls());
+            b.putParcelableArrayList("calls", (ArrayList<Conference>) mCallbacks.getService().getConcurrentCalls());
             b.putParcelable("call_selected", contact.associated_call);
             editName.setArguments(b);
             editName.setTargetFragment(this, REQUEST_TRANSFER);
@@ -489,7 +519,7 @@
         // check that soft input is hidden
         InputMethodManager lManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
         lManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
-        if(editName != null && editName.isVisible()){
+        if (editName != null && editName.isVisible()) {
             editName.dismiss();
         }
     }
@@ -503,28 +533,46 @@
         callStatusTxt.setText(String.format("%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
     }
 
-    @Override
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+//    @Override
+//    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+//
+//    }
 
-    }
-
-    @Override
-    public void onSensorChanged(SensorEvent event) {
-        if (event.values[0] == 0) {
-            WindowManager.LayoutParams params = getActivity().getWindow().getAttributes();
-            params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-            params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-            params.screenBrightness = 0.004f;
-            getActivity().getWindow().setAttributes(params);
-
-        } else {
-            WindowManager.LayoutParams params = getActivity().getWindow().getAttributes();
-            getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
-            params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-            params.screenBrightness = 1.0f;
-            getActivity().getWindow().setAttributes(params);
-        }
-    }
+//    @Override
+//    public void onSensorChanged(SensorEvent event) {
+//        if (event.values[0] == 0) {
+//            // WindowManager.LayoutParams params = getActivity().getWindow().getAttributes();
+//            // params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+//            // params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+//            // params.screenBrightness = -1f;
+//            // getActivity().getWindow().setAttributes(params);
+//
+//        } else {
+//            // WindowManager.LayoutParams params = getActivity().getWindow().getAttributes();
+//            // getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+//            // params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+//            // params.screenBrightness = 1.0f;
+//            // getActivity().getWindow().setAttributes(params);
+//        }
+//    }
+    
+//    private void releaseProximityLock() {
+//        boolean released = false;
+//        if (wakelockParameterizedRelease != null) {
+//          try {
+//            wakelockParameterizedRelease.invoke(proximityLock, new Integer(WAIT_FOR_PROXIMITY_NEGATIVE));
+//            released = true;
+//          } catch (IllegalAccessException e) {
+//            Log.d("LockManager", "Failed to invoke release method", e);
+//          } catch (InvocationTargetException e) {
+//            Log.d("LockManager", "Failed to invoke release method", e);
+//          }
+//        }
+//
+//        if(!released) {
+//          proximityLock.release();
+//        }
+//      }
 
     public Conference getConference() {
         return conf;
@@ -532,11 +580,10 @@
 
     public void onKeyUp(int keyCode, KeyEvent event) {
         try {
-            
-            if(event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)
+
+            if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)
                 return;
-            
-            
+
             String toSend = Character.toString(event.getDisplayLabel());
             toSend.toUpperCase(Locale.getDefault());
             Log.d(TAG, "toSend " + toSend);
diff --git a/src/org/sflphone/utils/AccelerometerListener.java b/src/org/sflphone/utils/AccelerometerListener.java
new file mode 100644
index 0000000..adc5c0f
--- /dev/null
+++ b/src/org/sflphone/utils/AccelerometerListener.java
@@ -0,0 +1,190 @@
+/*
+ *  Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
+ *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ *  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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+package org.sflphone.utils;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.Message;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * This class is used to listen to the accelerometer to monitor the orientation of the phone. The client of this class is notified when the
+ * orientation changes between horizontal and vertical.
+ */
+public final class AccelerometerListener {
+    private static final String TAG = "AccelerometerListener";
+    private static final boolean DEBUG = true;
+    private static final boolean VDEBUG = false;
+
+    private SensorManager mSensorManager;
+    private Sensor mSensor;
+
+    // mOrientation is the orientation value most recently reported to the client.
+    private int mOrientation;
+
+    // mPendingOrientation is the latest orientation computed based on the sensor value.
+    // This is sent to the client after a rebounce delay, at which point it is copied to
+    // mOrientation.
+    private int mPendingOrientation;
+
+    private OrientationListener mListener;
+
+    // Device orientation
+    public static final int ORIENTATION_UNKNOWN = 0;
+    public static final int ORIENTATION_VERTICAL = 1;
+    public static final int ORIENTATION_HORIZONTAL = 2;
+
+    private static final int ORIENTATION_CHANGED = 1234;
+
+    private static final int VERTICAL_DEBOUNCE = 100;
+    private static final int HORIZONTAL_DEBOUNCE = 500;
+    private static final double VERTICAL_ANGLE = 50.0;
+
+    public interface OrientationListener {
+        public void orientationChanged(int orientation);
+    }
+
+    public AccelerometerListener(Context context, OrientationListener listener) {
+        mListener = listener;
+        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+    }
+
+    public void enable(boolean enable) {
+//        if (DEBUG)
+//            Log.d(TAG, "enable(" + enable + ")");
+        synchronized (this) {
+            if (enable) {
+                mOrientation = ORIENTATION_UNKNOWN;
+                mPendingOrientation = ORIENTATION_UNKNOWN;
+                mSensorManager.registerListener(mSensorListener, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
+            } else {
+                mSensorManager.unregisterListener(mSensorListener);
+                mHandler.removeMessages(ORIENTATION_CHANGED);
+            }
+        }
+    }
+
+    private void setOrientation(int orientation) {
+        synchronized (this) {
+            if (mPendingOrientation == orientation) {
+                // Pending orientation has not changed, so do nothing.
+                return;
+            }
+
+            // Cancel any pending messages.
+            // We will either start a new timer or cancel alltogether
+            // if the orientation has not changed.
+            mHandler.removeMessages(ORIENTATION_CHANGED);
+
+            if (mOrientation != orientation) {
+                // Set timer to send an event if the orientation has changed since its
+                // previously reported value.
+                mPendingOrientation = orientation;
+                Message m = mHandler.obtainMessage(ORIENTATION_CHANGED);
+                // set delay to our debounce timeout
+                int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE : HORIZONTAL_DEBOUNCE);
+                mHandler.sendMessageDelayed(m, delay);
+            } else {
+                // no message is pending
+                mPendingOrientation = ORIENTATION_UNKNOWN;
+            }
+        }
+    }
+
+    private void onSensorEvent(double x, double y, double z) {
+//        if (VDEBUG)
+//            Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
+
+        // If some values are exactly zero, then likely the sensor is not powered up yet.
+        // ignore these events to avoid false horizontal positives.
+        if (x == 0.0 || y == 0.0 || z == 0.0)
+            return;
+
+        // magnitude of the acceleration vector projected onto XY plane
+        double xy = Math.sqrt(x * x + y * y);
+        // compute the vertical angle
+        double angle = Math.atan2(xy, z);
+        // convert to degrees
+        angle = angle * 180.0 / Math.PI;
+        int orientation = (angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL);
+//        if (VDEBUG)
+//            Log.d(TAG, "angle: " + angle + " orientation: " + orientation);
+        setOrientation(orientation);
+    }
+
+    SensorEventListener mSensorListener = new SensorEventListener() {
+        public void onSensorChanged(SensorEvent event) {
+            onSensorEvent(event.values[0], event.values[1], event.values[2]);
+        }
+
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            // ignore
+        }
+    };
+
+    Handler mHandler = new AccelerometerHandler(this);
+
+    private static class AccelerometerHandler extends Handler {
+        WeakReference<AccelerometerListener> l;
+
+        AccelerometerHandler(AccelerometerListener listener) {
+            l = new WeakReference<AccelerometerListener>(listener);
+        }
+
+        public void handleMessage(Message msg) {
+            AccelerometerListener listener = l.get();
+            if (listener == null) {
+                return;
+            }
+            switch (msg.what) {
+            case ORIENTATION_CHANGED:
+                synchronized (listener) {
+                    listener.mOrientation = listener.mPendingOrientation;
+//                    if (DEBUG) {
+//                        Log.d(TAG, "orientation: "
+//                                + (listener.mOrientation == ORIENTATION_HORIZONTAL ? "horizontal"
+//                                        : (listener.mOrientation == ORIENTATION_VERTICAL ? "vertical" : "unknown")));
+//                    }
+                    listener.mListener.orientationChanged(listener.mOrientation);
+                }
+                break;
+            }
+        }
+    };
+}
\ No newline at end of file
diff --git a/src/org/sflphone/utils/CallProximityManager.java b/src/org/sflphone/utils/CallProximityManager.java
new file mode 100644
index 0000000..da9614e
--- /dev/null
+++ b/src/org/sflphone/utils/CallProximityManager.java
@@ -0,0 +1,314 @@
+/*
+ *  Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
+ *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ *  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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+package org.sflphone.utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.sflphone.utils.AccelerometerListener.OrientationListener;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.net.wifi.WifiManager;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
+
+/**
+ * Class to manage proximity detection while in call.
+ * 
+ */
+public class CallProximityManager implements SensorEventListener, OrientationListener {
+    private static final String THIS_FILE = "CallProximityManager";
+
+    private Context mContext;
+
+    private SensorManager sensorManager;
+    private PowerManager powerManager;
+
+    // Timeout management of screen locker ui
+    // private ScreenLocker mScreenLocker;
+    private Boolean useTimeoutOverlay = null;
+
+    // Self management of proximity sensor
+    private Sensor proximitySensor;
+    private static final float PROXIMITY_THRESHOLD = 5.0f;
+    private boolean invertProximitySensor = false;
+    private boolean proximitySensorTracked = false;
+    private boolean isFirstRun = true;
+    private ProximityDirector mDirector = null;
+
+    // The hidden api that uses a wake lock
+    private WakeLock proximityWakeLock;
+
+    // The accelerometer
+    private AccelerometerListener accelerometerManager;
+    private int mOrientation;
+    private boolean accelerometerEnabled = false;
+
+    private int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
+    // private final static int SCREEN_LOCKER_ACQUIRE_DELAY = "google_sdk".equals(Build.PRODUCT) ? ScreenLocker.WAIT_BEFORE_LOCK_LONG
+    // : ScreenLocker.WAIT_BEFORE_LOCK_SHORT;
+
+    private static Method powerLockReleaseIntMethod;
+
+    public interface ProximityDirector {
+        public boolean shouldActivateProximity();
+
+        public void onProximityTrackingChanged(boolean acquired);
+    }
+
+    public CallProximityManager(Context context, ProximityDirector director) {
+        mContext = context;
+        mDirector = director;
+        // mScreenLocker = screenLocker;
+
+        sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+        powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        accelerometerManager = new AccelerometerListener(context, this);
+
+        // Try to detect the hidden api
+        if (powerManager != null) {
+            WifiManager wman = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+
+            // Try to use powermanager proximity sensor
+            try {
+                boolean supportProximity = false;
+                Field f = PowerManager.class.getDeclaredField("PROXIMITY_SCREEN_OFF_WAKE_LOCK");
+                int proximityScreenOffWakeLock = (Integer) f.get(null);
+                if (Compatibility.isCompatible(17)) {
+                    // Changes of the private API on android 4.2
+                    Method method = powerManager.getClass().getDeclaredMethod("isWakeLockLevelSupported", int.class);
+                    supportProximity = (Boolean) method.invoke(powerManager, proximityScreenOffWakeLock);
+                    Log.d(THIS_FILE, "Use 4.2 detection way for proximity sensor detection. Result is " + supportProximity);
+                } else {
+                    Method method = powerManager.getClass().getDeclaredMethod("getSupportedWakeLockFlags");
+                    int supportedFlags = (Integer) method.invoke(powerManager);
+                    Log.d(THIS_FILE, "Proxmity flags supported : " + supportedFlags);
+                    supportProximity = ((supportedFlags & proximityScreenOffWakeLock) != 0x0);
+                }
+                if (supportProximity) {
+                    Log.d(THIS_FILE, "We can use native screen locker !!");
+                    proximityWakeLock = powerManager.newWakeLock(proximityScreenOffWakeLock, "com.csipsimple.CallProximity");
+                    proximityWakeLock.setReferenceCounted(false);
+                }
+
+            } catch (Exception e) {
+                Log.d(THIS_FILE, "Impossible to get power manager supported wake lock flags ");
+            }
+            if (powerLockReleaseIntMethod == null) {
+                try {
+                    powerLockReleaseIntMethod = proximityWakeLock.getClass().getDeclaredMethod("release", int.class);
+
+                } catch (Exception e) {
+                    Log.d(THIS_FILE, "Impossible to get power manager release with it");
+                }
+
+            }
+        }
+
+        // Try to detect a proximity sensor as fallback
+        if (proximityWakeLock == null) {
+            proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            // invertProximitySensor = SipConfigManager.getPreferenceBooleanValue(context, SipConfigManager.INVERT_PROXIMITY_SENSOR);
+        }
+
+    }
+
+    public synchronized void startTracking() {
+        // If we should manage it ourselves
+        if (proximitySensor != null && !proximitySensorTracked) {
+            // Fall back to manual mode
+            isFirstRun = true;
+            Log.d(THIS_FILE, "Register sensor");
+            sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+            proximitySensorTracked = true;
+        }
+        if (!accelerometerEnabled) {
+            accelerometerManager.enable(true);
+            accelerometerEnabled = true;
+        }
+    }
+
+    public synchronized void stopTracking() {
+        if (proximitySensor != null && proximitySensorTracked) {
+            proximitySensorTracked = false;
+            sensorManager.unregisterListener(this);
+            Log.d(THIS_FILE, "Unregister to sensor is done !!!");
+        }
+        if (accelerometerEnabled) {
+            accelerometerManager.enable(false);
+            accelerometerEnabled = false;
+        }
+        // mScreenLocker.tearDown();
+    }
+
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        // Log.d(THIS_FILE, "Tracked : "+proximitySensorTracked);
+        if (proximitySensorTracked && !isFirstRun) {
+            float distance = event.values[0];
+            boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD && distance < event.sensor.getMaximumRange());
+            if (invertProximitySensor) {
+                active = !active;
+            }
+            Log.d(THIS_FILE, "Distance is now " + distance);
+
+            boolean isValidCallState = false;
+            if (mDirector != null) {
+                isValidCallState = mDirector.shouldActivateProximity();
+            }
+
+            if (isValidCallState && active) {
+                // mScreenLocker.show();
+                if (mDirector != null) {
+                    mDirector.onProximityTrackingChanged(true);
+                }
+            } else {
+                // mScreenLocker.hide();
+                if (mDirector != null) {
+                    mDirector.onProximityTrackingChanged(false);
+                }
+            }
+
+        }
+        if (isFirstRun) {
+            isFirstRun = false;
+        }
+    }
+
+    private boolean isProximityWakeHeld = false;
+
+    /**
+     * Release any lock taken by the proximity sensor
+     */
+    public synchronized void release(int flag) {
+        if (proximityWakeLock != null && isProximityWakeHeld) {
+            boolean usedNewRelease = false;
+            if (powerLockReleaseIntMethod != null) {
+                try {
+                    powerLockReleaseIntMethod.invoke(proximityWakeLock, flag);
+                    usedNewRelease = true;
+                    // Log.d(THIS_FILE, "CALL NEW RELEASE WITH FLAG " + flag);
+                } catch (Exception e) {
+                    Log.d(THIS_FILE, "Error calling new release method ", e);
+                }
+            }
+            if (!usedNewRelease) {
+                proximityWakeLock.release();
+            }
+            isProximityWakeHeld = false;
+        }
+
+        if (shouldUseTimeoutOverlay()) {
+            // mScreenLocker.hide();
+        }
+        // Notify
+        if (mDirector != null) {
+            mDirector.onProximityTrackingChanged(false);
+        }
+    }
+
+    public synchronized void acquire() {
+        if (proximityWakeLock != null && !isProximityWakeHeld) {
+            proximityWakeLock.acquire();
+            isProximityWakeHeld = true;
+        }
+        if (shouldUseTimeoutOverlay()) {
+            // mScreenLocker.delayedLock(SCREEN_LOCKER_ACQUIRE_DELAY);
+        }
+        // Notify
+        if (mDirector != null) {
+            mDirector.onProximityTrackingChanged(true);
+        }
+    }
+
+    /**
+     * Update proximity lock mode depending on current state
+     */
+    public synchronized void updateProximitySensorMode() {
+
+        // We do not keep the screen off when the user is outside in-call screen and we are
+        // horizontal, but we do not force it on when we become horizontal until the
+        // proximity sensor goes negative.
+        boolean horizontal = (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
+
+        boolean activeRegardingCalls = false;
+        if (mDirector != null) {
+            activeRegardingCalls = mDirector.shouldActivateProximity();
+        }
+
+        Log.d(THIS_FILE, "Horizontal : " + horizontal + " and activate for calls " + activeRegardingCalls);
+        if (activeRegardingCalls && !horizontal) {
+            // Phone is in use! Arrange for the screen to turn off
+            // automatically when the sensor detects a close object.
+            acquire();
+        } else {
+            // Phone is either idle, or ringing. We don't want any
+            // special proximity sensor behavior in either case.
+            int flags = (!horizontal ? 0 : WAIT_FOR_PROXIMITY_NEGATIVE);
+            release(flags);
+        }
+    }
+
+    /**
+     * Should the application display the overlay after a timeout.
+     * 
+     * @return false if we are in table mode or if proximity sensor can be used
+     */
+    private boolean shouldUseTimeoutOverlay() {
+        if (useTimeoutOverlay == null) {
+            useTimeoutOverlay = proximitySensor == null && proximityWakeLock == null && !Compatibility.isTabletScreen(mContext);
+        }
+        return useTimeoutOverlay;
+    }
+
+    public void restartTimer() {
+        if (shouldUseTimeoutOverlay()) {
+            // mScreenLocker.delayedLock(ScreenLocker.WAIT_BEFORE_LOCK_LONG);
+        }
+    }
+
+    @Override
+    public void orientationChanged(int orientation) {
+        mOrientation = orientation;
+        updateProximitySensorMode();
+    }
+
+}
\ No newline at end of file
diff --git a/src/org/sflphone/utils/Compatibility.java b/src/org/sflphone/utils/Compatibility.java
new file mode 100644
index 0000000..7a4a800
--- /dev/null
+++ b/src/org/sflphone/utils/Compatibility.java
@@ -0,0 +1,528 @@
+/*
+ *  Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
+ *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ *  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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+package org.sflphone.utils;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.lang.reflect.Field;
+import java.util.regex.Pattern;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.media.MediaRecorder.AudioSource;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.Contacts;
+import android.util.Log;
+
+@SuppressWarnings("deprecation")
+public final class Compatibility {
+
+    private Compatibility() {
+    }
+
+    private static final String THIS_FILE = "Compat";
+
+    public static int getApiLevel() {
+        return android.os.Build.VERSION.SDK_INT;
+    }
+
+    public static boolean isCompatible(int apiLevel) {
+        return android.os.Build.VERSION.SDK_INT >= apiLevel;
+    }
+
+    /**
+     * Get the stream id for in call track. Can differ on some devices. Current
+     * device for which it's different :
+     * 
+     * @return
+     */
+    public static int getInCallStream(boolean requestBluetooth) {
+        /* Archos 5IT */
+        if (android.os.Build.BRAND.equalsIgnoreCase("archos")
+                && android.os.Build.DEVICE.equalsIgnoreCase("g7a")) {
+            // Since archos has no voice call capabilities, voice call stream is
+            // not implemented
+            // So we have to choose the good stream tag, which is by default
+            // falled back to music
+            return AudioManager.STREAM_MUSIC;
+        }
+        if (requestBluetooth) {
+            return 6; /* STREAM_BLUETOOTH_SCO -- Thx @Stefan for the contrib */
+        }
+
+        // return AudioManager.STREAM_MUSIC;
+        return AudioManager.STREAM_VOICE_CALL;
+    }
+
+    public static boolean shouldUseRoutingApi() {
+        Log.d(THIS_FILE, "Current device " + android.os.Build.BRAND + " - "
+                + android.os.Build.DEVICE);
+
+        // HTC evo 4G
+        if (android.os.Build.PRODUCT.equalsIgnoreCase("htc_supersonic")) {
+            return true;
+        }
+
+        // ZTE joe
+        if (android.os.Build.DEVICE.equalsIgnoreCase("joe")) {
+            return true;
+        }
+
+        // Samsung GT-S5830
+        if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-S")) {
+            return true;
+        }
+
+        if (!isCompatible(4)) {
+            // If android 1.5, force routing api use
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static boolean shouldUseModeApi() {
+
+        // ZTE blade et joe
+        if (android.os.Build.DEVICE.equalsIgnoreCase("blade")
+                || android.os.Build.DEVICE.equalsIgnoreCase("joe")) {
+            return true;
+        }
+        // Samsung GT-S5360 GT-S5830 GT-S6102 ... probably all..
+        if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-") ||
+                android.os.Build.PRODUCT.toUpperCase().startsWith("GT-") ||
+                android.os.Build.DEVICE.toUpperCase().startsWith("YP-")) {
+            return true;
+        }
+
+        // HTC evo 4G
+        if (android.os.Build.PRODUCT.equalsIgnoreCase("htc_supersonic")) {
+            return true;
+        }
+        // LG P500, Optimus V
+        if (android.os.Build.DEVICE.toLowerCase().startsWith("thunder")) {
+            return true;
+        }
+        // LG-E720(b)
+        if (android.os.Build.MODEL.toUpperCase().startsWith("LG-E720")
+                && !Compatibility.isCompatible(9)) {
+            return true;
+        }
+        // LG-LS840
+        if (android.os.Build.DEVICE.toLowerCase().startsWith("cayman")) {
+            return true;
+        }
+
+        // Huawei
+        if (android.os.Build.DEVICE.equalsIgnoreCase("U8150") ||
+                android.os.Build.DEVICE.equalsIgnoreCase("U8110") ||
+                android.os.Build.DEVICE.equalsIgnoreCase("U8120") ||
+                android.os.Build.DEVICE.equalsIgnoreCase("U8100") ||
+                android.os.Build.PRODUCT.equalsIgnoreCase("U8655")) {
+            return true;
+        }
+
+        // Moto defy mini
+        if (android.os.Build.MODEL.equalsIgnoreCase("XT320")) {
+            return true;
+        }
+
+        // Alcatel
+        if (android.os.Build.DEVICE.toUpperCase().startsWith("ONE_TOUCH_993D")) {
+            return true;
+        }
+
+        // N4
+        if (android.os.Build.DEVICE.toUpperCase().startsWith("MAKO")) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public static String guessInCallMode() {
+        // New api for 2.3.3 is not available on galaxy S II :(
+        if (!isCompatible(11) && android.os.Build.DEVICE.toUpperCase().startsWith("GT-I9100")) {
+            return Integer.toString(AudioManager.MODE_NORMAL);
+        }
+
+        if (android.os.Build.BRAND.equalsIgnoreCase("sdg") || isCompatible(10)) {
+            // Note that in APIs this is only available from level 11.
+            return "3";
+        }
+        if (android.os.Build.DEVICE.equalsIgnoreCase("blade")) {
+            return Integer.toString(AudioManager.MODE_IN_CALL);
+        }
+
+        if (!isCompatible(5)) {
+            return Integer.toString(AudioManager.MODE_IN_CALL);
+        }
+
+        return Integer.toString(AudioManager.MODE_NORMAL);
+    }
+
+    public static String getDefaultMicroSource() {
+        // Except for galaxy S II :(
+        if (!isCompatible(11) && android.os.Build.DEVICE.toUpperCase().startsWith("GT-I9100")) {
+            return Integer.toString(AudioSource.MIC);
+        }
+
+        if (isCompatible(10)) {
+            // Note that in APIs this is only available from level 11.
+            // VOICE_COMMUNICATION
+            return Integer.toString(0x7);
+        }
+        /*
+         * Too risky in terms of regressions else if (isCompatible(4)) { //
+         * VOICE_CALL return 0x4; }
+         */
+        /*
+         * if(android.os.Build.MODEL.equalsIgnoreCase("X10i")) { // VOICE_CALL
+         * return Integer.toString(0x4); }
+         */
+        /*
+         * Not relevant anymore, atrix I tested sounds fine with that
+         * if(android.os.Build.DEVICE.equalsIgnoreCase("olympus")) { //Motorola
+         * atrix bug // CAMCORDER return Integer.toString(0x5); }
+         */
+
+        return Integer.toString(AudioSource.DEFAULT);
+    }
+
+    public static String getDefaultFrequency() {
+        if (android.os.Build.DEVICE.equalsIgnoreCase("olympus")) {
+            // Atrix bug
+            return "32000";
+        }
+        if (android.os.Build.DEVICE.toUpperCase().equals("GT-P1010")) {
+            // Galaxy tab see issue 932
+            return "32000";
+        }
+
+        return isCompatible(4) ? "16000" : "8000";
+    }
+
+    public static String getCpuAbi() {
+        if (isCompatible(4)) {
+            Field field;
+            try {
+                field = android.os.Build.class.getField("CPU_ABI");
+                return field.get(null).toString();
+            } catch (Exception e) {
+                Log.w(THIS_FILE, "Announce to be android 1.6 but no CPU ABI field", e);
+            }
+
+        }
+        return "armeabi";
+    }
+
+    public final static int getNumCores() {
+        // Private Class to display only CPU devices in the directory listing
+        class CpuFilter implements FileFilter {
+            @Override
+            public boolean accept(File pathname) {
+                // Check if filename is "cpu", followed by a single digit number
+                if (Pattern.matches("cpu[0-9]", pathname.getName())) {
+                    return true;
+                }
+                return false;
+            }
+        }
+        try {
+            // Get directory containing CPU info
+            File dir = new File("/sys/devices/system/cpu/");
+            // Filter to only list the devices we care about
+            File[] files = dir.listFiles(new CpuFilter());
+            // Return the number of cores (virtual CPU devices)
+            return files.length;
+        } catch (Exception e) {
+            return Runtime.getRuntime().availableProcessors();
+        }
+    }
+
+    private static boolean needPspWorkaround() {
+        // New api for 2.3 does not work on Incredible S
+        if (android.os.Build.DEVICE.equalsIgnoreCase("vivo")) {
+            return true;
+        }
+
+        // New API for android 2.3 should be able to manage this but do only for
+        // honeycomb cause seems not correctly supported by all yet
+        if (isCompatible(11)) {
+            return false;
+        }
+
+        // All htc except....
+        if (android.os.Build.PRODUCT.toLowerCase().startsWith("htc")
+                || android.os.Build.BRAND.toLowerCase().startsWith("htc")
+                || android.os.Build.PRODUCT.toLowerCase().equalsIgnoreCase("inc") /*
+                                                                                   * For
+                                                                                   * Incredible
+                                                                                   */
+                || android.os.Build.DEVICE.equalsIgnoreCase("passion") /* N1 */) {
+            if (android.os.Build.DEVICE.equalsIgnoreCase("hero") /* HTC HERO */
+                    || android.os.Build.DEVICE.equalsIgnoreCase("magic") /*
+                                                                          * Magic
+                                                                          * Aka
+                                                                          * Dev
+                                                                          * G2
+                                                                          */
+                    || android.os.Build.DEVICE.equalsIgnoreCase("tatoo") /* Tatoo */
+                    || android.os.Build.DEVICE.equalsIgnoreCase("dream") /*
+                                                                          * Dream
+                                                                          * Aka
+                                                                          * Dev
+                                                                          * G1
+                                                                          */
+                    || android.os.Build.DEVICE.equalsIgnoreCase("legend") /* Legend */
+
+            ) {
+                return false;
+            }
+
+            // Older than 2.3 has no chance to have the new full perf wifi mode
+            // working since does not exists
+            if (!isCompatible(9)) {
+                return true;
+            } else {
+                // N1 is fine with that
+                if (android.os.Build.DEVICE.equalsIgnoreCase("passion")) {
+                    return false;
+                }
+                return true;
+            }
+
+        }
+        // Dell streak
+        if (android.os.Build.BRAND.toLowerCase().startsWith("dell") &&
+                android.os.Build.DEVICE.equalsIgnoreCase("streak")) {
+            return true;
+        }
+        // Motorola milestone 1 and 2 & motorola droid & defy not under 2.3
+        if ((android.os.Build.DEVICE.toLowerCase().contains("milestone2") ||
+                android.os.Build.BOARD.toLowerCase().contains("sholes") ||
+                android.os.Build.PRODUCT.toLowerCase().contains("sholes") ||
+                android.os.Build.DEVICE.equalsIgnoreCase("olympus") ||
+                android.os.Build.DEVICE.toLowerCase().contains("umts_jordan")) && !isCompatible(9)) {
+            return true;
+        }
+        // Moto defy mini
+        if (android.os.Build.MODEL.equalsIgnoreCase("XT320")) {
+            return true;
+        }
+
+        // Alcatel ONE touch
+        if (android.os.Build.DEVICE.startsWith("one_touch_990")) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean needToneWorkaround() {
+        if (android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i5800") ||
+                android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i5801") ||
+                android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i9003")) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean needSGSWorkaround() {
+        if (isCompatible(9)) {
+            return false;
+        }
+        if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-I9000") ||
+                android.os.Build.DEVICE.toUpperCase().startsWith("GT-P1000")) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean needWebRTCImplementation() {
+        if (android.os.Build.DEVICE.toLowerCase().contains("droid2")) {
+            return true;
+        }
+        if (android.os.Build.MODEL.toLowerCase().contains("droid bionic")) {
+            return true;
+        }
+        if (android.os.Build.DEVICE.toLowerCase().contains("sunfire")) {
+            return true;
+        }
+        // Huawei Y300
+        if (android.os.Build.DEVICE.equalsIgnoreCase("U8833")) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean shouldSetupAudioBeforeInit() {
+        // Setup for GT / GS samsung devices.
+        if (android.os.Build.DEVICE.toLowerCase().startsWith("gt-")
+                || android.os.Build.PRODUCT.toLowerCase().startsWith("gt-")) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean shouldFocusAudio() {
+        /* HTC One X */
+        if (android.os.Build.DEVICE.toLowerCase().startsWith("endeavoru") ||
+                android.os.Build.DEVICE.toLowerCase().startsWith("evita")) {
+            return false;
+        }
+
+        if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-P7510") && isCompatible(15)) {
+            return false;
+        }
+        return true;
+    }
+
+//    private static int getDefaultAudioImplementation() {
+//        // Acer A510
+//        if (android.os.Build.DEVICE.toLowerCase().startsWith("picasso")) {
+//            return SipConfigManager.AUDIO_IMPLEMENTATION_JAVA;
+//        }
+//        if (Compatibility.isCompatible(11)) {
+//            return SipConfigManager.AUDIO_IMPLEMENTATION_OPENSLES;
+//        }
+//        if (android.os.Build.DEVICE.equalsIgnoreCase("ST25i") && Compatibility.isCompatible(10)) {
+//            return SipConfigManager.AUDIO_IMPLEMENTATION_OPENSLES;
+//        }
+//        if (android.os.Build.DEVICE.equalsIgnoreCase("u8510") && Compatibility.isCompatible(10)) {
+//            return SipConfigManager.AUDIO_IMPLEMENTATION_OPENSLES;
+//        }
+//        return SipConfigManager.AUDIO_IMPLEMENTATION_JAVA;
+//    }
+
+    
+
+    public static boolean useFlipAnimation() {
+        if (android.os.Build.BRAND.equalsIgnoreCase("archos")
+                && android.os.Build.DEVICE.equalsIgnoreCase("g7a")) {
+            return false;
+        }
+        return true;
+    }
+
+
+    public static Intent getContactPhoneIntent() {
+        Intent intent = new Intent(Intent.ACTION_PICK);
+        /*
+         * intent.setAction(Intent.ACTION_GET_CONTENT);
+         * intent.setType(Contacts.Phones.CONTENT_ITEM_TYPE);
+         */
+        if (isCompatible(5)) {
+            // Don't use constant to allow backward compat simply
+            intent.setData(Uri.parse("content://com.android.contacts/contacts"));
+        } else {
+            // Fallback for android 4
+            intent.setData(Contacts.People.CONTENT_URI);
+        }
+
+        return intent;
+
+    }
+    
+
+    public static boolean isTabletScreen(Context ctxt) {
+        boolean isTablet = false;
+        if (!isCompatible(4)) {
+            return false;
+        }
+        Configuration cfg = ctxt.getResources().getConfiguration();
+        int screenLayoutVal = 0;
+        try {
+            Field f = Configuration.class.getDeclaredField("screenLayout");
+            screenLayoutVal = (Integer) f.get(cfg);
+        } catch (Exception e) {
+            return false;
+        }
+        int screenLayout = (screenLayoutVal & 0xF);
+        // 0xF = SCREENLAYOUT_SIZE_MASK but avoid 1.5 incompat doing that
+        if (screenLayout == 0x3 || screenLayout == 0x4) {
+            // 0x3 = SCREENLAYOUT_SIZE_LARGE but avoid 1.5 incompat doing that
+            // 0x4 = SCREENLAYOUT_SIZE_XLARGE but avoid 1.5 incompat doing that
+            isTablet = true;
+        }
+
+        return isTablet;
+    }
+
+    public static int getHomeMenuId() {
+        return 0x0102002c;
+        // return android.R.id.home;
+    }
+
+    public static boolean isInstalledOnSdCard(Context context) {
+        // check for API level 8 and higher
+        if (Compatibility.isCompatible(8)) {
+            PackageManager pm = context.getPackageManager();
+            try {
+                PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+                ApplicationInfo ai = pi.applicationInfo;
+                return (ai.flags & 0x00040000 /*
+                                               * ApplicationInfo.
+                                               * FLAG_EXTERNAL_STORAGE
+                                               */) == 0x00040000 /*
+                                                                  * ApplicationInfo.
+                                                                  * FLAG_EXTERNAL_STORAGE
+                                                                  */;
+            } catch (NameNotFoundException e) {
+                // ignore
+            }
+        }
+
+        // check for API level 7 - check files dir
+        try {
+            String filesDir = context.getFilesDir().getAbsolutePath();
+            if (filesDir.startsWith("/data/")) {
+                return false;
+            } else if (filesDir.contains(Environment.getExternalStorageDirectory().getPath())) {
+                return true;
+            }
+        } catch (Throwable e) {
+            // ignore
+        }
+
+        return false;
+    }
+
+}
\ No newline at end of file