From d169c9ee2e59ebf82dfffbecc04e352f66c5ce1f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Feb 2010 15:46:01 +0100 Subject: [PATCH] phone book integration --- AndroidManifest.xml | 3 +- Application.mk | 2 +- res/layout/dialer.xml | 3 +- res/raw/linphonerc | 6 +- res/values/non_localizable_strings.xml | 1 + res/values/strings.xml | 12 ++- res/xml/preferences.xml | 2 + src/org/linphone/DialerActivity.java | 21 +++- src/org/linphone/Linphone.java | 97 ++++++++++++------- src/org/linphone/core/LinphoneAddress.java | 37 +++++++ .../linphone/core/LinphoneAddressImpl.java | 61 ++++++++++++ .../linphone/core/LinphoneAuthInfoImpl.java | 18 ++++ src/org/linphone/core/LinphoneCore.java | 5 + src/org/linphone/core/LinphoneCoreImpl.java | 9 ++ .../linphone/core/LinphoneProxyConfig.java | 8 +- .../core/LinphoneProxyConfigImpl.java | 5 + 16 files changed, 239 insertions(+), 51 deletions(-) create mode 100644 src/org/linphone/core/LinphoneAddress.java create mode 100644 src/org/linphone/core/LinphoneAddressImpl.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 755e9b0f6..881c0dfd7 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5,7 +5,8 @@ android:versionName="1.0"> + android:label="@string/app_name" + android:theme="@android:style/Theme.NoTitleBar"> diff --git a/Application.mk b/Application.mk index a8a033a2d..cb85b26d9 100644 --- a/Application.mk +++ b/Application.mk @@ -1,3 +1,3 @@ APP_PROJECT_PATH := $(call my-dir)/ -APP_MODULES :=libspeex libortp libosip2 libeXosip2 libmediastreamer2 libmsandroidsnd liblinphone +APP_MODULES :=libspeex libgsm libortp libosip2 libeXosip2 libmediastreamer2 libmsandroidsnd liblinphone APP_BUILD_SCRIPT:=$(call my-dir)/../linphone-builder/android/Android.mk diff --git a/res/layout/dialer.xml b/res/layout/dialer.xml index 51da56e53..7d4023aa5 100644 --- a/res/layout/dialer.xml +++ b/res/layout/dialer.xml @@ -7,7 +7,7 @@ - + @@ -35,4 +35,5 @@ + diff --git a/res/raw/linphonerc b/res/raw/linphonerc index fc3658fbf..b0dfe00ad 100644 --- a/res/raw/linphonerc +++ b/res/raw/linphonerc @@ -36,7 +36,7 @@ enabled=0 [audio_codec_1] mime=speex rate=16000 -enabled=0 +enabled=1 [audio_codec_2] mime=speex @@ -61,10 +61,10 @@ enabled=1 [audio_codec_6] mime=PCMU rate=8000 -enabled=0 +enabled=1 [audio_codec_7] mime=PCMA rate=8000 -enabled=0 +enabled=1 diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml index 04591bc94..f2669c602 100644 --- a/res/values/non_localizable_strings.xml +++ b/res/values/non_localizable_strings.xml @@ -1,5 +1,6 @@ + pref_prefix_key pref_proxy_key pref_domain_key pref_passwd_key diff --git a/res/values/strings.xml b/res/values/strings.xml index 3c661852a..37c960682 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,5 +1,7 @@ + Prefix + Advanced Settings Proxy Domain* @@ -8,9 +10,13 @@ Hello World, Linphone! Linphone SIP Account - Enter a user name -Enter a password -Enter a domain + wrong user name +wrong password +Wrong domain Dialer Contact +Cannot call %s +Yes +No +%s, do you want to return to the settings page ? diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 2912fbaa9..ddce3aae4 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -6,4 +6,6 @@ + + diff --git a/src/org/linphone/DialerActivity.java b/src/org/linphone/DialerActivity.java index 6dfa95932..4413b9c91 100644 --- a/src/org/linphone/DialerActivity.java +++ b/src/org/linphone/DialerActivity.java @@ -1,6 +1,8 @@ package org.linphone; import org.linphone.core.LinphoneCore; +import org.linphone.core.LinphoneProxyConfig; + import android.app.Activity; import android.os.Bundle; import android.util.Log; @@ -13,6 +15,7 @@ import android.widget.TextView; public class DialerActivity extends Activity { private LinphoneCore mLinphoneCore; private TextView mAddress; + private TextView mStatus; private ImageButton mCall; private ImageButton mHangup; private Button mZero; @@ -30,9 +33,13 @@ public class DialerActivity extends Activity { private static DialerActivity theDialer; private String mDisplayName; + /** + * + * @return nul if not ready yet + */ public static DialerActivity getDialer() { if (theDialer == null) { - throw new RuntimeException("DialerActivity not instanciated yet"); + return null; } else { return theDialer; } @@ -41,6 +48,9 @@ public class DialerActivity extends Activity { mAddress.setText(aContact); mDisplayName = aDisplayName; } + public void displayStatus(String status) { + mStatus.setText(status); + } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialer); @@ -52,7 +62,12 @@ public class DialerActivity extends Activity { mCall = (ImageButton) findViewById(R.id.Call); mCall.setOnClickListener(new OnClickListener() { public void onClick(View v) { - mLinphoneCore.invite(mAddress.getText().toString()); + LinphoneProxyConfig lProxy = mLinphoneCore.getDefaultProxyConfig(); + String lNormalizedNumber = mAddress.getText().toString(); + if (lProxy!=null) { + lNormalizedNumber = lProxy.normalizePhoneNumber(lNormalizedNumber); + } + mLinphoneCore.invite(lNormalizedNumber); } }); @@ -102,7 +117,7 @@ public class DialerActivity extends Activity { mHash = (Button) findViewById(R.id.ButtonHash); mHash.setOnClickListener(new DialKeyListener(mAddress,'#')); - + mStatus = (TextView) findViewById(R.id.status_label); } catch (Exception e) { Log.e(Linphone.TAG,"Cannot start linphone",e); diff --git a/src/org/linphone/Linphone.java b/src/org/linphone/Linphone.java index 4bd7da127..038d116a5 100644 --- a/src/org/linphone/Linphone.java +++ b/src/org/linphone/Linphone.java @@ -33,24 +33,21 @@ import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; import org.linphone.core.LinphoneProxyConfig; -import android.app.Activity; + +import android.app.AlertDialog; import android.app.TabActivity; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.Resources; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.preference.PreferenceManager; -import android.provider.Contacts.People; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.ImageButton; import android.widget.TabHost; -import android.widget.TextView; import android.widget.Toast; public class Linphone extends TabActivity implements LinphoneCoreListener { @@ -67,7 +64,7 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { Timer mTimer = new Timer("Linphone scheduler"); public static String DIALER_TAB = "dialer"; - + private Handler mIteratehandler; static Linphone getLinphone() { if (theLinphone == null) { throw new RuntimeException("LinphoneActivity not instanciated yet"); @@ -90,16 +87,21 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { , null); initFromConf(); + mIteratehandler = new Handler() { + public void handleMessage(Message msg) { + //iterate is called inside an Android handler to allow UI interaction within LinphoneCoreListener + mLinphoneCore.iterate(); + } + }; TimerTask lTask = new TimerTask() { - @Override public void run() { - mLinphoneCore.iterate(); - + mIteratehandler.sendEmptyMessage(0); } }; + mTimer.scheduleAtFixedRate(lTask, 0, 100); @@ -149,23 +151,27 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { private void copyAssetsFromPackage() throws IOException { copyIfNotExist(R.raw.oldphone_mono,RING_SND); copyIfNotExist(R.raw.ringback,RINGBACK_SND); - copyIfNotExist(R.raw.linphonerc,LINPHONE_FACTORY_RC); + copyFromPackage(R.raw.linphonerc, new File(LINPHONE_FACTORY_RC).getName()); } private void copyIfNotExist(int ressourceId,String target) throws IOException { File lFileToCopy = new File(target); if (!lFileToCopy.exists()) { - FileOutputStream lOutputStream = openFileOutput (lFileToCopy.getName(), 0); - InputStream lInputStream = getResources().openRawResource(ressourceId); - int readByte; - byte[] buff = new byte[8048]; - while (( readByte = lInputStream.read(buff))!=-1) { - lOutputStream.write(buff,0, readByte); - } - lOutputStream.flush(); - lOutputStream.close(); - lInputStream.close(); - } + copyFromPackage(ressourceId,lFileToCopy.getName()); + } + } + private void copyFromPackage(int ressourceId,String target) throws IOException{ + FileOutputStream lOutputStream = openFileOutput (target, 0); + InputStream lInputStream = getResources().openRawResource(ressourceId); + int readByte; + byte[] buff = new byte[8048]; + while (( readByte = lInputStream.read(buff))!=-1) { + lOutputStream.write(buff,0, readByte); + } + lOutputStream.flush(); + lOutputStream.close(); + lInputStream.close(); + } public void authInfoRequested(LinphoneCore lc, String realm, String username) { // TODO Auto-generated method stub @@ -181,7 +187,7 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { } public void displayStatus(LinphoneCore lc, String message) { Log.i(TAG, message); - + if (DialerActivity.getDialer()!=null) DialerActivity.getDialer().displayStatus(message); } public void displayWarning(LinphoneCore lc, String message) { // TODO Auto-generated method stub @@ -191,9 +197,14 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { Log.i(TAG, "new state ["+state+"]"); switch(state) { - case GSTATE_REG_OK: { - //mLinphoneCore.invite("simon.morlat"); + case GSTATE_CALL_ERROR: { + + Toast toast = Toast.makeText(this + ,String.format(getString(R.string.call_error),mLinphoneCore.getRemoteAddress()) + , Toast.LENGTH_LONG); + toast.show(); } + case GSTATE_REG_OK: } } @@ -229,30 +240,26 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { return false; } + public void initFromConf() throws LinphoneCoreException { //1 read proxy config from preferences String lUserName = mPref.getString(getString(R.string.pref_username_key), null); if (lUserName == null) { - Toast toast = Toast.makeText(this, getString(R.string.enter_username), Toast.LENGTH_LONG); - toast.show(); - startprefActivity(); + handleBadConfig(getString(R.string.wrong_username)); return; } String lPasswd = mPref.getString(getString(R.string.pref_passwd_key), null); if (lPasswd == null) { - Toast toast = Toast.makeText(this, this.getString(R.string.enter_passwd), Toast.LENGTH_LONG); - toast.show(); - startprefActivity(); + handleBadConfig(getString(R.string.wrong_passwd)); return; + } String lDomain = mPref.getString(getString(R.string.pref_domain_key), null); if (lDomain == null) { - Toast toast = Toast.makeText(this, this.getString(R.string.enter_domain), Toast.LENGTH_LONG); - toast.show(); - startprefActivity(); - return; + handleBadConfig(getString(R.string.wrong_domain)); + return; } @@ -284,6 +291,22 @@ public class Linphone extends TabActivity implements LinphoneCoreListener { } + private void handleBadConfig(String message) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(String.format(getString(R.string.config_error),message)) + .setCancelable(false) + .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + startprefActivity(); + } + }) + .setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + builder.create().show(); + } private void startprefActivity() { Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClass(Linphone.this, LinphonePreferencesActivity.class); diff --git a/src/org/linphone/core/LinphoneAddress.java b/src/org/linphone/core/LinphoneAddress.java new file mode 100644 index 000000000..d7ad7c4b0 --- /dev/null +++ b/src/org/linphone/core/LinphoneAddress.java @@ -0,0 +1,37 @@ +/* +LinphoneAddress.java +Copyright (C) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.core; + +public interface LinphoneAddress { + /** + * Human display name + * @return null if not set + */ + public String getDisplayName(); + /** + * userinfo + * @return null if not set + */ + public String getUserName(); + /** + * + * @return null if not set + */ + public String getDomain(); +} diff --git a/src/org/linphone/core/LinphoneAddressImpl.java b/src/org/linphone/core/LinphoneAddressImpl.java new file mode 100644 index 000000000..83176180e --- /dev/null +++ b/src/org/linphone/core/LinphoneAddressImpl.java @@ -0,0 +1,61 @@ +/* +LinphoneAddressImpl.java +Copyright (C) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.core; + + + +public class LinphoneAddressImpl implements LinphoneAddress { + protected final long nativePtr; + boolean ownPtr = false; + private native long newLinphoneAddressImpl(String uri,String displayName); + private native void delete(long ptr); + private native String getDisplayName(long ptr); + private native String getUserName(long ptr); + private native String getDomain(long ptr); + + + protected LinphoneAddressImpl(String username,String domain,String displayName) { + nativePtr = newLinphoneAddressImpl("sip:"+username+"@"+domain, displayName); + } + protected LinphoneAddressImpl(long aNativePtr) { + nativePtr = aNativePtr; + ownPtr=false; + } + protected void finalize() throws Throwable { + if (ownPtr) delete(nativePtr); + } + public String getDisplayName() { + return getDisplayName(nativePtr); + } + public String getDomain() { + return getDomain(nativePtr); + } + public String getUserName() { + return getUserName(nativePtr); + } + + public String toString() { + String tmp=""; + if (getDisplayName()!=null) { + tmp="<"+getDisplayName()+">"; + } + return tmp+"sip:"+getUserName()+"@"+getDomain(); + } + +} diff --git a/src/org/linphone/core/LinphoneAuthInfoImpl.java b/src/org/linphone/core/LinphoneAuthInfoImpl.java index 15a064ec9..719101883 100644 --- a/src/org/linphone/core/LinphoneAuthInfoImpl.java +++ b/src/org/linphone/core/LinphoneAuthInfoImpl.java @@ -1,3 +1,21 @@ +/* +LinphoneAuthInfoImpl.java +Copyright (C) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ package org.linphone.core; class LinphoneAuthInfoImpl implements LinphoneAuthInfo { diff --git a/src/org/linphone/core/LinphoneCore.java b/src/org/linphone/core/LinphoneCore.java index 8ae0effd3..0a327f481 100644 --- a/src/org/linphone/core/LinphoneCore.java +++ b/src/org/linphone/core/LinphoneCore.java @@ -89,6 +89,11 @@ public interface LinphoneCore { public void invite(String uri); public void terminateCall(); + /** + * get the remote address in case of in/out call + * @return null if no call engaged yet + */ + public LinphoneAddress getRemoteAddress(); public void iterate(); } diff --git a/src/org/linphone/core/LinphoneCoreImpl.java b/src/org/linphone/core/LinphoneCoreImpl.java index 0e4956566..2ef2895f6 100644 --- a/src/org/linphone/core/LinphoneCoreImpl.java +++ b/src/org/linphone/core/LinphoneCoreImpl.java @@ -38,6 +38,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void addAuthInfo(long nativePtr,long authInfoNativePtr); private native void invite(long nativePtr,String uri); private native void terminateCall(long nativePtr); + private native long getRemoteAddress(long nativePtr); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { mListener=listener; @@ -87,6 +88,14 @@ class LinphoneCoreImpl implements LinphoneCore { public void terminateCall() { terminateCall(nativePtr); } + public LinphoneAddress getRemoteAddress() { + long ptr = getRemoteAddress(nativePtr); + if (ptr==0) { + return null; + } else { + return new LinphoneAddressImpl(ptr); + } + } } diff --git a/src/org/linphone/core/LinphoneProxyConfig.java b/src/org/linphone/core/LinphoneProxyConfig.java index 17085de82..8e338e613 100644 --- a/src/org/linphone/core/LinphoneProxyConfig.java +++ b/src/org/linphone/core/LinphoneProxyConfig.java @@ -45,6 +45,10 @@ public interface LinphoneProxyConfig { * @throws LinphoneCoreException */ public void enableRegister(boolean value) throws LinphoneCoreException; - - + /** + * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 + * @param number + * @return + */ + public String normalizePhoneNumber(String number); } diff --git a/src/org/linphone/core/LinphoneProxyConfigImpl.java b/src/org/linphone/core/LinphoneProxyConfigImpl.java index f1de9707b..7c65c7b28 100644 --- a/src/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/src/org/linphone/core/LinphoneProxyConfigImpl.java @@ -55,6 +55,8 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { private native void enableRegister(long ptr,boolean value); + private native String normalizePhoneNumber(long ptr,String number); + public void enableRegister(boolean value) { enableRegister(nativePtr,value); } @@ -76,4 +78,7 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { throw new LinphoneCoreException("Bad proxy address ["+proxyUri+"]"); } } + public String normalizePhoneNumber(String number) { + return normalizePhoneNumber(nativePtr,number); + } }