Android SIP手动注册&x2B;文本视图更新

Android SIP手动注册&x2B;文本视图更新,android,sip,Android,Sip,我正试图编写一个运行在android上的简单SIP客户端,我下载了SIPDemo项目以便与之联系,然后我开始编写代码,我遇到了一些问题 让我们向您展示代码: package com.example.gt_sipclient; import java.text.ParseException; import android.net.sip.SipAudioCall; import android.net.sip.SipException; import android.net.sip.SipMa

我正试图编写一个运行在android上的简单SIP客户端,我下载了SIPDemo项目以便与之联系,然后我开始编写代码,我遇到了一些问题

让我们向您展示代码:

package com.example.gt_sipclient;

import java.text.ParseException;

import android.net.sip.SipAudioCall;
import android.net.sip.SipException;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
import android.net.sip.SipRegistrationListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

//Activity android simple pour effectuer quelques appels VoIP
//et réaliser des tests.
public class SIPCliMainActivity extends Activity {

private TextView numText, domText, usrText, pswText, callerIDText, sipText,
        statusText;
private EditText numInput, domInput, usrInput, pswInput, callerIDInput,
        sipInput;
private Button callBtn, registerBtn, unregisterBtn;
private String number, domain, username, password, callerID, sipPort;

public SipManager mySipManager = null;
public SipProfile mySipProfile = null;
public SipAudioCall call = null;
public IncomingCallReceiver callReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sipcli_main);

    // TODO: virer les éléments qui ne seront pas utilisés au final
    // Get the layout elements
    // TextViews
    numText = (TextView) findViewById(R.id.number_title);
    domText = (TextView) findViewById(R.id.domain);
    usrText = (TextView) findViewById(R.id.username);
    pswText = (TextView) findViewById(R.id.password);
    callerIDText = (TextView) findViewById(R.id.callerid);
    sipText = (TextView) findViewById(R.id.sipport);
    statusText = (TextView) findViewById(R.id.status);

    // EditText views
    numInput = (EditText) findViewById(R.id.number_input);
    domInput = (EditText) findViewById(R.id.domain_input);
    usrInput = (EditText) findViewById(R.id.username_input);
    pswInput = (EditText) findViewById(R.id.password_input);
    callerIDInput = (EditText) findViewById(R.id.callerid_input);
    sipInput = (EditText) findViewById(R.id.sipport_input);

    // Button views
    callBtn = (Button) findViewById(R.id.callbtn);
    registerBtn = (Button) findViewById(R.id.registerbtn);
    unregisterBtn = (Button) findViewById(R.id.unregisterbtn);

    // make sure that the screen will not turn off during the app lifecycle
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

}

// handle click events without implementing listeners (see layout file
// android:onclick)
// register handling
public void registerClick(View v) {

    // Get the SIP account parameters
    domain = domInput.getText().toString().trim();
    username = usrInput.getText().toString().trim();

    // TODO: penser à stocker le psw en MD5 et à le faire aussi dans le
    // sip.conf
    password = pswInput.getText().toString().trim();
    callerID = callerIDInput.getText().toString().trim();
    sipPort = sipInput.getText().toString().trim();

    sipManagerInit();

}

public void unregisterClick(View v) {

    myProfileClose();

}

// TODO: call handling
public void callClick(View v) {

}

public void sipManagerInit() {
    if (mySipManager == null)
        mySipManager = SipManager.newInstance(this);

    myProfileInit();
}

public void myProfileInit() {
    if (mySipManager == null)
        return;

    // TODO: test si un profil est déjà présent

    // TODO: Load persistent data if they exist
    // SharedPreferences myPreferences =
    // PreferenceManager.getDefaultSharedPreferences(getBaseContext());

    if (username == null || password == null || domain == null) {
        updateStatus("Please fill the form.");
        return;
    }

    try {
        SipProfile.Builder builder = new SipProfile.Builder(username,
                domain);
        builder.setPassword(password);
        // important
        //builder.setAutoRegistration(false);
        mySipProfile = builder.build();

        // open myProfile for making and receiving calls

        Intent i = new Intent();
        i.setAction("com.example.gt_sipclient.INCOMING_CALL");
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i,
                Intent.FILL_IN_DATA);
        mySipManager.open(mySipProfile, pi, null);

        //manual register
        //mySipManager.register(mySipProfile, 60, null);

        // set SIP registration events

        mySipManager.setRegistrationListener(mySipProfile.getUriString(),
                new SipRegistrationListener() {

                    @Override
                    public void onRegistrationFailed(String arg0, int arg1,
                            String arg2) {
                        updateStatus("Registration failed");

                    }

                    @Override
                    public void onRegistrationDone(String arg0, long arg1) {
                        updateStatus("Registration OK");
                        registerBtn.setVisibility(View.INVISIBLE);
                    }

                    @Override
                    public void onRegistering(String arg0) {
                        updateStatus("Registering with SIP server...");

                    }
                });

    } catch (ParseException e) {
        // TODO getMessage juste pour le debug
        updateStatus("Connection error." + e.getMessage());
    } catch (SipException e) {
        // TODO getMessage juste pour le debug
        updateStatus("Connection error SIP." + e.getMessage());
    }

}

public void myProfileClose() {
    if (mySipManager == null)
        return;

    try {
        if (mySipProfile != null) {
            mySipManager.close(mySipProfile.getUriString());
            unregisterBtn.setVisibility(View.VISIBLE);
        }
    } catch (Exception ee) {
        Log.d("WalkieTalkieActivity/onDestroy",
                "Failed to close local profile.", ee);
    }
}

//TODO: completer cette methode pour se desinscrire du serveur manuellement
public void myProfileUnregister(){
    if(mySipManager == null)
        return;

    try {
        if(mySipProfile != null && mySipManager.isRegistered(mySipProfile.getUriString())){
            mySipManager.unregister(mySipProfile, new SipRegistrationListener(){

                @Override
                public void onRegistering(String localProfileUri) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onRegistrationDone(String localProfileUri,
                        long expiryTime) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onRegistrationFailed(String localProfileUri,
                        int errorCode, String errorMessage) {
                    // TODO Auto-generated method stub

                }

            });
        }
    } catch (SipException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.sipcli_main, menu);
    return true;
}

//Allez on va coder un thread propre pour la maj
public void updateStatus(final String status) {


    this.runOnUiThread(new Runnable() {

        @Override
        public void run() {
            statusText.setText(status);

        }

    });

}

public void updateStatus(SipAudioCall call) {
    String useName = call.getPeerProfile().getDisplayName();
    // TODO: watch it
    if (useName == null)
        useName = call.getPeerProfile().getUserName();

    updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());

}

    }
好的,现在当我运行应用程序时,我有以下错误:

03-06 17:38:35.931: E/JavaBinder(3754): *** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
03-06 17:38:35.931: E/JavaBinder(3754): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4039)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.ViewRootImpl.invalidateChild(ViewRootImpl.java:722)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:771)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.ViewGroup.invalidateChild(ViewGroup.java:4005)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.View.invalidate(View.java:8581)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.View.setFlags(View.java:6766)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.view.View.setVisibility(View.java:4617)
03-06 17:38:35.931: E/JavaBinder(3754):     at com.example.gt_sipclient.SIPCliMainActivity$1.onRegistrationDone(SIPCliMainActivity.java:163)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.net.sip.SipManager$ListenerRelay.onRegistrationDone(SipManager.java:601)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.net.sip.ISipSessionListener$Stub.onTransact(ISipSessionListener.java:167)
03-06 17:38:35.931: E/JavaBinder(3754):     at android.os.Binder.execTransact(Binder.java:338)
03-06 17:38:35.931: E/JavaBinder(3754):     at dalvik.system.NativeStart.run(Native Method)
问题是,我正在尝试为通过的每个注册步骤更新TextView,我认为使用runOnUiThread可以,但我显然遗漏了一些东西。不用担心注册,它运行得很好(有点慢,但无论如何…),我可以在我的SIP服务器上看到设备

我的第二个问题是关于避免自动注册:我希望用户通过单击按钮(如zoiper客户端中的按钮,如果您知道的话)将自己注册/注销到SIP服务器。我找不到任何关于此的示例,但如果您有一些示例,我很乐意阅读这些示例。
如果您需要更多信息,请告诉我。

您还需要移动
registerBtn.setVisibility(View.INVISIBLE)内部
runOnUiThread
。将注册完成后的代码更改为:

 @Override
 public void onRegistrationDone(String arg0, long arg1) {
   updateStatus("Registration OK");  
  }
///..your code here....

public void updateStatus(final String status) {
    SIPCliMainActivity.this.runOnUiThread(new Runnable() {

        @Override
        public void run() {
            statusText.setText(status);
            registerBtn.setVisibility(View.INVISIBLE);
        }

    });
}

是的,它成功了,这是一个巨大的错误!无论如何,我决定暂时不将我的registerbtn设置为不可见,因为如果我用这种方法设置它,每次完成注册步骤时,按钮都会被设置。关于SipManager.register的第二个问题,有什么建议吗?