1

I am developing video calling app using Quickblox-SDK for android. App is working fine and perfect if the app is open But if the app is in background I am not able to receive call. I've created app using this link please help. I have tried following things:

1) Opening CallActivity when the notification arrive, notification using GCM but as its talking time to receive notification this thing is also not working.

Thanks.

PriyankaChauhan
  • 953
  • 11
  • 26

4 Answers4

0

Create a sticky service which will run in background even activity destroy, this service is responsible for QBsession and all other operations so it will detect call in background . Iam successfully implements this and iam successfully receiving calls in background by this.

public class BloxService extends Service implements QBRTCClientSessionCallbacks {
    private QBChatService chatService;
    private volatile boolean resultReceived = true;
    static final String APP_ID = "";
    static final String AUTH_KEY = "";
    static final String AUTH_SECRET = "";
    static final String ACCOUNT_KEY = "";
    private QBRTCClient rtcClient;
    public static BloxService bloxService;
    private static final String TAG = "BloxService";
    public boolean isSessionRunning;
    public boolean isCallRunning;
    private  Date tokenExpirationDate;
    private QBAuth qbAuth;
    private AppPrefs prefs;

    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            /*boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
            String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
            boolean isFailover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);*/
            NetworkInfo currentNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
            //NetworkInfo otherNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
            if(currentNetworkInfo!=null && currentNetworkInfo.isConnected()){
                if(!QBChatService.getInstance().isLoggedIn()){
                    if(!isSessionRunning) {
                        initializeQb();
                    }
                }
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
       // prefs = AppPrefs.getInstance(getApplicationContext()); // for testing we put this line on start
        registerReceiver(this.mConnReceiver,
                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("bloxservice","onDestroy");
        try{
            unregisterReceiver(mConnReceiver);
        }catch (Exception e){

        }
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        prefs = AppPrefs.getInstance(getApplicationContext());
        if (prefs.getData(IS_USER_LOGIN, false)) {
            Log.d("bloxservice","start");
            try {
                if (!QBChatService.getInstance().isLoggedIn()) {
                    initializeQb();
                }
            }catch (Exception e)
            {
                initializeQb();
            }
            bloxService=this;
        }
        else {
            stopSelf();
        }

        return START_STICKY;
    }

    public static BloxService getBloxService() {
        return bloxService;
    }

    public void initializeQb(){
        QBSettings.getInstance().init(getApplicationContext(), APP_ID, AUTH_KEY, AUTH_SECRET);
        QBSettings.getInstance().setAccountKey(ACCOUNT_KEY);
        QBChatService.setDebugEnabled(true);
// added on 20 july
        QBChatService.setDefaultAutoSendPresenceInterval(60);
        QBChatService.ConfigurationBuilder chatServiceConfigurationBuilder = new QBChatService.ConfigurationBuilder();
        chatServiceConfigurationBuilder.setSocketTimeout(60); //Sets chat socket's read timeout in seconds
        chatServiceConfigurationBuilder.setKeepAlive(true); //Sets connection socket's keepAlive option.
        QBChatService.setConfigurationBuilder(chatServiceConfigurationBuilder);
    //    QBChatService.getInstance().startAutoSendPresence(10);// added on 20 july
        chatService = QBChatService.getInstance();

       /* tokenExpirationDate = qbAuth.getTokenExpirationDate();
        try {
          String Token=  QBAuth.getSession().toString();
            QBAuth.createFromExistentToken()
        } catch (QBResponseException e) {
            e.printStackTrace();
        }
*/
        if(AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.IS_USER_LOGIN,false)){
            Log.e("Login Process", "Started");
            isSessionRunning=true;
            String userId=AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.USER_ID,"");
            String name=AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.USER_NAME,"");
            String picUrl=AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.USER_IMAGE,"");
            String phone=prefs.getData(Constants.PrefsConstatnt.USER_PHONE, "");
            if(name.isEmpty()){
                name=userId;
            }
            createAppSession(Integer.parseInt(userId)<10?"0"+userId:userId,name,userId,picUrl,phone);
        }
    }

    private void createAppSession(final String userId, final String name,final String exId,final String picUrl,final String phone) {
        QBAuth.createSession(new QBEntityCallback<QBSession>() {
            @Override
            public void onSuccess(QBSession qbSession, Bundle bundle) {
                loadUsers(userId, name, exId,picUrl,phone);
                final SharedPreferences prefs = getGCMPreferences(getApplicationContext());
                String registrationId = prefs.getString(PROPERTY_REG_ID, "");
                if (registrationId.isEmpty()) {
                }

                // Subscribe to Push Notifications
                //subscribeToPushNotifications(registrationId);


            }
            @Override
            public void onError(QBResponseException exc) {
                exc.printStackTrace();
                isSessionRunning=false;
            }
        });
    }
    //QBUser users;
    public void loadUsers(String userId,String name,String exId,String picUrl,String phone) {
        final QBUser userr = new QBUser(userId, DataHolder.PASSWORD);
        userr.setFullName(name);
        userr.setExternalId(exId);
        userr.setCustomData(picUrl);
        userr.setPhone(phone);
        QBUsers.signUp(userr, new QBEntityCallback<QBUser>() {
            @Override
            public void onSuccess(QBUser user, Bundle args) {
                createSession(userr.getLogin(), userr.getPassword());

            }

            @Override
            public void onError(QBResponseException error) {
                error.printStackTrace();
                QBUsers.signIn(userr, new QBEntityCallback<QBUser>() {
                    @Override
                    public void onSuccess(QBUser user, Bundle args) {
                        createSession(userr.getLogin(), userr.getPassword());
                    }

                    @Override
                    public void onError(QBResponseException error) {
                        error.printStackTrace();
                        isSessionRunning = false;
                    }
                });
            }
        });
    }
    private void createSession(final String login, final String password) {
        final QBUser user = new QBUser(login, password);
        QBAuth.createSession(login, password, new QBEntityCallback<QBSession>() {
            @Override
            public void onSuccess(QBSession session, Bundle bundle) {
                user.setId(session.getUserId());
                Log.e("User" + session.getUserId(), "Login");
                QBSettings.getInstance().fastConfigInit(APP_ID, AUTH_KEY, AUTH_SECRET);
                sendRegistrationToServer(AppPrefs.getInstance(BloxService.this).getData(Constants.PrefsConstatnt.DEVICE_TOKEN, ""));
                DataHolder.setLoggedUser(user);
                if (chatService.isLoggedIn()) {
                    resultReceived = true;
                    initQBRTCClient();
                    isSessionRunning = false;
                } else {
                    chatService.login(user, new QBEntityCallback<Void>() {
                        @Override
                        public void onSuccess(Void result, Bundle bundle) {
                            initQBRTCClient();
                            resultReceived = true;
                            isSessionRunning = false;
                        }
                        @Override
                        public void onError(QBResponseException exc) {
                            resultReceived = true;
                            isSessionRunning = false;
                        }
                    });
                }

/*                QBRosterListener rosterListener = new QBRosterListener() {
                    @Override
                    public void entriesDeleted(Collection<Integer> userIds) {
                        Log.d("mayanks","changed");
                    }

                    @Override
                    public void entriesAdded(Collection<Integer> userIds) {
                        Log.d("mayanks","changed");
                    }

                    @Override
                    public void entriesUpdated(Collection<Integer> userIds) {
                        Log.d("mayanks","changed");
                    }

                    @Override
                    public void presenceChanged(QBPresence presence) {
                        Log.d("mayanks","changed");
                    }
                };

                QBSubscriptionListener subscriptionListener = new QBSubscriptionListener() {
                    @Override
                    public void subscriptionRequested(int userId) {

                    }
                };

                QBRoster chatRoster = QBChatService.getInstance().getRoster(QBRoster.SubscriptionMode.mutual, subscriptionListener);
                chatRoster.addRosterListener(rosterListener);
                Collection<QBRosterEntry> entries = chatRoster.getEntries();
                QBPresence presence = chatRoster.getPresence(9);
                if (presence!=null) {

                    if (presence.getType() == QBPresence.Type.online) {
                        Log.d("mayanks","online");
                        // User is online
                    }else{
                        Log.d("mayanks","offline");
                        // User is offline
                    }
                }*/

            }

            @Override
            public void onError(QBResponseException exc) {
                resultReceived = true;
                isSessionRunning = false;
            }
        });
    }

    private void sendRegistrationToServer(final String token) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                final SharedPreferences prefs = getGCMPreferences(getApplicationContext());
                String deviceID = prefs.getString(PROPERTY_DEVICE_ID, null);
                if(deviceID==null)
                {
                    deviceID=DeviceUtils.getDeviceUid();
                    storeDeviceId(getApplicationContext(),deviceID);
                }
                QBSubscription qbSubscription = new QBSubscription();
                qbSubscription.setNotificationChannel(QBNotificationChannel.GCM);
                qbSubscription.setDeviceUdid(deviceID);
                qbSubscription.setRegistrationID(token);
                qbSubscription.setEnvironment(QBEnvironment.DEVELOPMENT); // Don't forget to change QBEnvironment to PRODUCTION when releasing application
                QBPushNotifications.createSubscription(qbSubscription,
                        new QBEntityCallback<ArrayList<QBSubscription>>() {
                            @Override
                            public void onSuccess(ArrayList<QBSubscription> qbSubscriptions, Bundle bundle) {
                                Log.e(TAG, "Successfully subscribed for QB push messages");
                                //saveGcmRegIdToPreferences(gcmRegId);
                                isSessionRunning=false;
                            }

                            @Override
                            public void onError(QBResponseException error) {
                                Log.e(TAG, "Unable to subscribe for QB push messages; " + error.toString());
                                isSessionRunning=false;
                            }
                        });
            }
        });

    }

    @Override
    public void onReceiveNewSession(final QBRTCSession qbrtcSession) {
        Log.d("bloxservice","CallRecive");
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                if(!isCallRunning) {
                    DataHolder.incomingSession = qbrtcSession;
                   /* Map<String,String> userInfo = qbrtcSession.getUserInfo();
                    String s=userInfo.get("mayank");*/
                    Intent intent = new Intent(BloxService.this, CallActivity.class);
                    intent.putExtra("incoming", true);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
                else{
                    Log.e("User","Busy");
                }
            }
        });
    }

    @Override
    public void onUserNotAnswer(QBRTCSession qbrtcSession, Integer integer) {
       // ToastUtil.showShortToast(this, "no answer");
    }

    @Override
    public void onCallRejectByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
      //  ToastUtil.showShortToast(this,"rejected");
    }

    @Override
    public void onCallAcceptByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
        //ToastUtil.showShortToast(this,"accepted");
    }

    @Override
    public void onReceiveHangUpFromUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {

    }

    @Override
    public void onUserNoActions(QBRTCSession qbrtcSession, Integer integer) {
       // ToastUtil.showShortToast(this,"no Action");
    }

    @Override
    public void onSessionClosed(QBRTCSession qbrtcSession) {
       // ToastUtil.showShortToast(this,"onSessionClosed");
    }

    @Override
    public void onSessionStartClose(QBRTCSession qbrtcSession) {
       // ToastUtil.showShortToast(this,"onSessionStartClose");
    }

    private void initQBRTCClient() {
        rtcClient = QBRTCClient.getInstance(this);
        QBVideoChatWebRTCSignalingManager qbChatService = QBChatService.getInstance().getVideoChatWebRTCSignalingManager();
        if (qbChatService != null) {
            qbChatService.addSignalingManagerListener(new QBVideoChatSignalingManagerListener() {
                @Override
                public void signalingCreated(QBSignaling qbSignaling, boolean createdLocally) {
                    if (!createdLocally) {
                        rtcClient.addSignaling((QBWebRTCSignaling) qbSignaling);
                    }
                }
            });
            QBRTCConfig.setMaxOpponentsCount(2);
            QBRTCConfig.setDisconnectTime(40);
            QBRTCConfig.setAnswerTimeInterval(30l);
            QBRTCConfig.setDebugEnabled(true);

            rtcClient.addSessionCallbacksListener(this);
            rtcClient.prepareToProcessCalls();
            QBChatService.getInstance().addConnectionListener(new AbstractConnectionListener() {
                @Override
                public void connectionClosedOnError(Exception e) {

                }
                @Override
                public void reconnectionSuccessful() {

                }
                @Override
                public void reconnectingIn(int seconds) {
                }
            });
        }
    }

    public void logout(){
        chatService.logout(new QBEntityCallback<Void>() {
            @Override
            public void onSuccess(Void result, Bundle bundle) {
            }
            @Override
            public void onError(QBResponseException list) {
            }
        });
    }

/*    public void subscribeToPushNotifications(String registrationID) {
        QBSubscription subscription = new QBSubscription(QBNotificationChannel.GCM);
        subscription.setEnvironment(QBEnvironment.DEVELOPMENT);
        //
        String deviceId;
        final TelephonyManager mTelephony = (TelephonyManager) getSystemService(
                Context.TELEPHONY_SERVICE);
        if (mTelephony.getDeviceId() != null) {
            deviceId = mTelephony.getDeviceId(); /*//*** use for mobiles
        } else {
            deviceId = Settings.Secure.getString(getContentResolver(),
                    Settings.Secure.ANDROID_ID); /*//*** use for tablets
        }
        subscription.setDeviceUdid(deviceId);
        //
        subscription.setRegistrationID(registrationID);
        //
        QBPushNotifications.createSubscription(subscription, new QBEntityCallback<ArrayList<QBSubscription>>() {

            @Override
            public void onSuccess(ArrayList<QBSubscription> subscriptions, Bundle args) {
                Log.d("push_send","sucess");
            }

            @Override
            public void onError(QBResponseException error) {
                Log.d("push_send","sucess");
            }
        });
    }*/
    private SharedPreferences getGCMPreferences(Context context) {
        // This sample app persists the registration ID in shared preferences,
        // but
        // how you store the regID in your app is up to you.
        Log.e("getGCMPreferences", "package= " + context.getPackageName());
        return getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
    }

    private void storeDeviceId(Context context, String deviceId) {
        final SharedPreferences prefs = getGCMPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(PROPERTY_DEVICE_ID, deviceId);
        editor.commit();
    }

}
Mayank Sharma
  • 2,735
  • 21
  • 26
  • Can you post your CallActivity. ? – PriyankaChauhan Aug 02 '16 at 10:09
  • Can you please help ? – PriyankaChauhan Aug 03 '16 at 05:08
  • there is no major changes in callActivity . you have to fire callActivity from service when call is recive from onReceiveNewSession() iam unable to post here because i have modify it according my need hence code is too long and also there are no changes – Mayank Sharma Aug 03 '16 at 07:08
  • I have created Sticky Service but redirecting to that not able to receive call exception throws like chatService is already initialized or channel is already initialized . You have used rtcClient as Global ? – PriyankaChauhan Aug 03 '16 at 12:33
  • Do not Create Session in CallActivity and run service at the start of app means before CallActivity . You are facing problem because session is create in CallActivity and after that service is try to create session . – Mayank Sharma Aug 03 '16 at 13:26
  • Okay In CallActivity you have removed OnReceiveNewSession and other methods ? how you changed Fragment from service ? – PriyankaChauhan Aug 03 '16 at 13:29
  • no i dont remove OnReceiveNewSession and other overrided method , from service we call activity and then activity is responsible for fragment ( see service code when call receive ) but there is nothing in OnReceiveNewSession in activity because we handle it from service – Mayank Sharma Aug 03 '16 at 13:34
  • iam unable to post my callActivity here because of word limit – Mayank Sharma Aug 03 '16 at 13:38
  • 1
    here is link of CallActivity http://paste.ofcode.org/V9VR5vBzMhh5AXtwhRzNLF – Mayank Sharma Aug 04 '16 at 07:24
  • Thank you so much @Mayank Sharma – PriyankaChauhan Aug 04 '16 at 09:47
  • One more help please, Problem is when call is coming Phone is not ringing only on samsung devices. its working on other devices. Can you please suggest what Can I do ? – PriyankaChauhan Aug 04 '16 at 09:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120099/discussion-between-priyanka-chauhan-and-mayank-sharma). – PriyankaChauhan Aug 04 '16 at 10:14
0

Finally got solutions for this. You can start activity onReveiveNewSession overridden method of the CallActivity

 @Override
public void onReceiveNewSession(final QBRTCSession session) {

    Log.e("PLog", "Session " + session.getSessionID() + " are income");


    Log.d(TAG, "Session " + session.getSessionID() + " are income");
    String curSession = (getCurrentSession() == null) ? null : getCurrentSession().getSessionID();

    if (getCurrentSession() == null) {
        Log.d(TAG, "Start new session");
        initCurrentSession(session);

        setOptionsForSession(session, getDefaultSharedPrefs());
         addIncomeCallFragment(session);

        isInCommingCall = true;
        initIncommingCallTask();
        Intent i = new Intent(CallActivity.this, CallActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(i);
    } else {
        Log.d(TAG, "Stop new session. Device now is busy");
        Map<String, String> infoMap = new HashMap<>();
        infoMap.put(Consts.REJECT_REASON, "I'm on a call right now!");
        session.rejectCall(infoMap);
    }

}
PriyankaChauhan
  • 953
  • 11
  • 26
0

I have got it working now. Add following method to PushListenerService

class PushListenerService : QBFcmPushListenerService() {

    private val TAG = PushListenerService::class.java.simpleName

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        if (SharedPrefsHelper.hasQbUser()) {
            val qbUser: QBUser = SharedPrefsHelper.getQbUser()
            Log.v(TAG, "App has logged user" + qbUser.id)
            LoginService.start(this, qbUser)
        }
    }

    override fun sendPushMessage(data: MutableMap<Any?, Any?>?, from: String?, message: String?) {
        super.sendPushMessage(data, from, message)
        Log.v(TAG, "From: $from")
        Log.v(TAG, "Message: $message")
        if (SharedPrefsHelper.hasQbUser()) {
            val qbUser: QBUser = SharedPrefsHelper.getQbUser()
            Log.v(TAG, "App has logged user" + qbUser.id)
            LoginService.start(this, qbUser)
        }
    }
}

Also add the service to manifest.xml

<service
    android:name=".quickblox.services.fcm.PushListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

<service
    android:name="com.quickblox.messages.services.fcm.QBFcmPushInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
    </intent-filter>
</service>

Firebase push notifications is pre-requisite for this

Krishna Meena
  • 5,693
  • 5
  • 32
  • 44
0

Steps to get background calls in quickblox for Android

  1. Linked your app Firebase. Follow this link for more understanding https://docs.quickblox.com/docs/android-push-notifications

  2. Add server key from firebase console to quickblox Admin panel as shown in the above link. Also check carefully the Environment in Quickblox (Development, Production).

  3. Add meta tags in Manifest file of android as shown in link.

  4. This is my PushListenerService Code for reference

    class PushListenerService : QBFcmPushListenerService() {
     private val TAG = PushListenerService::class.java.simpleName
     override fun onNewToken(token: String) {
         super.onNewToken(token)
    
         val tokenRefreshed = true
         SharedPrefs.storeFcmToken(this, token)
         SubscribeService.subscribeToPushes(MyApplication.getInstance(), tokenRefreshed)
    
     }
    
     override fun onMessageReceived(p0: RemoteMessage) {
         Log.d(TAG, "onMessageReceived: $p0")
    
         if (SharedPrefsHelper.hasQbUser()) {
             val qbUser: QBUser? = SharedPrefsHelper.getQbUser()
             if (qbUser != null) {
                 Log.d(TAG, "App has logged user" + qbUser.id)
                 LoginService.start(this, qbUser)
    
             }
         }
     }
    
     override fun sendPushMessage(data: MutableMap<Any?, Any?>?, from: String?, message: String?) {
         super.sendPushMessage(data, from, message)
         Log.v(TAG, "From: $from")
         Log.v(TAG, "Message: $message")
     }
    }
    
  5. This is the sendPushMessage code as called in CallActivity.kt of quickblox sample video app

     fun sendPushMessage(recipients: ArrayList<Int>,
                     senderName: String,
                     newSessionID: String,
                     opponentsIDs: String,
                     opponentsNames: String,
                     isVideoCall: Boolean) {
     val outMessage = String.format(R.string.text_push_notification_message.toString(), senderName)
    
     val currentTime = Calendar.getInstance().time
     val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
     val eventDate = simpleDateFormat.format(currentTime)
    
     // Send Push: create QuickBlox Push Notification Event
     val qbEvent = QBEvent()
     qbEvent.notificationType = QBNotificationType.PUSH
     qbEvent.environment = QBEnvironment.DEVELOPMENT
     // Generic push - will be delivered to all platforms (Android, iOS, WP, Blackberry..)
    
     val json = JSONObject()
     try {
         json.put("message", outMessage)
         json.put("ios_voip", "1")
         json.put("VOIPCall", "1")
         json.put("sessionID", newSessionID)
         json.put("opponentsIDs", opponentsIDs)
         json.put("contactIdentifier", opponentsNames)
         json.put("conferenceType", if (isVideoCall) "1" else "2")
         json.put("timestamp", eventDate)
     } catch (e: JSONException) {
         e.printStackTrace()
     }
    
     qbEvent.message = json.toString()
    
     val userIds = StringifyArrayList(recipients)
     qbEvent.userIds = userIds
    
     QBPushNotifications.createEvents(qbEvent).performAsync(object : QBEntityCallback<List<QBEvent>> {
         override fun onSuccess(p0: List<QBEvent>?, p1: Bundle?) {
             Log.d("FCM", "onSuccess: ")
         }
    
         override fun onError(p0: QBResponseException?) {
             Log.d("FCM", "onError: ${p0?.printStackTrace()}")
         }
     })
    }
    

Notes: Make sure you start LoginService when user is logged in. LoginService is mentioned in sample code of quickblox

Aksh Shah
  • 1
  • 2