1

I'm Developing VoIP App for call app to app. I am using Sinch API, FCM for receiving incoming in background. It is working fine, but when the app is killed in the background I am not getting incoming calls.

My code is as follows:

FCM-

  public class FireBaseMsgService extends FirebaseMessagingService {
        public static SinchClient sinchClient=null;
        public static CallClient callClient=null;
        String username;

        @Override
        public void onCreate() {
            username=Common.getSavedUserData(this,"user_name");
            super.onCreate();

            if (username != null) {
                initsinch();
            }
        }
    
        @Override
        public void onMessageReceived(RemoteMessage remoteMessage) {
            super.onMessageReceived(remoteMessage);
            //initsinch();

            if (foregrounded()) {
                return;
            }

            if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
    
                initsinch();
                NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getData());     // relay the background incoming call
            }
        }
    
        // To check if the app is in foreground 
        public static boolean foregrounded() {
            ActivityManager.RunningAppProcessInfo appProcessInfo =
                    new ActivityManager.RunningAppProcessInfo();
            ActivityManager.getMyMemoryState(appProcessInfo);
            return (appProcessInfo.importance == IMPORTANCE_FOREGROUND
                    || appProcessInfo.importance == IMPORTANCE_VISIBLE);
        } 

        private void initsinch() {
            if (sinchClient == null) {
                android.content.Context context = this.getApplicationContext();
                sinchClient = Sinch.getSinchClientBuilder().context(context)
                        .applicationKey(APP_KEY)
                        .applicationSecret(APP_SECRET)
                        .environmentHost(ENVIORNMENT)
                        .userId(username).build();
    
                sinchClient.setSupportCalling(true);
                sinchClient.setSupportActiveConnectionInBackground(true);
                sinchClient.startListeningOnActiveConnection();
                sinchClient.setSupportManagedPush(true);
    
                sinchClient.setPushNotificationDisplayName("my display name");
                sinchClient.addSinchClientListener(new SinchClientListener() {
    
                    public void onClientStarted(SinchClient client) {
                    }

                    public void onClientStopped(SinchClient client) {
                    }

                    public void onClientFailed(SinchClient client, SinchError error) {
                    }

                    public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration registrationCallback) {
                    }

                    public void onLogMessage(int level, String area, String message) {
                    }
                });

                callClient = sinchClient.getCallClient();
                callClient.setRespectNativeCalls(true);
                callClient.addCallClientListener(new CallClientListener() {
                    @Override
                    public void onIncomingCall(CallClient callClient, Call INCOMINGCALL) {
    
    
                        Intent it=new Intent(getApplicationContext(),IncomingCallScreenActivity.class);
                        it.putExtra("mCall", INCOMINGCALL.getCallId());
                        it.putExtra("mCall_caller", INCOMINGCALL.getRemoteUserId());
                        it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(it);
                    }
                });
            }

            if (sinchClient != null && !sinchClient.isStarted()) {
                sinchClient.start();
            }
        }
    }

The Username is the login username which is intialized in Sinch User. I have created mCall object in IncomingCallActivity.call and receiving the call object in Onservice Connected() and calling sinchCall listener as follows,

 public class IncomingCallScreenActivity extends BaseActivity {
    static final String TAG=IncomingCallScreenActivity.class.getSimpleName();
    private String mCallId;
    private String mCallLocation;
    private AudioPlayer mAudioPlayer;
    TextView highlight;
   // private NotificationCallvo mCallVo;
    Call fmcall;
    ImageView img;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.incoming);
        highlight=(TextView)findViewById(R.id.highlight);
        Animation a = AnimationUtils.loadAnimation(this, R.anim.blink);
        a.reset();
        highlight.startAnimation(a);
        img=(ImageView)findViewById(R.id.image);
        // Animation shake = AnimationUtils.loadAnimation(this, R.anim.milkshake);
        // img.startAnimation(shake);
        ImageButton answer=(ImageButton)findViewById(R.id.answerButton);
        Animation shake = AnimationUtils.loadAnimation(this, R.anim.milkshake);
        answer.startAnimation(shake);
        answer.setOnClickListener(mClickListener);
        ImageButton decline=(ImageButton) findViewById(R.id.declineButton);
        decline.startAnimation(shake);

        decline.setOnClickListener(mClickListener);

        mAudioPlayer=new AudioPlayer(this);
        mAudioPlayer.playRingTone();

        mCallId=getIntent().getStringExtra(SinchService.CALL_ID);
        System.out.println("cllerid++"+mCallId);
        mCallLocation=getIntent().getStringExtra(SinchService.LOCATION);

    }

    @Override
    protected void onServiceConnected()
    {
        if(getIntent().getExtras().get("mCall")!=null){
            fmcall=FireBaseMsgService.callClient.getCall((String) getIntent().getExtras().get("mCall"));
            ((Call) fmcall).addCallListener(new SinchCallListener());
            TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
            remoteUser.setText(((Call) fmcall).getRemoteUserId());
            // TextView remoteUserLocation = (TextView) findViewById(R.id.remoteUserLocation);
            //   remoteUserLocation.setText("Calling from " + mCallLocation);
        }else {
            Call call = getSinchServiceInterface().getCall(mCallId);

            if (call != null) {

                call.addCallListener(new SinchCallListener());
                TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
                remoteUser.setText(call.getRemoteUserId());
                TextView remoteUserLocation = (TextView) findViewById(R.id.remoteUserLocation);
                remoteUserLocation.setText("Calling from " + mCallLocation);

            } else {
                Log.e(TAG, "Started with invalid callId, aborting");
                finish();
            }

        }


    }

    private void answerClicked() {
        mAudioPlayer.stopRingtone();
        if (getIntent().getExtras().get("mCall") != null) {
            fmcall = FireBaseMsgService.callClient.getCall((String) getIntent().getExtras().get("mCall"));
            fmcall.answer();
            Intent intent = new Intent(this, CallScreenActivity.class);
            intent.putExtra("fcallId", (String) getIntent().getExtras().get("mCall"));
            startActivity(intent);
        } else {
            Call call = getSinchServiceInterface().getCall(mCallId);
            if (call != null) {
                call.answer();
                Intent intent = new Intent(this, CallScreenActivity.class);
                intent.putExtra(SinchService.CALL_ID, mCallId);
                startActivity(intent);
            } else {
                finish();
            }
        }
    }

    private void declineClicked(){
        mAudioPlayer.stopRingtone();
        if(getIntent().getExtras().get("mCall")!=null){
            fmcall.hangup();
        }else {
            Call call=getSinchServiceInterface().getCall(mCallId);
            if(call!=null)
            {
                call.hangup();
            }
            finish();
        }

    }
    private class SinchCallListener implements CallListener {

        @Override
        public void onCallProgressing(Call call) {
            Log.d(TAG,"Call progressing");
        }

        @Override
        public void onCallEstablished(Call call) {
            Log.d(TAG,"Call Established");
        }

        @Override
        public void onCallEnded(Call call) {
            CallEndCause cause=call.getDetails().getEndCause();
            Log.d(TAG, "Call ended, cause: " + cause.toString());
            mAudioPlayer.stopRingtone();
            finish();
        }

        @Override
        public void onShouldSendPushNotification(Call call, List<PushPair> list) {

        }
    }
    private View.OnClickListener mClickListener=new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch (view.getId())
            {
                case R.id.answerButton:
                    answerClicked();
                    break;
                case R.id.declineButton:
                    declineClicked();
                    break;
            }
        }
    };
}

When I Kill the App in background and make call to the username with another device, I am not receiving call notification. please help

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
prashant
  • 29
  • 5
  • please used sinch push notification, it is easily solved your issue. Bc using sinch push notification get a video call both platforms working (app background/foreground/app kill form) – mujjuraja Sep 16 '19 at 05:27

1 Answers1

2

For that you need to prepare one service. below is the code of service.

public class SinchService extends Service {

private static final String APP_KEY = "REPLACE_WITH_YOUR_APP_KEY";
private static final String APP_SECRET = "REPLACE_WITH_APP_SECRET";
private static final String ENVIRONMENT = "sandbox.sinch.com";

public static final String LOCATION = "LOCATION";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();

private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;

private StartFailedListener mListener;



@Override
public void onCreate() {
    super.onCreate();
}

@Override
public void onDestroy() {
    if (mSinchClient != null && mSinchClient.isStarted()) {
        mSinchClient.terminate();
    }
    super.onDestroy();
}

private void start(String userName) {
    if (mSinchClient == null) {
        mUserId = userName;
        mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
                .applicationKey(APP_KEY)
                .applicationSecret(APP_SECRET)
                .environmentHost(ENVIRONMENT).build();

        mSinchClient.setSupportCalling(true);
        mSinchClient.startListeningOnActiveConnection();

        mSinchClient.addSinchClientListener(new MySinchClientListener());
        mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
        mSinchClient.start();
    }
}

private void stop() {
    if (mSinchClient != null) {
        mSinchClient.terminate();
        mSinchClient = null;
    }
}

private boolean isStarted() {
    return (mSinchClient != null && mSinchClient.isStarted());
}

@Override
public IBinder onBind(Intent intent) {
    return mSinchServiceInterface;
}

public class SinchServiceInterface extends Binder {

    public Call callPhoneNumber(String phoneNumber) {
        return mSinchClient.getCallClient().callPhoneNumber(phoneNumber);
    }

    public Call callUser(String userId) {
        return mSinchClient.getCallClient().callUser(userId);
    }

    public Call callUser(String userId, Map<String, String> headers) {
        return mSinchClient.getCallClient().callUser(userId, headers);
    }

    public String getUserName() {
        return mUserId;
    }

    public boolean isStarted() {
        return SinchService.this.isStarted();
    }

    public void startClient(String userName) {
        start(userName);
    }

    public void stopClient() {
        stop();
    }

    public void setStartListener(StartFailedListener listener) {
        mListener = listener;
    }

    public Call getCall(String callId) {
        return mSinchClient.getCallClient().getCall(callId);
    }

    public NotificationResult relayRemotePushNotificationPayload(final Map payload) {

        if (mSinchClient == null && !mUserId.isEmpty()) {
            start(mUserId);
        } else if (mSinchClient == null && mUserId.isEmpty()) {
            Log.e(TAG, "Can't start a SinchClient as no username is available, unable to relay push.");
            return null;
        }
        return mSinchClient.relayRemotePushNotificationPayload(payload);
    }
}

public interface StartFailedListener {
    void onStartFailed(SinchError error);

    void onStarted();
}

private class MySinchClientListener implements SinchClientListener {

    @Override
    public void onClientFailed(SinchClient client, SinchError error) {
        if (mListener != null) {
            mListener.onStartFailed(error);
        }
        mSinchClient.terminate();
        mSinchClient = null;
    }

    @Override
    public void onClientStarted(SinchClient client) {
        Log.d(TAG, "SinchClient started");
        if (mListener != null) {
            mListener.onStarted();
        }
    }

    @Override
    public void onClientStopped(SinchClient client) {
        Log.d(TAG, "SinchClient stopped");
    }

    @Override
    public void onLogMessage(int level, String area, String message) {
        switch (level) {
            case Log.DEBUG:
                Log.d(area, message);
                break;
            case Log.ERROR:
                Log.e(area, message);
                break;
            case Log.INFO:
                Log.i(area, message);
                break;
            case Log.VERBOSE:
                Log.v(area, message);
                break;
            case Log.WARN:
                Log.w(area, message);
                break;
        }
    }

    @Override
    public void onRegistrationCredentialsRequired(SinchClient client,
            ClientRegistration clientRegistration) {
    }
}

private class SinchCallClientListener implements CallClientListener {

    @Override
    public void onIncomingCall(CallClient callClient, Call call) {
        Log.d(TAG, "Incoming call");
        Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
        intent.putExtra(CALL_ID, call.getCallId());
        intent.putExtra(LOCATION, call.getHeaders().get("location"));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        SinchService.this.startActivity(intent);
    }
}

}

After that start this service with below code in your main activity after sinch permission allowed by user

FirebaseApp.initializeApp(this);
            getApplicationContext().bindService(new Intent(this, SinchService.class), this,
                    BIND_AUTO_CREATE);

And replace your FireBaseMsgService with below code

public class FireBaseMsgService extends FirebaseMessagingService {

@Override
public void onMessageReceived(RemoteMessage remoteMessage){
    Map data = remoteMessage.getData();
    if (SinchHelpers.isSinchPushPayload(data)) {
        new ServiceConnection() {
            private Map payload;

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                if (payload != null) {
                    SinchService.SinchServiceInterface sinchService = (SinchService.SinchServiceInterface) service;
                    if (sinchService != null) {
                        NotificationResult result = sinchService.relayRemotePushNotificationPayload(payload);
                        // handle result, e.g. show a notification or similar
                    }
                }
                payload = null;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {}

            public void relayMessageData(Map<String, String> data) {
                payload = data;
                getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, BIND_AUTO_CREATE);
            }
        }.relayMessageData(data);
    }
}

}

Create temp Foreground service

public class TempService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        startMyOwnForeground();
    else
        startForeground(1, new Notification());
    return START_STICKY;
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground(){
    String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";
    String channelName = "My Background Service";
    NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
    chan.setLightColor(Color.BLUE);
    chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    assert manager != null;
    manager.createNotificationChannel(chan);

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
    Notification notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setContentTitle("App is running in background")
            .setPriority(NotificationManager.IMPORTANCE_MIN)
            .setCategory(Notification.CATEGORY_SERVICE)
            .build();
    startForeground(2, notification);
}

}

and start that service in main activity

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(new Intent(this,TempService.class));
    } else
        startService(new Intent(this,TempService.class));

Manifest Declaration part

   <service
        android:name=".TempService"
        android:exported="true"/>

Check once in your code that you don't have below code if it is there then please comment it

 getSinchServiceInterface().stopClient();
  • thanks for response,sir, it is not working when app is killed in background i have used this link-https://github.com/sinch/android-app-app-calling-headers.. – prashant Mar 08 '19 at 07:27
  • the tutorial is incomplete .My requirment is to get incoming call when app is not using or it is swipe clear in background..your answer is working fine in foreground but not working in after killing the app. – prashant Mar 08 '19 at 07:34
  • I am displaying the Incoming call activity on for incoming calls by refererring this link-https://stackoverflow.com/questions/38556403/sinch-not-running-in-background-no-way-android/48810297#48810297 – prashant Mar 08 '19 at 07:52
  • The only option left is to use foreground service –  Mar 08 '19 at 09:52
  • "still same problem.. worked with temp service." -> Does this work or not ? –  Mar 08 '19 at 12:14
  • Used temp service ,still not working ,.when we kill app foreground the login username ,sinch key ,variables also vanishing ..so not getting incoming call..is it necessary to intialize once again on message received method of Firebase messaging service.or this method is called when we make call to user – prashant Mar 08 '19 at 12:43
  • Can you share ur current full code So I can have look? as this solution works perfectly for us –  Mar 08 '19 at 12:50
  • please give me your email i will send the full code – prashant Mar 09 '19 at 04:38
  • https://drive.google.com/file/d/1A8BjzjWwVkK7k6gFZ-lFqrmx1ZJElIKx/view?usp=sharing – prashant Mar 09 '19 at 04:41
  • Hi i have one more doubt that i have two different apps where in one app called doctor's app ,calls to another app which is used by patient app..do I need to add FCm to both apps or adding fcm to only patient app for incoming calls in background .? – prashant Mar 09 '19 at 05:59
  • The foreground service given by you working fine in Oreo, but not working in Nougat version – prashant Mar 09 '19 at 07:35