Sinch 视频通话无法在后台运行

Sinch video call not working in background

我在当前的应用程序中实现了 Sinch 视频通话。当应用程序在前台时,来电一切正常。但是当我关闭应用程序并尝试接听来电时,它没有显示任何来电。当应用程序关闭来电时如何进行视频 Sinch 通话?以下是我的 FCMMessageReceiverService class.

public class FCMMessageReceiverService  extends FirebaseMessagingService implements ServiceConnection {

    Context context;
    private SinchService.SinchServiceInterface mSinchServiceInterface;
    HashMap dataHashMap;


    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        context = this;
        if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
            Map data = remoteMessage.getData();
            dataHashMap = (data instanceof HashMap) ? (HashMap) data : new HashMap<>(data);
            if (SinchHelpers.isSinchPushPayload(dataHashMap)) {
                getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, Context.BIND_AUTO_CREATE);
            }
        } else {
            Intent intent;
            PendingIntent pendingIntent = null;
            if (remoteMessage.getData().size() > 0) {
                String identifier = remoteMessage.getData().get("identifier");
                if (identifier.equals("0")) {
                    intent = new Intent(this, MainActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
                }
            }
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
            notificationBuilder.setWhen(System.currentTimeMillis());
            notificationBuilder.setContentTitle(remoteMessage.getNotification().getTitle());
            notificationBuilder.setContentText(remoteMessage.getNotification().getBody());
            notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
            notificationBuilder.setDefaults(Notification.DEFAULT_ALL | Notification.DEFAULT_LIGHTS | Notification.FLAG_SHOW_LIGHTS | Notification.DEFAULT_SOUND);
            notificationBuilder.setAutoCancel(true);
            notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
            notificationBuilder.setContentIntent(pendingIntent);
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.notify(0, notificationBuilder.build());
        }

    }

    public static boolean foregrounded() {
        ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
        ActivityManager.getMyMemoryState(appProcessInfo);
        return (appProcessInfo.importance == appProcessInfo.IMPORTANCE_FOREGROUND || appProcessInfo.importance == appProcessInfo.IMPORTANCE_VISIBLE);
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        if (SinchService.class.getName().equals(componentName.getClassName())) {
            mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
        }

        // it starts incoming call activity which does not show incoming caller name and picture
        NotificationResult result = mSinchServiceInterface.relayRemotePushNotificationPayload(dataHashMap);
        if (result.isValid() && result.isCall()) {
            CallNotificationResult callResult = result.getCallResult();
            if (callResult.isCallCanceled() || callResult.isTimedOut()) {
                createNotification("Missed Call from : ", callResult.getRemoteUserId());
                return;
            } else {
                if (callResult.isVideoOffered()) {
                    Intent intent = new Intent(this, IncomingCallScreenActivity.class);
                    intent.putExtra(SinchService.CALL_ID, callResult.getRemoteUserId());
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
                    startActivity(intent);
                }
            }
        } else if (result.isValid() && result.isMessage()) {
            //i want to get message content here
            MessageNotificationResult notificationResult = result.getMessageResult();
            createNotification("Received Message from : ", notificationResult.getSenderId());
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        unbindService(this);
    }

    private void createNotification(String contentTitle, String userId) {
        PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), 0);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext()).setSmallIcon(R.mipmap.ic_launcher).setContentTitle(contentTitle).setContentText(userId);
        mBuilder.setContentIntent(contentIntent);
        mBuilder.setDefaults(Notification.DEFAULT_SOUND);
        mBuilder.setAutoCancel(true);
        NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(1, mBuilder.build());
    }
}

这是我的服务代码:

public class SinchService extends Service {

    private static final String APP_KEY = "***********";
    private static final String APP_SECRET = "***********";
    private static final String ENVIRONMENT = "clientapi.sinch.com";

    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 PersistedSettings mSettings;


    private StartFailedListener mListener;
    @Override
    public void onCreate() {
        super.onCreate();
        mSettings = new PersistedSettings(getApplicationContext());
        String userName = mSettings.getUsername();


        if (!userName.isEmpty()) {

            Intent intent=new Intent(this,placecallActvity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            start(userName);

        }
    }

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

    private void start(String userName) {
        if (mSinchClient == null) {
            mSettings.setUsername(userName);
            mUserId = userName;
            mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName).applicationKey(APP_KEY).applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
            mSinchClient.setSupportCalling(true);
            mSinchClient.setSupportManagedPush(true);
            mSinchClient.checkManifest();
            mSinchClient.setSupportActiveConnectionInBackground(true);
            mSinchClient.startListeningOnActiveConnection();
            mSinchClient.addSinchClientListener(new MySinchClientListener());
            mSinchClient.getCallClient().setRespectNativeCalls(false);
            mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
            mSinchClient.getVideoController().setResizeBehaviour(VideoScalingType.ASPECT_FILL);
            mSinchClient.start();
        }
    }

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

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

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

    public class SinchServiceInterface extends Binder {

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

        public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
            if (mSinchClient == null && !mSettings.getUsername().isEmpty()) {
                start(mSettings.getUsername());
            } else if (mSinchClient == null && mSettings.getUsername().isEmpty()) {

                return null;
            }
            return mSinchClient.relayRemotePushNotificationPayload(payload);
        }


        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 VideoController getVideoController() {
            if (!isStarted()) {
                return null;
            }
            return mSinchClient.getVideoController();
        }

        public AudioController getAudioController() {
            if (!isStarted()) {
                return null;
            }
            return mSinchClient.getAudioController();
        }
    }

    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.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            SinchService.this.startActivity(intent);
        }
    }

    private class PersistedSettings {

        private SharedPreferences mStore;

        private static final String PREF_KEY = "Sinch";
        public PersistedSettings(Context context) {
            mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
        }
        public String getUsername() {
            return mStore.getString("Username", "");
        }
        public void setUsername(String username) {
            SharedPreferences.Editor editor = mStore.edit();
            editor.putString("Username", username);
            editor.commit();
        }
    }

}

在我们的 SDK 包中,您会在 Samples 文件夹下找到多个示例文件,名为 sinch-rtc-sample-video-push 的文件可以满足您的需求。 您还应该在此处查看我们的文档: https://developers.sinch.com/docs/voice-android-push-notifications

此致

将 FCM 添加到您的项目中

添加以下代码

public class SinchService  extends Service {
static final String APP_KEY = "************";
static final String APP_SECRET = "***********";
static final String ENVIRONMENT = "clientapi.sinch.com";
public static final int MESSAGE_PERMISSIONS_NEEDED = 1;
public static final String REQUIRED_PERMISSION = "REQUIRED_PESMISSION";
public static final String MESSENGER = "MESSENGER";
private Messenger messenger;

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;
private PersistedSettings mSettings;
private AudioPlayer audioPlayer;
private Handler handler;

@Override
public void onCreate() {
    super.onCreate();
    super.onCreate();
    mSettings = new PersistedSettings(getApplicationContext());
    String userName = mSettings.getUsername();


    if (!userName.isEmpty()) {

       
        start(userName);


    }
    handler = new Handler();

}
private void createClient(String username) {
    mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(username)
            .applicationKey(APP_KEY)
            .applicationSecret(APP_SECRET)
            .environmentHost(ENVIRONMENT).build();

    mSinchClient.setSupportCalling(true);
    mSinchClient.setSupportManagedPush(true);

    mSinchClient.addSinchClientListener(new MySinchClientListener());
    mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
    mSinchClient.setPushNotificationDisplayName("User " + username);
}


@Override
public void onDestroy() {
    if (mSinchClient != null && mSinchClient.isStarted()) {
        mSinchClient.terminateGracefully();
    }
    super.onDestroy();
}
private boolean hasUsername() {
    if (mSettings.getUsername().isEmpty()) {
        Log.e(TAG, "Can't start a SinchClient as no username is available!");
        return false;
    }
    return true;
}
private void createClientIfNecessary() {
    if (mSinchClient != null)
        return;
    if (!hasUsername()) {
        throw new IllegalStateException("Can't create a SinchClient as no username is available!");
    }
    createClient(mSettings.getUsername());
}

private void start(String userName) {
    boolean permissionsGranted = true;
    if (mSinchClient == null) {
        mSettings.setUsername(userName);
        createClient(userName);
    }
    createClientIfNecessary();
    try {
        //mandatory checks
        mSinchClient.checkManifest();
        if (getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            throw new MissingPermissionException(Manifest.permission.CAMERA);
        }
    } catch (MissingPermissionException e) {
        permissionsGranted = false;
        if (messenger != null) {
            Message message = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString(REQUIRED_PERMISSION, e.getRequiredPermission());
            message.setData(bundle);
            message.what = MESSAGE_PERMISSIONS_NEEDED;
            try {
                messenger.send(message);
            } catch (RemoteException e1) {
                e1.printStackTrace();
            }
        }
    }
    if (permissionsGranted) {
        Log.d(TAG, "Starting SinchClient");
        try {
            mSinchClient.start();
        } catch (IllegalStateException e) {
            Log.w(TAG, "Can't start SinchClient - " + e.getMessage());
        }
    }
}


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


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

@Override
public IBinder onBind(Intent intent) {
    messenger = intent.getParcelableExtra(MESSENGER);
    return mSinchServiceInterface;
}

public class SinchServiceInterface extends Binder {

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

    public String getUserName() {
        return mSettings.getUsername();
    }
    public void setUsername(String username) {
        mSettings.setUsername(username);
    }
    public void retryStartAfterPermissionGranted() {
        SinchService.this.attemptAutoStart();
    }

    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 VideoController getVideoController() {
        if (!isStarted()) {
            return null;
        }
        return mSinchClient.getVideoController();
    }

    public AudioController getAudioController() {
        if (!isStarted()) {
            return null;
        }
        return mSinchClient.getAudioController();
    }

    public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
        if (!hasUsername()) {
            Log.e(TAG, "Unable to relay the push notification!");
            return null;
        }
        createClientIfNecessary();
        return mSinchClient.relayRemotePushNotificationPayload(payload);
    }

}

private void attemptAutoStart() {
}
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, "onIncomingCall: " + call.getCallId());
        audioPlayer = AudioPlayer.getInstance(getApplicationContext());
        call.addCallListener(new SinchCallListener());
        Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
        intent.putExtra(EXTRA_ID, MESSAGE_ID);
        intent.putExtra(CALL_ID, call.getCallId());
        boolean inForeground = isAppOnForeground(getApplicationContext());
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (inForeground) {
            SinchService.this.startActivity(intent);
        } else {
            if (!audioPlayer.isPlayedRingtone()) {
                audioPlayer.playRingtone();
            }
            ((NotificationManager) Objects.requireNonNull(getSystemService(NOTIFICATION_SERVICE))).notify(MESSAGE_ID, createIncomingCallNotification(call.getRemoteUserId(), intent));
        }
    }
    private boolean isAppOnForeground(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = null;
        if (activityManager != null) {
            appProcesses = activityManager.getRunningAppProcesses();
        }
        if (appProcesses == null) {
            return false;
        }
        final String packageName = context.getPackageName();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
                return true;
            }
        }
        return false;
    }
    private Bitmap getBitmap(Context context, int resId) {
        int largeIconWidth = (int) context.getResources()
                .getDimension(R.dimen.height);
        int largeIconHeight = (int) context.getResources()
                .getDimension(R.dimen.height);
        Drawable d = context.getResources().getDrawable(resId);
        Bitmap b = Bitmap.createBitmap(largeIconWidth, largeIconHeight, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        d.setBounds(0, 0, largeIconWidth, largeIconHeight);
        d.draw(c);
        return b;
    }
    private PendingIntent getPendingIntent(Intent intent, String action) {
        intent.setAction(action);
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 111, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        return pendingIntent;
    }
    @TargetApi(29)
    private Notification createIncomingCallNotification(String userId, Intent fullScreenIntent) {

        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 112, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(getApplicationContext(), FcmListenerService.CHANNEL_ID)
                        .setContentTitle("Incoming call")
                        .setContentText(userId)
                        .setLargeIcon(getBitmap(getApplicationContext(), R.drawable.call_normal))
                        .setSmallIcon(R.drawable.call_pressed)
                        .setPriority(NotificationCompat.PRIORITY_MAX)
                        .setContentIntent(pendingIntent)
                        .setFullScreenIntent(pendingIntent, true)
                        .addAction(R.drawable.button_accept, "Answer", getPendingIntent(fullScreenIntent, ACTION_ANSWER))
                        .addAction(R.drawable.button_decline, "Ignore", getPendingIntent(fullScreenIntent, ACTION_IGNORE))
                        .setOngoing(true);

        return builder.build();
    }
}
private class SinchCallListener implements CallListener {

    @Override
    public void onCallEnded(Call call) {
        cancelNotification();
        if (audioPlayer != null && audioPlayer.isPlayedRingtone()) {
            audioPlayer.stopRingtone();
        }
    }

    @Override
    public void onCallEstablished(Call call) {
        Log.d(TAG, "Call established");
        if (audioPlayer != null && audioPlayer.isPlayedRingtone()) {
            audioPlayer.stopRingtone();
        }
    }

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

    @Override
    public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
        // no need to implement for managed push
    }

}
public void cancelNotification() {
    NotificationManager nMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    if (nMgr != null) {
        nMgr.cancel(MESSAGE_ID);
    }
}
private static class PersistedSettings {
    private SharedPreferences mStore;
    private static final String PREF_KEY = "Sinch";

    public PersistedSettings(Context context) {
        mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
    }
    public String getUsername() {
        return mStore.getString("Username", "");
    }
    public void setUsername(String username) {
        SharedPreferences.Editor editor = mStore.edit();
        editor.putString("Username", username);
        editor.apply();
    }
}

} 并创建 FcmListenerService 并添加以下代码

public class FcmListenerService extends FirebaseMessagingService {
public static String CHANNEL_ID = "Sinch Push Notification Channel";
private final String PREFERENCE_FILE = "com.sinch.android.rtc.sample.push.shared_preferences";
SharedPreferences sharedPreferences;
@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) {

                Context context = getApplicationContext();
                sharedPreferences = context.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);

                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
                        // here is example for notifying user about missed/canceled call:
                        if (result!=null && result.isValid() && result.isCall()) {
                            CallNotificationResult callResult = result.getCallResult();
                            if (callResult != null && result.getDisplayName() != null) {
                                SharedPreferences.Editor editor = sharedPreferences.edit();
                                editor.putString(callResult.getRemoteUserId(), result.getDisplayName());
                                editor.apply();
                            }
                            if (callResult != null && callResult.isCallCanceled()) {
                                String displayName = result.getDisplayName();
                                if (displayName == null) {
                                    displayName = sharedPreferences.getString(callResult.getRemoteUserId(), "n/a");
                                }
                                createMissedCallNotification(!displayName.isEmpty() ? displayName : callResult.getRemoteUserId());
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                    context.deleteSharedPreferences(PREFERENCE_FILE);
                                }
                            }
                        }
                    }
                }
                payload = null;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {}

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

private void createNotificationChannel(int importance) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = "Amar LPG";
        String description = "Incoming call notification";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(channel);
        }
    }
}
private void createMissedCallNotification(String userId) {

    createNotificationChannel(NotificationManager.IMPORTANCE_DEFAULT);

    PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
            new Intent(getApplicationContext(), IncomingCallScreenActivity.class), 0);
    NotificationCompat.Builder builder =
            new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
                    .setSmallIcon(R.drawable.icon)
                    .setContentTitle("Missed call from ")
                    .setContentText(userId)
                    .setContentIntent(contentIntent)
                    .setDefaults(Notification.DEFAULT_SOUND)
                    .setAutoCancel(true);
    NotificationManager mNotificationManager =
            (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
    if (mNotificationManager != null) {
        mNotificationManager.notify(1, builder.build());
    }
}

}

在来电界面添加以下代码

public class IncomingCallScreenActivity 扩展了 BaseActivity {

static final String TAG = IncomingCallScreenActivity.class.getSimpleName();
private String mCallId;
private AudioPlayer mAudioPlayer;
public static final String ACTION_ANSWER = "answer";
public static final String ACTION_IGNORE = "ignore";
public static final String EXTRA_ID = "id";
public static int MESSAGE_ID = 14;
private String mAction;

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

    Button answer = (Button) findViewById(R.id.answerButton);
    answer.setOnClickListener(mClickListener);
    Button decline = (Button) findViewById(R.id.declineButton);
    decline.setOnClickListener(mClickListener);

    mAudioPlayer = new AudioPlayer(this);
    mAudioPlayer.playRingtone();
    mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
    mAction = "";
}
@Override
protected void onResume() {
    super.onResume();
    Intent intent = getIntent();
    if (intent != null) {
        if (intent.getStringExtra(SinchService.CALL_ID) != null) {
            mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
        }
        final int id = intent.getIntExtra(EXTRA_ID, -1);
        if (id > 0) {
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.cancel(id);
        }
        mAction = intent.getAction();
    }
}

@Override
protected void onServiceConnected() {
    Call call = getSinchServiceInterface().getCall(mCallId);
    if (call != null) {
        call.addCallListener(new SinchCallListener());
        TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
        remoteUser.setText(call.getRemoteUserId());

        if (ACTION_ANSWER.equals(mAction)) {
            mAction = "";
            answerClicked();
        } else if (ACTION_IGNORE.equals(mAction)) {
            mAction = "";
            declineClicked();
        }

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

private void answerClicked() {
    if (mAudioPlayer!=null && mAudioPlayer.isPlayedRingtone()){
        mAudioPlayer.stopRingtone();
    }

    Call call = getSinchServiceInterface().getCall(mCallId);
    if (call != null) {
        Log.d(TAG, "Answering call");
        call.answer();
        Intent intent = new Intent(this, CallScreenActivity.class);
        intent.putExtra(SinchService.CALL_ID, mCallId);
        startActivity(intent);
    } else {
        finish();
    }
}

private void declineClicked() {
    if (mAudioPlayer!=null && mAudioPlayer.isPlayedRingtone()){
        mAudioPlayer.stopRingtone();
    }
    Call call = getSinchServiceInterface().getCall(mCallId);
    if (call != null) {
        call.hangup();
    }
    finish();
}

private class SinchCallListener implements VideoCallListener {

    @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 onCallEstablished(Call call) {
        Log.d(TAG, "Call established");
    }

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

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

    @Override
    public void onVideoTrackAdded(Call call) {
        // Display some kind of icon showing it's a video call
    }

    @Override
    public void onVideoTrackPaused(Call call) {

    }

    @Override
    public void onVideoTrackResumed(Call call) {

    }
}

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

}

在登录activity中添加以下代码。

public class MainActivity extends BaseActivity implements SinchService.StartFailedListener, PushTokenRegistrationCallback, UserRegistrationCallback {

private Button mLoginButton;
private EditText mLoginName;
private ProgressDialog mSpinner;
private String mUserId;
private long mSigningSequence = 1;




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

   
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.READ_PHONE_STATE},100);
    }

   
    mLoginName = (EditText) findViewById(R.id.loginName);
    mLoginButton = (Button) findViewById(R.id.loginButton);
    mLoginButton.setEnabled(false);
    mLoginButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            loginClicked();
        }
    });
}
@Override
protected void onResume() {
    super.onResume();
}


@Override
protected void onServiceConnected() {
    mLoginButton.setEnabled(true);
    getSinchServiceInterface().setStartListener(this);
}

@Override
protected void onPause() {
    if (mSpinner != null) {
        mSpinner.dismiss();
    }
    super.onPause();
}

@Override
public void onStartFailed(SinchError error) {
    Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
    if (mSpinner != null) {
        mSpinner.dismiss();
    }
}


@Override
public void onStarted() {
    openPlaceCallActivity();
}


private void loginClicked() {
    String userName = mLoginName.getText().toString();

    if (userName.isEmpty()) {
        Toast.makeText(this, "Please enter a name", Toast.LENGTH_LONG).show();
        return;
    }

    if (!getSinchServiceInterface().isStarted()) {
        getSinchServiceInterface().startClient(userName);
        showSpinner();
    } else {
        openPlaceCallActivity();
    }
    mUserId = userName;
    UserController uc = Sinch.getUserControllerBuilder()
            .context(getApplicationContext())
            .applicationKey(APP_KEY)
            .userId(mUserId)
            .environmentHost(ENVIRONMENT)
            .build();
    uc.registerUser(this, this);
}




private void openPlaceCallActivity() {
    Intent mainActivity = new Intent(this, PlaceCallActivity.class);
    startActivity(mainActivity);
    finish();
}

private void showSpinner() {
    mSpinner = new ProgressDialog(this);
    mSpinner.setTitle("Logging in");
    mSpinner.setMessage("Please wait...");
    mSpinner.show();
}
private void dismissSpinner() {
    if (mSpinner != null) {
        mSpinner.dismiss();
        mSpinner = null;
    }
}

@Override
public void tokenRegistered() {
    dismissSpinner();
    startClientAndOpenPlaceCallActivity();

}

private void startClientAndOpenPlaceCallActivity() {
    // start Sinch Client, it'll result onStarted() callback from where the place call activity will be started
    if (!getSinchServiceInterface().isStarted()) {
        getSinchServiceInterface().startClient("");
        showSpinner();
    }
}

@Override
public void tokenRegistrationFailed(SinchError sinchError) {
    dismissSpinner();
    Toast.makeText(this, "Push token registration failed - incoming calls can't be received!", Toast.LENGTH_LONG).show();
}

@Override
public void onCredentialsRequired(ClientRegistration clientRegistration) {
    String toSign = mUserId + APP_KEY + mSigningSequence + APP_SECRET;
    String signature;
    MessageDigest messageDigest;
    try {
        messageDigest = MessageDigest.getInstance("SHA-1");
        byte[] hash = messageDigest.digest(toSign.getBytes("UTF-8"));
        signature = Base64.encodeToString(hash, Base64.DEFAULT).trim();
    } catch (Exception e) {
        throw new RuntimeException(e.getMessage(), e.getCause());
    }

    clientRegistration.register(signature, mSigningSequence++);

}

@Override
public void onUserRegistered() {

}

@Override
public void onUserRegistrationFailed(SinchError sinchError) {
    dismissSpinner();
    Toast.makeText(this, "Registration failed!", Toast.LENGTH_LONG).show();
}

}