在Marshmallow上的Whatsapp/Viber/Line/Skype等VOIP应用程序的锁定屏幕上的来电

pra*_*k31 6 android voip twilio

我们计划发布基于Twilio Voice SDK的Android应用程序更新.我们的客户想要更原生的体验,他们可以直接看到接受或拒绝电话的屏幕(就像Skype/Whatsapp/Viber/Line等),而不是点击通知然后再点击对话框.此外,这也应该在锁定屏幕上工作.

截至目前,我已成功在我的应用程序中打开一个活动并显示接受或拒绝按钮.它适用于应用程序处于前台或后台时.这是实现这一目标的代码片段.我修改了VoiceFirebaseMessagingService.java中的notify()方法,以便在每次调用onMessageRecived来显示来电通知时显示活动.

private void notify(CallInvite callInvite, int notificationId) {
        String callSid = callInvite.getCallSid();

        if (callInvite.getState() == CallInvite.State.PENDING) {
            soundPoolManager.playRinging();

            System.out.println("Disabling keyguard and accquiring wake lock");



            Intent intent = new Intent(this, OnCallActivityNew.class);
            intent.setAction(OnCallActivityNew.ACTION_INCOMING_CALL);
            intent.putExtra(OnCallActivityNew.INCOMING_CALL_NOTIFICATION_ID, notificationId);
            intent.putExtra(OnCallActivityNew.INCOMING_CALL_INVITE, callInvite);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent pendingIntent =
                    PendingIntent.getActivity(this, notificationId, intent, PendingIntent.FLAG_ONE_SHOT);
            /*
             * Pass the notification id and call sid to use as an identifier to cancel the
             * notification later
             */
            Bundle extras = new Bundle();
            extras.putInt(NOTIFICATION_ID_KEY, notificationId);
            extras.putString(CALL_SID_KEY, callSid);

            NotificationCompat.Builder notificationBuilder =
                    new NotificationCompat.Builder(this)
                            .setSmallIcon(R.drawable.ic_call_end_white_24px)
                            .setContentTitle(getString(R.string.app_name))
                            .setContentText(callInvite.getFrom() + " is calling.")
                            .setAutoCancel(true)
                            .setExtras(extras)
                            .setContentIntent(pendingIntent)
                            .setGroup("test_app_notification")
                            .setOngoing(true)
                            .setColor(Color.rgb(214, 10, 37));
            notificationManager.notify(notificationId, notificationBuilder.build());
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtras(extras);
            globalintent =  intent;

            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    startActivity(globalintent);
                }
            },2000);

        } else {
            SoundPoolManager.getInstance(this).stopRinging();
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                /*
                 * If the incoming call was cancelled then remove the notification by matching
                 * it with the call sid from the list of notifications in the notification drawer.
                 */
                StatusBarNotification[] activeNotifications = notificationManager.getActiveNotifications();
                for (StatusBarNotification statusBarNotification : activeNotifications) {
                    Notification notification = statusBarNotification.getNotification();
                    Bundle extras = notification.extras;
                    String notificationCallSid = extras.getString(CALL_SID_KEY);

                    if (callSid.equals(notificationCallSid)) {
                        notificationManager.cancel(extras.getInt(NOTIFICATION_ID_KEY));
                    } else {
                        sendCallInviteToActivity(callInvite, notificationId);
                    }
                }
            } else {
                /*
                 * Prior to Android M the notification manager did not provide a list of
                 * active notifications so we lazily clear all the notifications when
                 * receiving a cancelled call.
                 *
                 * In order to properly cancel a notification using
                 * NotificationManager.cancel(notificationId) we should store the call sid &
                 * notification id of any incoming calls using shared preferences or some other form
                 * of persistent storage.
                 */
                notificationManager.cancelAll();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

而且,在OnCallActivityNew.java的onCreate()中,我提到了以下代码.

@Override
    protected void onCreate(Bundle savedInstanceState) {
        System.out.println("on create of activity is called for oncallactivitynew");

        super.onCreate(savedInstanceState);
        KeyguardManager kgm = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
        boolean isKeyguardUp = kgm.inKeyguardRestrictedInputMode();
        KeyguardManager.KeyguardLock kgl = kgm.newKeyguardLock("OnCallActivityNew");

        if(isKeyguardUp){
            kgl.disableKeyguard();
            isKeyguardUp = false;
        }

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Tag");
        wl.acquire();
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
                        WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
                WindowManager.LayoutParams.FLAG_FULLSCREEN |
                        WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

        setContentView(R.layout.activity_on_call);


        coordinatorLayout = (CoordinatorLayout) fin
       ..... ///more code below to add listener to different buttons
}
Run Code Online (Sandbox Code Playgroud)

现在唯一的问题是,当手机被锁定时,此活动会打开并调用onDestroy(),我无法显示接受和拒绝按钮的屏幕.

我想要的行为是拥有一种机制,即使在锁定屏幕上也可以像上面提到的应用程序那样接听电话.

我知道这是一个与Android工作方式有关的问题,但是你们这方面的任何帮助都会非常感激.我相信人们会从这次讨论中受益.

ous*_*maz 2

我能够按照此答案中的步骤进行视频通话。

至于您打开屏幕的代码,请尝试我的代码,并告诉我它是否适合您。如果没有,您就会知道问题出在其他地方,因为此代码适用于我测试的 Android 设备:

// These flags ensure that the activity can be launched when the screen is locked.
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
        | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

// to wake up screen
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "TAG");
wakeLock.acquire();

// to release screen lock
KeyguardManager keyguardManager = (KeyguardManager) getApplicationContext().getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("TAG");
keyguardLock.disableKeyguard();
Run Code Online (Sandbox Code Playgroud)