Я разработал версию родного демо-приложения SIP, предоставленного Google https://android.googlesource.com/platform/development/+/master/samples/SipDemo/
Приложение My Simple регистрируется на SIP-сервере, и когда на эту учетную запись SIP получено приглашение к вызову, уведомление и тостотображается с идентификатором звонящего.Я не разработал приложение для запуска в качестве службы или чего-либо еще.После запуска действия приложение регистрируется на SIP-сервере, а затем я просто нажимаю кнопку «Домой» и запускаю приложение в фоновом режиме, ожидая входящего вызова.
Приложение работает правильно, просто в течение ~ 12 - 24 часов приложение, кажется, было остановлено ОС Android.Я не уверен, связано ли это с собственным стеком SIP или диспетчером ресурсов Android, закрывающим приложение, но я попытался настроить все, что смогу, на самой трубке, чтобы предотвратить остановку приложения, например, удалить все настройки экономии заряда аккумулятора и т. Д.
Есть ли какие-либо советы, чтобы приложение работало в фоновом режиме с помощью собственного SIP API?
Мой код ниже:
CallerIDActivity.java -
package example.callerid;
//This app has been developed with a target API of 22 so as to avoid having to
//implement runtime permissions on the test handset with a higher API level.
import android.Manifest;
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.sip.SipException;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
import android.net.sip.SipRegistrationListener;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Random;
public class CallerIDactivity extends Activity {
public SipManager manager = null;
public SipProfile me = null;
public IncomingCallReceiver callReceiver;
public CallerIDactivity (){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createNotificationChannel();
}//end constructor
//define NotificationChannel method for use in the contructor above
//IncomingCallReciever will then use this channel to send notification of CID
public void createNotificationChannel(){
//Create the Notification but only on API 26+ as the
//notification class is new and not in the support lib
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
CharSequence name = "CHANNEL_NAME";
String description = "CID_NOTIFY";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel("CHANNEL_ID", name, importance);
channel.setDescription(description);
//Register the channel with the system: you can't change the importance
//or other notification behaviour after this
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if(notificationManager !=null) {
notificationManager.createNotificationChannel(channel);
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.callerid);
// Set up the intent filter. This will be used to trigger an
// IncomingCallReceiver when someone calls the SIP address used by this
// application.
IntentFilter filter = new IntentFilter();
filter.addAction("android.CallerID.INCOMING_CALL");
callReceiver = new IncomingCallReceiver();
this.registerReceiver(callReceiver, filter);
}//end onCreate
@Override
public void onStart() {
super.onStart();
// When we get back from the preference setting Activity, assume
// settings have changed, and re-login with new auth info.
initializeManager();
}
@Override
public void onDestroy() {
super.onDestroy();
closeLocalProfile();
if (callReceiver != null) {
this.unregisterReceiver(callReceiver);
Log.d("CallerID", "UnRegisteringReceiverOnDestroy ");
Toast toast = Toast.makeText(getApplicationContext(), "UnRegisteringReceiverOnDestroy", Toast.LENGTH_LONG);
toast.show();
}
}//end onDestroy
public void RegisterBtn(View callerid){
initializeManager();
Log.d("CallerIDactivity","RegisterBtn Press");
Toast toast = Toast.makeText(getApplicationContext(),"Registering", Toast.LENGTH_SHORT);
toast.show();
}
public void initializeManager() {
if(manager == null) {
manager = SipManager.newInstance(this);
}
initializeLocalProfile();
}
public void initializeLocalProfile() {
if (manager == null) {
return;
}
if (me != null) {
closeLocalProfile();
}
try {
SipProfile.Builder builder = new SipProfile.Builder("sipaccount", "my.sip.server");
builder.setPassword("pass");
me = builder.build();
Intent i = new Intent();
i.setAction("android.CallerID.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
manager.open(me,pi,null);
// This listener must be added AFTER manager.open is called,
// Otherwise the methods aren't guaranteed to fire.
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
updateStatus("Registering with SIP Server...");
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
updateStatus("Ready");
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
updateStatus("Registration failed. Please check settings.");
}
});
}catch (ParseException pe) {
updateStatus("Connection Error.");
} catch (SipException se) {
updateStatus("Connection error.");
}
}
/**
* Closes out your local profile, freeing associated objects into memory
* and unregistering your device from the server.
*/
public void closeLocalProfile() {
if (manager == null) {
Log.d("closeLocalProfile", "manager == null");
return;
}
try {
if (me != null) {
manager.close(me.getUriString());
Toast toast = Toast.makeText(getApplicationContext(), "ClosingProfileURI"+" "+me.getUriString(), Toast.LENGTH_SHORT);
toast.show();
}
} catch (Exception ee) {
Toast toast = Toast.makeText(getApplicationContext(), ee.getMessage(), Toast.LENGTH_SHORT);
toast.show();
Log.d("onDestroy", "Failed to close local profile.", ee);
}
}
/**
* Updates the status box at the top of the UI with a messege of your choice.
* @param status The String to display in the status box.
*/
public void updateStatus(final String status) {
this.runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(getApplicationContext(), status, Toast.LENGTH_SHORT);
toast.show();
}});
/* Be a good citizen. Make sure UI changes fire on the UI thread.
this.runOnUiThread(new Runnable() {
public void run() {
Log.i("allenssip",status);
TextView labelView = (TextView) findViewById(R.id.sipLabel);
labelView.setText(status);
}
});
*/
}//end updateStatus
}//end Class
IncomingCallReceiver.java -
package example.callerid;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.sip.*;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Random;
/**
* Listens for incoming SIP calls, intercepts and hands them off to CallerIDactivity.
*/
public class IncomingCallReceiver extends BroadcastReceiver {
public Calendar calendar;
public SimpleDateFormat dateFormat;
public String date;
public SipManager mSipManager;
public SipSession mSipSesion;
public SipProfile peerProfile;
static private int notifyNum = 1;
/**
* Processes the incoming call, answers it, and hands it over to the
* CallerIDactivity.
* @param context The context under which the receiver is running.
* @param intent The intent being received.
*/
@Override
public void onReceive(Context context, Intent intent) {
mSipManager = SipManager.newInstance(context);
try {
mSipSesion = mSipManager.getSessionFor(intent);
} catch (SipException e) {
e.printStackTrace();
}
peerProfile = mSipSesion.getPeerProfile();
calendar = Calendar.getInstance();
dateFormat = new SimpleDateFormat("dd/MM/yyyy");
date = dateFormat.format(calendar.getTime());
Log.d("CallerID", "OnReceive");
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "CHANNEL_ID")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("CallerID" + " " + date)
.setContentText(peerProfile.getDisplayName())
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if(notifyNum <= 9) {
notificationManager.notify(notifyNum++, mBuilder.build());
}else {notificationManager.notify(notifyNum, mBuilder.build());
notifyNum = 1;
}
int count = 0;
while (count <= 10) {
Toast toast = Toast.makeText(context, peerProfile.getDisplayName(), Toast.LENGTH_SHORT);
toast.show();
count++;
}//end while
}//end onReceive
}//end Class