Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f27d246 authored by Grace Jia's avatar Grace Jia
Browse files

Add notification cache for VoipCallMonitor to avoid match failure

between notifications and calls.

Sometimes voip app can post notification before the foreground service
delegation started. Cache the already posted notification and match it
with possible calls when we actually start the monitoring.

Bug: 277648806
Test: Manually test with test app transactionalVoipApp
Change-Id: Id4b26245443fa814eab3f7f26c98199772509b2d
parent 4eb22a9d
Loading
Loading
Loading
Loading
+52 −22
Original line number Original line Diff line number Diff line
@@ -49,7 +49,9 @@ import java.util.Set;
public class VoipCallMonitor extends CallsManagerListenerBase {
public class VoipCallMonitor extends CallsManagerListenerBase {


    private final List<Call> mPendingCalls;
    private final List<Call> mPendingCalls;
    private final Map<StatusBarNotification, Call> mNotifications;
    // Same notification may be passed as different object in onNotificationPosted and
    // onNotificationRemoved. Use its string as key to cache ongoing notifications.
    private final Map<String, Call> mNotifications;
    private final Map<PhoneAccountHandle, Set<Call>> mPhoneAccountHandleListMap;
    private final Map<PhoneAccountHandle, Set<Call>> mPhoneAccountHandleListMap;
    private ActivityManagerInternal mActivityManagerInternal;
    private ActivityManagerInternal mActivityManagerInternal;
    private final Map<PhoneAccountHandle, ServiceConnection> mServices;
    private final Map<PhoneAccountHandle, ServiceConnection> mServices;
@@ -58,6 +60,7 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
    private final HandlerThread mHandlerThread;
    private final HandlerThread mHandlerThread;
    private final Handler mHandler;
    private final Handler mHandler;
    private final Context mContext;
    private final Context mContext;
    private List<StatusBarNotification> mPendingSBN;


    public VoipCallMonitor(Context context, TelecomSystem.SyncRoot lock) {
    public VoipCallMonitor(Context context, TelecomSystem.SyncRoot lock) {
        mContext = context;
        mContext = context;
@@ -65,6 +68,7 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
        mHandlerThread.start();
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
        mHandler = new Handler(mHandlerThread.getLooper());
        mPendingCalls = new ArrayList<>();
        mPendingCalls = new ArrayList<>();
        mPendingSBN = new ArrayList<>();
        mNotifications = new HashMap<>();
        mNotifications = new HashMap<>();
        mServices = new HashMap<>();
        mServices = new HashMap<>();
        mPhoneAccountHandleListMap = new HashMap<>();
        mPhoneAccountHandleListMap = new HashMap<>();
@@ -74,24 +78,21 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
            @Override
            @Override
            public void onNotificationPosted(StatusBarNotification sbn) {
            public void onNotificationPosted(StatusBarNotification sbn) {
                synchronized (mLock) {
                synchronized (mLock) {
                    if (mPendingCalls.isEmpty()) {
                        return;
                    }
                    if (sbn.getNotification().isStyle(Notification.CallStyle.class)) {
                    if (sbn.getNotification().isStyle(Notification.CallStyle.class)) {
                        String packageName = sbn.getPackageName();
                        boolean sbnMatched = false;
                        UserHandle userHandle = sbn.getUser();

                        for (Call call : mPendingCalls) {
                        for (Call call : mPendingCalls) {
                            if (packageName != null &&
                            if (notificationMatchedCall(sbn, call)) {
                                    packageName.equals(call.getTargetPhoneAccount()
                                            .getComponentName().getPackageName())
                                    && userHandle != null
                                    && userHandle.equals(call.getInitiatingUser())) {
                                mPendingCalls.remove(call);
                                mPendingCalls.remove(call);
                                mNotifications.put(sbn, call);
                                mNotifications.put(sbn.toString(), call);
                                sbnMatched = true;
                                break;
                                break;
                            }
                            }
                        }
                        }
                        if (!sbnMatched) {
                            // notification may posted before we started to monitor the call, cache
                            // this notification and try to match it later with new added call.
                            mPendingSBN.add(sbn);
                        }
                    }
                    }
                }
                }
            }
            }
@@ -99,12 +100,13 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
            @Override
            @Override
            public void onNotificationRemoved(StatusBarNotification sbn) {
            public void onNotificationRemoved(StatusBarNotification sbn) {
                synchronized (mLock) {
                synchronized (mLock) {
                    mPendingSBN.remove(sbn);
                    if (mNotifications.isEmpty()) {
                    if (mNotifications.isEmpty()) {
                        return;
                        return;
                    }
                    }
                    Call call = mNotifications.getOrDefault(sbn, null);
                    Call call = mNotifications.getOrDefault(sbn.toString(), null);
                    if (call != null) {
                    if (call != null) {
                        mNotifications.remove(sbn, call);
                        mNotifications.remove(sbn.toString(), call);
                        stopFGSDelegation(call.getTargetPhoneAccount());
                        stopFGSDelegation(call.getTargetPhoneAccount());
                    }
                    }
                }
                }
@@ -225,16 +227,32 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
    }
    }


    private void startMonitorNotification(Call call) {
    private void startMonitorNotification(Call call) {
        synchronized (mLock) {
            boolean sbnMatched = false;
            for (StatusBarNotification sbn : mPendingSBN) {
                if (notificationMatchedCall(sbn, call)) {
                    mPendingSBN.remove(sbn);
                    mNotifications.put(sbn.toString(), call);
                    sbnMatched = true;
                    break;
                }
            }
            if (!sbnMatched) {
                // Only continue to
                mPendingCalls.add(call);
                mPendingCalls.add(call);
                mHandler.postDelayed(() -> {
                mHandler.postDelayed(() -> {
                    synchronized (mLock) {
                    synchronized (mLock) {
                        if (mPendingCalls.contains(call)) {
                        if (mPendingCalls.contains(call)) {
                            Log.i(this, "Notification for voip-call %s haven't "
                                    + "posted in time, stop delegation.", call.getId());
                            stopFGSDelegation(call.getTargetPhoneAccount());
                            stopFGSDelegation(call.getTargetPhoneAccount());
                            mPendingCalls.remove(call);
                            mPendingCalls.remove(call);
                        }
                        }
                    }
                    }
                }, 5000L);
                }, 5000L);
            }
            }
        }
    }


    private void stopMonitorNotification(Call call) {
    private void stopMonitorNotification(Call call) {
        mPendingCalls.remove(call);
        mPendingCalls.remove(call);
@@ -249,4 +267,16 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
    public void setNotificationListenerService(NotificationListenerService listener) {
    public void setNotificationListenerService(NotificationListenerService listener) {
        mNotificationListener = listener;
        mNotificationListener = listener;
    }
    }

    private boolean notificationMatchedCall(StatusBarNotification sbn, Call call) {
        String packageName = sbn.getPackageName();
        UserHandle userHandle = sbn.getUser();
        PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();

        return packageName != null &&
                packageName.equals(call.getTargetPhoneAccount()
                        .getComponentName().getPackageName())
                && userHandle != null
                && userHandle.equals(accountHandle.getUserHandle());
    }
}
}